From b2e8dd187343cf3059e373374426833d1a676a3e Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Fri, 28 Jul 2017 16:30:05 -0400 Subject: [PATCH] cmd/trace: expose MMU analysis flags in web UI Change-Id: I672240487172380c9eef61837b41698021aaf834 Reviewed-on: https://go-review.googlesource.com/c/60798 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Hyang-Ah Hana Kim --- src/cmd/trace/mmu.go | 133 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 119 insertions(+), 14 deletions(-) diff --git a/src/cmd/trace/mmu.go b/src/cmd/trace/mmu.go index d3b6768686..3fae3d6645 100644 --- a/src/cmd/trace/mmu.go +++ b/src/cmd/trace/mmu.go @@ -25,24 +25,54 @@ func init() { http.HandleFunc("/mmuDetails", httpMMUDetails) } -var mmuCache struct { +var utilFlagNames = map[string]trace.UtilFlags{ + "perProc": trace.UtilPerProc, + "stw": trace.UtilSTW, + "background": trace.UtilBackground, + "assist": trace.UtilAssist, + "sweep": trace.UtilSweep, +} + +type mmuCacheEntry struct { init sync.Once util [][]trace.MutatorUtil mmuCurve *trace.MMUCurve err error } -func getMMUCurve() ([][]trace.MutatorUtil, *trace.MMUCurve, error) { - mmuCache.init.Do(func() { +var mmuCache struct { + m map[trace.UtilFlags]*mmuCacheEntry + lock sync.Mutex +} + +func init() { + mmuCache.m = make(map[trace.UtilFlags]*mmuCacheEntry) +} + +func getMMUCurve(r *http.Request) ([][]trace.MutatorUtil, *trace.MMUCurve, error) { + var flags trace.UtilFlags + for _, flagStr := range strings.Split(r.FormValue("flags"), "|") { + flags |= utilFlagNames[flagStr] + } + + mmuCache.lock.Lock() + c := mmuCache.m[flags] + if c == nil { + c = new(mmuCacheEntry) + mmuCache.m[flags] = c + } + mmuCache.lock.Unlock() + + c.init.Do(func() { tr, err := parseTrace() if err != nil { - mmuCache.err = err + c.err = err } else { - mmuCache.util = tr.MutatorUtilization(trace.UtilSTW | trace.UtilBackground | trace.UtilAssist) - mmuCache.mmuCurve = trace.NewMMUCurve(mmuCache.util) + c.util = tr.MutatorUtilization(flags) + c.mmuCurve = trace.NewMMUCurve(c.util) } }) - return mmuCache.util, mmuCache.mmuCurve, mmuCache.err + return c.util, c.mmuCurve, c.err } // httpMMU serves the MMU plot page. @@ -52,7 +82,7 @@ func httpMMU(w http.ResponseWriter, r *http.Request) { // httpMMUPlot serves the JSON data for the MMU plot. func httpMMUPlot(w http.ResponseWriter, r *http.Request) { - mu, mmuCurve, err := getMMUCurve() + mu, mmuCurve, err := getMMUCurve(r) if err != nil { http.Error(w, fmt.Sprintf("failed to parse events: %v", err), http.StatusInternalServerError) return @@ -107,7 +137,8 @@ var templMMU = ` + -
Loading plot...
+
+
Loading plot...
+
+

+ View
+ + ?Consider whole system utilization. For example, if one of four procs is available to the mutator, mutator utilization will be 0.25. This is the standard definition of an MMU.
+ + ?Consider per-goroutine utilization. When even one goroutine is interrupted by GC, mutator utilization is 0.
+

+

+ Include
+ + ?Stop-the-world stops all goroutines simultaneously.
+ + ?Background workers are GC-specific goroutines. 25% of the CPU is dedicated to background workers during GC.
+ + ?Mark assists are performed by allocation to prevent the mutator from outpacing GC.
+ + ?Sweep reclaims unused memory between GCs. (Enabling this may be very slow.).
+

+
+
Select a point for details.
@@ -202,7 +307,7 @@ var templMMU = ` // httpMMUDetails serves details of an MMU graph at a particular window. func httpMMUDetails(w http.ResponseWriter, r *http.Request) { - _, mmuCurve, err := getMMUCurve() + _, mmuCurve, err := getMMUCurve(r) if err != nil { http.Error(w, fmt.Sprintf("failed to parse events: %v", err), http.StatusInternalServerError) return -- 2.50.0