From cf879b268e8f71885bf70a8c877afda0c0816905 Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Thu, 28 Apr 2016 16:13:10 +0100 Subject: [PATCH 1/2] Aggressively pass nil for the decorator in the rendering pipeline to improve performance. --- README.md | 47 +++++++++++++++++++++++++------------------ app/api_topologies.go | 13 +++++++++--- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 05523e304..9c1e65263 100644 --- a/README.md +++ b/README.md @@ -325,40 +325,47 @@ kill -USR1 $(pgrep -f scope-probe) docker logs weavescope ``` -- Both the Scope App and the Scope Probe offer - [HTTP endpoints with profiling information](https://golang.org/pkg/net/http/pprof/). - These cover things such as CPU usage and memory consumption: - * The Scope App enables its HTTP profiling endpoints by default, which - are accessible on the same port the Scope UI is served (4040). - * The Scope Probe doesn't enable its profiling endpoints by default. - To enable them, you must launch Scope with `--probe.http.listen addr:port`. - For instance, launching Scope with `scope launch --probe.http.listen :4041`, will - allow you access the Scope Probe's profiling endpoints on port 4041. +Both the Scope App and the Scope Probe offer [HTTP endpoints with profiling information](https://golang.org/pkg/net/http/pprof/). +These cover things such as CPU usage and memory consumption: +- The Scope App enables its HTTP profiling endpoints by default, which + are accessible on the same port the Scope UI is served (4040). +- The Scope Probe doesn't enable its profiling endpoints by default. + To enable them, you must launch Scope with `--probe.http.listen addr:port`. + For instance, launching Scope with `scope launch --probe.http.listen :4041`, will + allow you access the Scope Probe's profiling endpoints on port 4041. - Then, you can collect profiles in the usual way. For instance: +Then, you can collect profiles in the usual way. For instance: - * To collect the memory profile of the Scope App: +- To collect the memory profile of the Scope App: - ``` +``` go tool pprof http://localhost:4040/debug/pprof/heap ``` - * To collect the CPU profile of the Scope Probe: - ``` +- To collect the CPU profile of the Scope Probe: + +``` go tool pprof http://localhost:4041/debug/pprof/profile ``` - If you don't have `go` installed, you can use a Docker container instead: +If you don't have `go` installed, you can use a Docker container instead: - * To collect the memory profile of the Scope App: +- To collect the memory profile of the Scope App: - ``` +``` docker run --net=host -v $PWD:/root/pprof golang go tool pprof http://localhost:4040/debug/pprof/heap ``` - * To collect the CPU profile of the Scope Probe: - ``` +- To collect the CPU profile of the Scope Probe: + +``` docker run --net=host -v $PWD:/root/pprof golang go tool pprof http://localhost:4041/debug/pprof/profile ``` - You will find the output profiles in your working directory. +You will find the output profiles in your working directory. To analyse the dump, do something like: + +``` +go tool pprof prog/scope pprof.localhost\:4040.samples.cpu.001.pb.gz +Entering interactive mode (type "help" for commands) +(pprof) pdf >cpu.pdf +``` diff --git a/app/api_topologies.go b/app/api_topologies.go index 9c400e34e..0d4a61fdd 100644 --- a/app/api_topologies.go +++ b/app/api_topologies.go @@ -73,7 +73,7 @@ func init() { Options: []APITopologyOption{ // Show the user why there are filtered nodes in this view. // Don't give them the option to show those nodes. - {"hide", "Unconnected nodes hidden", render.Noop}, + {"hide", "Unconnected nodes hidden", nil}, }, }, } @@ -285,14 +285,21 @@ func renderedForRequest(r *http.Request, topology APITopologyDesc) (render.Rende for _, group := range topology.Options { value := r.FormValue(group.ID) for _, opt := range group.Options { + if opt.filter == nil { + continue + } if (value == "" && group.Default == opt.Value) || (opt.Value != "" && opt.Value == value) { filters = append(filters, opt.filter) } } } - return topology.renderer, func(renderer render.Renderer) render.Renderer { - return render.MakeFilter(render.ComposeFilterFuncs(filters...), renderer) + var decorator render.Decorator + if len(filters) > 0 { + decorator = func(renderer render.Renderer) render.Renderer { + return render.MakeFilter(render.ComposeFilterFuncs(filters...), renderer) + } } + return topology.renderer, decorator } type reportRenderHandler func( From b4a59f6e3632e6d1c20b934bff2bb781d5d87ce6 Mon Sep 17 00:00:00 2001 From: Tom Wilkie Date: Fri, 29 Apr 2016 12:06:33 +0100 Subject: [PATCH 2/2] Don't recursively gets stats beyond an ApplyDecorators decorator --- render/render.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/render/render.go b/render/render.go index 13d38c147..4741f4ec5 100644 --- a/render/render.go +++ b/render/render.go @@ -143,7 +143,7 @@ func (ad applyDecorator) Stats(rpt report.Report, dct Decorator) Stats { if dct != nil { return dct(ad.Renderer).Stats(rpt, nil) } - return ad.Renderer.Stats(rpt, nil) + return Stats{} } // ApplyDecorators returns a renderer which will apply the given decorators