-
Notifications
You must be signed in to change notification settings - Fork 616
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add show_from profile filter. #372
Changes from 7 commits
0776b46
331aae2
75fee66
30bb8e2
35a7878
5e56ca2
271c8f3
df73391
7af823d
397e732
2e80e4e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
Active filters: | ||
show_from=line2 | ||
Showing nodes accounting for 1.01s, 90.18% of 1.12s total | ||
----------------------------------------------------------+------------- | ||
flat flat% sum% cum cum% calls calls% + context | ||
----------------------------------------------------------+------------- | ||
0 0% 0% 1.01s 90.18% | line2000 testdata/file2000.src:4 | ||
1.01s 100% | line2001 testdata/file2000.src:9 (inline) | ||
----------------------------------------------------------+------------- | ||
1.01s 100% | line2000 testdata/file2000.src:4 (inline) | ||
0.01s 0.89% 0.89% 1.01s 90.18% | line2001 testdata/file2000.src:9 | ||
1s 99.01% | line1000 testdata/file1000.src:1 | ||
----------------------------------------------------------+------------- | ||
1s 100% | line2001 testdata/file2000.src:9 | ||
1s 89.29% 90.18% 1s 89.29% | line1000 testdata/file1000.src:1 | ||
----------------------------------------------------------+------------- |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -101,7 +101,29 @@ var inlinesProfile = &Profile{ | |
}, | ||
} | ||
|
||
func TestFilter(t *testing.T) { | ||
var emptyLinesLocs = []*Location{ | ||
{ID: 1, Mapping: mappings[0], Address: 0x1000, Line: []Line{{Function: functions[0], Line: 1}, {Function: functions[1], Line: 1}}}, | ||
{ID: 2, Mapping: mappings[0], Address: 0x2000, Line: []Line{}}, | ||
{ID: 3, Mapping: mappings[1], Address: 0x2000, Line: []Line{}}, | ||
} | ||
|
||
var emptyLinesProfile = &Profile{ | ||
TimeNanos: 10000, | ||
PeriodType: &ValueType{Type: "cpu", Unit: "milliseconds"}, | ||
Period: 1, | ||
DurationNanos: 10e9, | ||
SampleType: []*ValueType{{Type: "samples", Unit: "count"}}, | ||
Mapping: mappings, | ||
Function: functions, | ||
Location: emptyLinesLocs, | ||
Sample: []*Sample{ | ||
{Value: []int64{1}, Location: []*Location{emptyLinesLocs[0], emptyLinesLocs[1]}}, | ||
{Value: []int64{2}, Location: []*Location{emptyLinesLocs[2]}}, | ||
{Value: []int64{3}, Location: []*Location{}}, | ||
}, | ||
} | ||
|
||
func TestFilterSamplesByName(t *testing.T) { | ||
for _, tc := range []struct { | ||
// name is the name of the test case. | ||
name string | ||
|
@@ -392,6 +414,130 @@ func TestFilter(t *testing.T) { | |
} | ||
} | ||
|
||
func TestShowFrom(t *testing.T) { | ||
for _, tc := range []struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have test cases that check that "show from" shows frames from the highest match? It is not obvious from the test names that any test does that. Need a test for both locations and lines. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added two test cases. one for matching multiple frames without inlines, and one with inlines. |
||
name string | ||
profile *Profile | ||
showFrom *regexp.Regexp | ||
// wantMatch is the expected return value. | ||
wantMatch bool | ||
// wantSampleFuncs contains expected stack functions and sample value after | ||
// filtering, in the same order as in the profile. The format is as | ||
// returned by sampleFuncs function below, which is "callee caller: <num>". | ||
wantSampleFuncs []string | ||
}{ | ||
{ | ||
name: "nil showFrom keeps all frames", | ||
profile: noInlinesProfile, | ||
wantMatch: false, | ||
wantSampleFuncs: allNoInlinesSampleFuncs, | ||
}, | ||
{ | ||
name: "showFrom with no matches drops all samples", | ||
profile: noInlinesProfile, | ||
showFrom: regexp.MustCompile("unknown"), | ||
wantMatch: false, | ||
}, | ||
{ | ||
name: "showFrom matches function names", | ||
profile: noInlinesProfile, | ||
showFrom: regexp.MustCompile("fun1"), | ||
wantMatch: true, | ||
wantSampleFuncs: []string{ | ||
"fun0 fun1: 1", | ||
"fun4 fun5 fun1: 2", | ||
"fun9 fun4 fun10: 4", | ||
}, | ||
}, | ||
{ | ||
name: "showFrom matches file names", | ||
profile: noInlinesProfile, | ||
showFrom: regexp.MustCompile("file1"), | ||
wantMatch: true, | ||
wantSampleFuncs: []string{ | ||
"fun0 fun1: 1", | ||
"fun4 fun5 fun1: 2", | ||
"fun9 fun4 fun10: 4", | ||
}, | ||
}, | ||
{ | ||
name: "showFrom matches mapping names", | ||
profile: noInlinesProfile, | ||
showFrom: regexp.MustCompile("map1"), | ||
wantMatch: true, | ||
wantSampleFuncs: []string{ | ||
"fun9 fun4 fun10: 4", | ||
}, | ||
}, | ||
{ | ||
name: "showFrom drops frames above highest of multiple matches", | ||
profile: noInlinesProfile, | ||
showFrom: regexp.MustCompile("fun[12]"), | ||
wantMatch: true, | ||
wantSampleFuncs: []string{ | ||
"fun0 fun1 fun2: 1", | ||
"fun4 fun5 fun1: 2", | ||
"fun9 fun4 fun10: 4", | ||
}, | ||
}, | ||
{ | ||
name: "showFrom matches inline functions", | ||
profile: inlinesProfile, | ||
showFrom: regexp.MustCompile("fun0|fun5"), | ||
wantMatch: true, | ||
wantSampleFuncs: []string{ | ||
"fun0: 1", | ||
"fun4 fun5: 2", | ||
}, | ||
}, | ||
{ | ||
name: "showFrom drops frames above highest of multiple inline matches", | ||
profile: inlinesProfile, | ||
showFrom: regexp.MustCompile("fun[1245]"), | ||
wantMatch: true, | ||
wantSampleFuncs: []string{ | ||
"fun0 fun1 fun2: 1", | ||
"fun4 fun5: 2", | ||
}, | ||
}, | ||
{ | ||
name: "showFrom keeps all lines when matching mapping and function", | ||
profile: inlinesProfile, | ||
showFrom: regexp.MustCompile("map0|fun5"), | ||
wantMatch: true, | ||
wantSampleFuncs: []string{ | ||
"fun0 fun1 fun2 fun3: 1", | ||
"fun4 fun5 fun6: 2", | ||
}, | ||
}, | ||
{ | ||
name: "showFrom matches location with empty lines", | ||
profile: emptyLinesProfile, | ||
showFrom: regexp.MustCompile("map1"), | ||
wantMatch: true, | ||
wantSampleFuncs: []string{ | ||
": 2", | ||
}, | ||
}, | ||
} { | ||
t.Run(tc.name, func(t *testing.T) { | ||
p := tc.profile.Copy() | ||
|
||
if gotMatch := p.ShowFrom(tc.showFrom); gotMatch != tc.wantMatch { | ||
t.Errorf("match got %+v, want %+v", gotMatch, tc.wantMatch) | ||
} | ||
|
||
if got, want := strings.Join(sampleFuncs(p), "\n")+"\n", strings.Join(tc.wantSampleFuncs, "\n")+"\n"; got != want { | ||
diff, err := proftest.Diff([]byte(want), []byte(got)) | ||
if err != nil { | ||
t.Fatalf("failed to get diff: %v", err) | ||
} | ||
t.Errorf("profile samples got diff(want->got):\n%s", diff) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
// sampleFuncs returns a slice of strings where each string represents one | ||
// profile sample in the format "<fun1> <fun2> <fun3>: <value>". This allows | ||
// the expected values for test cases to be specifed in human-readable strings. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why adding showFrom var and separate check and not just put this line after
v.set("show", "")
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure whether to include it in the focus or hide section. it seems those flags are semantically equivalent so i combined focus, hide, and showFrom into a single flag "filter".