Commit bef4efc8 authored by Austin Clements's avatar Austin Clements

internal/trace: add "per-P" MMU analysis

The current MMU analysis considers all Ps together, so if, for
example, one of four Ps is blocked, mutator utilization is 75%.
However, this is less useful for understanding the impact on
individual goroutines because that one blocked goroutine could be
blocked for a very long time, but we still appear to have good
utilization.

Hence, this introduces a new flag that does a "per-P" analysis where
the utilization of each P is considered independently. The MMU is then
the combination of the MMU for each P's utilization function.

Change-Id: Id67b980d4d82b511d28300cdf92ccbb5ae8f0c78
Reviewed-on: https://go-review.googlesource.com/c/60797
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarHyang-Ah Hana Kim <hyangah@gmail.com>
parent 27920c8d
...@@ -27,12 +27,12 @@ func init() { ...@@ -27,12 +27,12 @@ func init() {
var mmuCache struct { var mmuCache struct {
init sync.Once init sync.Once
util []trace.MutatorUtil util [][]trace.MutatorUtil
mmuCurve *trace.MMUCurve mmuCurve *trace.MMUCurve
err error err error
} }
func getMMUCurve() ([]trace.MutatorUtil, *trace.MMUCurve, error) { func getMMUCurve() ([][]trace.MutatorUtil, *trace.MMUCurve, error) {
mmuCache.init.Do(func() { mmuCache.init.Do(func() {
tr, err := parseTrace() tr, err := parseTrace()
if err != nil { if err != nil {
...@@ -69,7 +69,16 @@ func httpMMUPlot(w http.ResponseWriter, r *http.Request) { ...@@ -69,7 +69,16 @@ func httpMMUPlot(w http.ResponseWriter, r *http.Request) {
// Cover six orders of magnitude. // Cover six orders of magnitude.
xMax := xMin * 1e6 xMax := xMin * 1e6
// But no more than the length of the trace. // But no more than the length of the trace.
if maxMax := time.Duration(mu[len(mu)-1].Time - mu[0].Time); xMax > maxMax { minEvent, maxEvent := mu[0][0].Time, mu[0][len(mu[0])-1].Time
for _, mu1 := range mu[1:] {
if mu1[0].Time < minEvent {
minEvent = mu1[0].Time
}
if mu1[len(mu1)-1].Time > maxEvent {
maxEvent = mu1[len(mu1)-1].Time
}
}
if maxMax := time.Duration(maxEvent - minEvent); xMax > maxMax {
xMax = maxMax xMax = maxMax
} }
// Compute MMU curve. // Compute MMU curve.
......
This diff is collapsed.
...@@ -29,14 +29,14 @@ func TestMMU(t *testing.T) { ...@@ -29,14 +29,14 @@ func TestMMU(t *testing.T) {
// 0.5 * * * * // 0.5 * * * *
// 0.0 ***** ***** // 0.0 ***** *****
// 0 1 2 3 4 5 // 0 1 2 3 4 5
util := []MutatorUtil{ util := [][]MutatorUtil{{
{0e9, 1}, {0e9, 1},
{1e9, 0}, {1e9, 0},
{2e9, 1}, {2e9, 1},
{3e9, 0}, {3e9, 0},
{4e9, 1}, {4e9, 1},
{5e9, 0}, {5e9, 0},
} }}
mmuCurve := NewMMUCurve(util) mmuCurve := NewMMUCurve(util)
for _, test := range []struct { for _, test := range []struct {
...@@ -90,7 +90,7 @@ func TestMMUTrace(t *testing.T) { ...@@ -90,7 +90,7 @@ func TestMMUTrace(t *testing.T) {
// Test the optimized implementation against the "obviously // Test the optimized implementation against the "obviously
// correct" implementation. // correct" implementation.
for window := time.Nanosecond; window < 10*time.Second; window *= 10 { for window := time.Nanosecond; window < 10*time.Second; window *= 10 {
want := mmuSlow(mu, window) want := mmuSlow(mu[0], window)
got := mmuCurve.MMU(window) got := mmuCurve.MMU(window)
if !aeq(want, got) { if !aeq(want, got) {
t.Errorf("want %f, got %f mutator utilization in window %s", want, got, window) t.Errorf("want %f, got %f mutator utilization in window %s", want, got, window)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment