Преглед на файлове

When pruning unsimplified names, don't trim "(anonymous namespace)". (#140)

* When pruning unsimplified names, don't trim "(anonymous namespace)".

Fixes #139.

* Fix copy/paste. Add test.

* Check for braces with a RE. Add more complex test cases. And operator().

* Fix last-minute debug.

* Construct bracketRx more cleanly

* spelling

* Redundant nil check

* While we're removing things...
Svilen Kanev преди 8 години
родител
ревизия
fffc5831a4
променени са 2 файла, в които са добавени 126 реда и са изтрити 12 реда
  1. 35
    12
      profile/prune.go
  2. 91
    0
      profile/prune_test.go

+ 35
- 12
profile/prune.go Целия файл

@@ -22,6 +22,39 @@ import (
22 22
 	"strings"
23 23
 )
24 24
 
25
+var (
26
+	reservedNames = []string{"(anonymous namespace)", "operator()"}
27
+	bracketRx     = func() *regexp.Regexp {
28
+		var quotedNames []string
29
+		for _, name := range append(reservedNames, "(") {
30
+			quotedNames = append(quotedNames, regexp.QuoteMeta(name))
31
+		}
32
+		return regexp.MustCompile(strings.Join(quotedNames, "|"))
33
+	}()
34
+)
35
+
36
+// simplifyFunc does some primitive simplification of function names.
37
+func simplifyFunc(f string) string {
38
+	// Account for leading '.' on the PPC ELF v1 ABI.
39
+	funcName := strings.TrimPrefix(f, ".")
40
+	// Account for unsimplified names -- try  to remove the argument list by trimming
41
+	// starting from the first '(', but skipping reserved names that have '('.
42
+	for _, ind := range bracketRx.FindAllStringSubmatchIndex(funcName, -1) {
43
+		foundReserved := false
44
+		for _, res := range reservedNames {
45
+			if funcName[ind[0]:ind[1]] == res {
46
+				foundReserved = true
47
+				break
48
+			}
49
+		}
50
+		if !foundReserved {
51
+			funcName = funcName[:ind[0]]
52
+			break
53
+		}
54
+	}
55
+	return funcName
56
+}
57
+
25 58
 // Prune removes all nodes beneath a node matching dropRx, and not
26 59
 // matching keepRx. If the root node of a Sample matches, the sample
27 60
 // will have an empty stack.
@@ -33,12 +66,7 @@ func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) {
33 66
 		var i int
34 67
 		for i = len(loc.Line) - 1; i >= 0; i-- {
35 68
 			if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
36
-				// Account for leading '.' on the PPC ELF v1 ABI.
37
-				funcName := strings.TrimPrefix(fn.Name, ".")
38
-				// Account for unsimplified names -- trim starting from the first '('.
39
-				if index := strings.Index(funcName, "("); index > 0 {
40
-					funcName = funcName[:index]
41
-				}
69
+				funcName := simplifyFunc(fn.Name)
42 70
 				if dropRx.MatchString(funcName) {
43 71
 					if keepRx == nil || !keepRx.MatchString(funcName) {
44 72
 						break
@@ -126,12 +154,7 @@ func (p *Profile) PruneFrom(dropRx *regexp.Regexp) {
126 154
 	for _, loc := range p.Location {
127 155
 		for i := 0; i < len(loc.Line); i++ {
128 156
 			if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
129
-				// Account for leading '.' on the PPC ELF v1 ABI.
130
-				funcName := strings.TrimPrefix(fn.Name, ".")
131
-				// Account for unsimplified names -- trim starting from the first '('.
132
-				if index := strings.Index(funcName, "("); index > 0 {
133
-					funcName = funcName[:index]
134
-				}
157
+				funcName := simplifyFunc(fn.Name)
135 158
 				if dropRx.MatchString(funcName) {
136 159
 					// Found matching entry to prune.
137 160
 					pruneBeneath[loc.ID] = true

+ 91
- 0
profile/prune_test.go Целия файл

@@ -25,6 +25,7 @@ func TestPrune(t *testing.T) {
25 25
 		want string
26 26
 	}{
27 27
 		{in1, out1},
28
+		{in2, out2},
28 29
 	} {
29 30
 		in := test.in.Copy()
30 31
 		in.RemoveUninteresting()
@@ -50,6 +51,10 @@ var funs = []*Function{
50 51
 	{ID: 4, Name: "fun3", SystemName: "fun3", Filename: "fun.c"},
51 52
 	{ID: 5, Name: "fun4", SystemName: "fun4", Filename: "fun.c"},
52 53
 	{ID: 6, Name: "fun5", SystemName: "fun5", Filename: "fun.c"},
54
+	{ID: 7, Name: "unsimplified_fun(int)", SystemName: "unsimplified_fun(int)", Filename: "fun.c"},
55
+	{ID: 8, Name: "Foo::(anonymous namespace)::Test::Bar", SystemName: "Foo::(anonymous namespace)::Test::Bar", Filename: "fun.c"},
56
+	{ID: 9, Name: "Hello::(anonymous namespace)::World(const Foo::(anonymous namespace)::Test::Bar)", SystemName: "Hello::(anonymous namespace)::World(const Foo::(anonymous namespace)::Test::Bar)", Filename: "fun.c"},
57
+	{ID: 10, Name: "Foo::operator()(::Bar)", SystemName: "Foo::operator()(::Bar)", Filename: "fun.c"},
53 58
 }
54 59
 
55 60
 var locs1 = []*Location{
@@ -137,3 +142,89 @@ Locations
137 142
      4: 0x0 fun5 fun.c:2 s=0
138 143
 Mappings
139 144
 `
145
+
146
+var locs2 = []*Location{
147
+	{
148
+		ID: 1,
149
+		Line: []Line{
150
+			{Function: funs[0], Line: 1},
151
+		},
152
+	},
153
+	{
154
+		ID: 2,
155
+		Line: []Line{
156
+			{Function: funs[6], Line: 1},
157
+		},
158
+	},
159
+	{
160
+		ID: 3,
161
+		Line: []Line{
162
+			{Function: funs[7], Line: 1},
163
+		},
164
+	},
165
+	{
166
+		ID: 4,
167
+		Line: []Line{
168
+			{Function: funs[8], Line: 1},
169
+		},
170
+	},
171
+	{
172
+		ID: 5,
173
+		Line: []Line{
174
+			{Function: funs[9], Line: 1},
175
+		},
176
+	},
177
+}
178
+
179
+var in2 = &Profile{
180
+	PeriodType:    &ValueType{Type: "cpu", Unit: "milliseconds"},
181
+	Period:        1,
182
+	DurationNanos: 10e9,
183
+	SampleType: []*ValueType{
184
+		{Type: "samples", Unit: "count"},
185
+		{Type: "cpu", Unit: "milliseconds"},
186
+	},
187
+	Sample: []*Sample{
188
+		// Unsimplified name with parameters shouldn't match.
189
+		{
190
+			Location: []*Location{locs2[1], locs2[0]},
191
+			Value:    []int64{1, 1},
192
+		},
193
+		// .*Foo::.*::Bar.* should (and will be dropped) regardless of the anonymous namespace.
194
+		{
195
+			Location: []*Location{locs2[2], locs2[0]},
196
+			Value:    []int64{1, 1},
197
+		},
198
+		// .*Foo::.*::Bar.* shouldn't match inside the parameter list.
199
+		{
200
+			Location: []*Location{locs2[3], locs2[0]},
201
+			Value:    []int64{1, 1},
202
+		},
203
+		// .*operator\(\) should match, regardless of parameters.
204
+		{
205
+			Location: []*Location{locs2[4], locs2[0]},
206
+			Value:    []int64{1, 1},
207
+		},
208
+	},
209
+	Location:   locs2,
210
+	Function:   funs,
211
+	DropFrames: `unsimplified_fun\(int\)|.*Foo::.*::Bar.*|.*operator\(\)`,
212
+}
213
+
214
+const out2 = `PeriodType: cpu milliseconds
215
+Period: 1
216
+Duration: 10s
217
+Samples:
218
+samples/count cpu/milliseconds
219
+          1          1: 2 1
220
+          1          1: 1
221
+          1          1: 4 1
222
+          1          1: 1
223
+Locations
224
+     1: 0x0 main main.c:1 s=0
225
+     2: 0x0 unsimplified_fun(int) fun.c:1 s=0
226
+     3: 0x0 Foo::(anonymous namespace)::Test::Bar fun.c:1 s=0
227
+     4: 0x0 Hello::(anonymous namespace)::World(const Foo::(anonymous namespace)::Test::Bar) fun.c:1 s=0
228
+     5: 0x0 Foo::operator()(::Bar) fun.c:1 s=0
229
+Mappings
230
+`