mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-28 17:51:21 +00:00
Memoise & cache the result of renderers, so we don't recalculate views multiple times.
This commit is contained in:
@@ -1,9 +1,35 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/bluele/gcache"
|
||||
|
||||
"github.com/weaveworks/scope/report"
|
||||
)
|
||||
|
||||
var renderCache = gcache.New(100).LRU().Build()
|
||||
|
||||
func memoisedRender(r Renderer, rpt report.Report) RenderableNodes {
|
||||
key := ""
|
||||
v := reflect.ValueOf(r)
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr, reflect.Func:
|
||||
key = fmt.Sprintf("%s-%x", rpt.ID, v.Pointer())
|
||||
default:
|
||||
return r.Render(rpt)
|
||||
}
|
||||
if result, err := renderCache.Get(key); err == nil {
|
||||
//fmt.Println("Hit", key)
|
||||
return result.(RenderableNodes)
|
||||
}
|
||||
//fmt.Println("Miss", key)
|
||||
output := r.Render(rpt)
|
||||
renderCache.Set(key, output)
|
||||
return output
|
||||
}
|
||||
|
||||
// Renderer is something that can render a report to a set of RenderableNodes.
|
||||
type Renderer interface {
|
||||
Render(report.Report) RenderableNodes
|
||||
@@ -27,22 +53,23 @@ type Reduce []Renderer
|
||||
|
||||
// MakeReduce is the only sane way to produce a Reduce Renderer.
|
||||
func MakeReduce(renderers ...Renderer) Renderer {
|
||||
return Reduce(renderers)
|
||||
r := Reduce(renderers)
|
||||
return &r
|
||||
}
|
||||
|
||||
// Render produces a set of RenderableNodes given a Report.
|
||||
func (r Reduce) Render(rpt report.Report) RenderableNodes {
|
||||
func (r *Reduce) Render(rpt report.Report) RenderableNodes {
|
||||
result := RenderableNodes{}
|
||||
for _, renderer := range r {
|
||||
result = result.Merge(renderer.Render(rpt))
|
||||
for _, renderer := range *r {
|
||||
result = result.Merge(memoisedRender(renderer, rpt))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Stats implements Renderer
|
||||
func (r Reduce) Stats(rpt report.Report) Stats {
|
||||
func (r *Reduce) Stats(rpt report.Report) Stats {
|
||||
var result Stats
|
||||
for _, renderer := range r {
|
||||
for _, renderer := range *r {
|
||||
result = result.merge(renderer.Stats(rpt))
|
||||
}
|
||||
return result
|
||||
@@ -55,24 +82,29 @@ type Map struct {
|
||||
Renderer
|
||||
}
|
||||
|
||||
// MakeMap makes a new Map
|
||||
func MakeMap(f MapFunc, r Renderer) Renderer {
|
||||
return &Map{f, r}
|
||||
}
|
||||
|
||||
// Render transforms a set of RenderableNodes produces by another Renderer.
|
||||
// using a map function
|
||||
func (m Map) Render(rpt report.Report) RenderableNodes {
|
||||
func (m *Map) Render(rpt report.Report) RenderableNodes {
|
||||
output, _ := m.render(rpt)
|
||||
return output
|
||||
}
|
||||
|
||||
// Stats implements Renderer
|
||||
func (m Map) Stats(rpt report.Report) Stats {
|
||||
func (m *Map) Stats(rpt report.Report) Stats {
|
||||
// There doesn't seem to be an instance where we want stats to recurse
|
||||
// through Maps - for instance we don't want to see the number of filtered
|
||||
// processes in the container renderer.
|
||||
return Stats{}
|
||||
}
|
||||
|
||||
func (m Map) render(rpt report.Report) (RenderableNodes, map[string]report.IDList) {
|
||||
func (m *Map) render(rpt report.Report) (RenderableNodes, map[string]report.IDList) {
|
||||
var (
|
||||
input = m.Renderer.Render(rpt)
|
||||
input = memoisedRender(m.Renderer, rpt)
|
||||
output = RenderableNodes{}
|
||||
mapped = map[string]report.IDList{} // input node ID -> output node IDs
|
||||
adjacencies = map[string]report.IDList{} // output node ID -> input node Adjacencies
|
||||
|
||||
Reference in New Issue
Block a user