瀏覽代碼

Speed up profile merging

Profile merging spends a lot of time computing function keys, which are currently a string.
Using structs for the keys whenever possible will reduce the overhead.
Raul Silvera 9 年之前
父節點
當前提交
57b4d4871d
共有 1 個檔案被更改,包括 81 行新增44 行删除
  1. 81
    44
      profile/merge.go

+ 81
- 44
profile/merge.go 查看文件

40
 
40
 
41
 	pm := &profileMerger{
41
 	pm := &profileMerger{
42
 		p:         p,
42
 		p:         p,
43
-		samples:   make(map[string]*Sample, len(srcs[0].Sample)),
44
-		locations: make(map[string]*Location, len(srcs[0].Location)),
45
-		functions: make(map[string]*Function, len(srcs[0].Function)),
46
-		mappings:  make(map[string]*Mapping, len(srcs[0].Mapping)),
43
+		samples:   make(map[sampleKey]*Sample, len(srcs[0].Sample)),
44
+		locations: make(map[locationKey]*Location, len(srcs[0].Location)),
45
+		functions: make(map[functionKey]*Function, len(srcs[0].Function)),
46
+		mappings:  make(map[mappingKey]*Mapping, len(srcs[0].Mapping)),
47
 	}
47
 	}
48
 
48
 
49
 	for _, src := range srcs {
49
 	for _, src := range srcs {
96
 	mappingsByID  map[uint64]mapInfo
96
 	mappingsByID  map[uint64]mapInfo
97
 
97
 
98
 	// Memoization tables for profile entities.
98
 	// Memoization tables for profile entities.
99
-	samples   map[string]*Sample
100
-	locations map[string]*Location
101
-	functions map[string]*Function
102
-	mappings  map[string]*Mapping
99
+	samples   map[sampleKey]*Sample
100
+	locations map[locationKey]*Location
101
+	functions map[functionKey]*Function
102
+	mappings  map[mappingKey]*Mapping
103
 }
103
 }
104
 
104
 
105
 type mapInfo struct {
105
 type mapInfo struct {
143
 	return s
143
 	return s
144
 }
144
 }
145
 
145
 
146
-// key generates encoded string of Sample to be used as a key for maps.
147
-func (sample *Sample) key() (s string) {
146
+// key generates sampleKey to be used as a key for maps.
147
+func (sample *Sample) key() sampleKey {
148
 	ids := make([]string, len(sample.Location))
148
 	ids := make([]string, len(sample.Location))
149
 	for i, l := range sample.Location {
149
 	for i, l := range sample.Location {
150
 		ids[i] = strconv.FormatUint(l.ID, 16)
150
 		ids[i] = strconv.FormatUint(l.ID, 16)
151
 	}
151
 	}
152
-	s = strings.Join(ids, "|")
153
-	if len(sample.Label) != 0 {
154
-		labels := make([]string, 0, len(sample.Label))
155
-		for k, v := range sample.Label {
156
-			labels = append(labels, fmt.Sprintf("%q%q", k, v))
157
-		}
158
-		sort.Strings(labels)
159
-		s += strings.Join(labels, "")
152
+
153
+	labels := make([]string, 0, len(sample.Label))
154
+	for k, v := range sample.Label {
155
+		labels = append(labels, fmt.Sprintf("%q%q", k, v))
160
 	}
156
 	}
161
-	if len(sample.NumLabel) > 0 {
162
-		labels := make([]string, 0, len(sample.NumLabel))
163
-		for k, v := range sample.NumLabel {
164
-			labels = append(labels, fmt.Sprintf("%q%v", k, v))
165
-		}
166
-		sort.Strings(labels)
167
-		s += strings.Join(labels, "")
157
+	sort.Strings(labels)
158
+
159
+	numlabels := make([]string, 0, len(sample.NumLabel))
160
+	for k, v := range sample.NumLabel {
161
+		numlabels = append(numlabels, fmt.Sprintf("%q%x", k, v))
168
 	}
162
 	}
169
-	return s
163
+	sort.Strings(numlabels)
164
+
165
+	return sampleKey{
166
+		strings.Join(ids, "|"),
167
+		strings.Join(labels, ""),
168
+		strings.Join(numlabels, ""),
169
+	}
170
+}
171
+
172
+type sampleKey struct {
173
+	locations string
174
+	labels    string
175
+	numlabels string
170
 }
176
 }
171
 
177
 
172
 func (pm *profileMerger) mapLocation(src *Location) *Location {
178
 func (pm *profileMerger) mapLocation(src *Location) *Location {
202
 	return l
208
 	return l
203
 }
209
 }
204
 
210
 
205
-// key generates encoded string of Location to be used as a key for maps.
206
-func (l *Location) key() string {
207
-	addr := l.Address
208
-	var s string
211
+// key generates locationKey to be used as a key for maps.
212
+func (l *Location) key() locationKey {
213
+	key := locationKey{
214
+		addr: l.Address,
215
+	}
209
 	if l.Mapping != nil {
216
 	if l.Mapping != nil {
210
 		// Normalizes address to handle address space randomization.
217
 		// Normalizes address to handle address space randomization.
211
-		addr -= l.Mapping.Start
212
-		s = strconv.FormatUint(l.Mapping.ID, 16) + "|" + strconv.FormatUint(addr, 16)
213
-	} else {
214
-		s = "0|" + strconv.FormatUint(addr, 16)
218
+		key.addr -= l.Mapping.Start
219
+		key.mappingID = l.Mapping.ID
215
 	}
220
 	}
216
-	for _, line := range l.Line {
217
-		s += strconv.FormatUint(line.Function.ID, 16) + "|" + strconv.FormatInt(line.Line, 16)
221
+	lines := make([]string, len(l.Line)*2)
222
+	for i, line := range l.Line {
223
+		lines[i*2] = strconv.FormatUint(line.Function.ID, 16)
224
+		lines[i*2+1] = strconv.FormatInt(line.Line, 16)
218
 	}
225
 	}
219
-	return s
226
+	key.lines = strings.Join(lines, "|")
227
+	return key
228
+}
229
+
230
+type locationKey struct {
231
+	addr, mappingID uint64
232
+	lines           string
220
 }
233
 }
221
 
234
 
222
 func (pm *profileMerger) mapMapping(src *Mapping) mapInfo {
235
 func (pm *profileMerger) mapMapping(src *Mapping) mapInfo {
273
 // key generates encoded strings of Mapping to be used as a key for
286
 // key generates encoded strings of Mapping to be used as a key for
274
 // maps. The first key represents only the build id, while the second
287
 // maps. The first key represents only the build id, while the second
275
 // represents only the file path.
288
 // represents only the file path.
276
-func (m *Mapping) key() (buildIDKey, pathKey string) {
289
+func (m *Mapping) key() (buildIDKey, pathKey mappingKey) {
277
 	// Normalize addresses to handle address space randomization.
290
 	// Normalize addresses to handle address space randomization.
278
 	// Round up to next 4K boundary to avoid minor discrepancies.
291
 	// Round up to next 4K boundary to avoid minor discrepancies.
279
 	const mapsizeRounding = 0x1000
292
 	const mapsizeRounding = 0x1000
281
 	size := m.Limit - m.Start
294
 	size := m.Limit - m.Start
282
 	size = size + mapsizeRounding - 1
295
 	size = size + mapsizeRounding - 1
283
 	size = size - (size % mapsizeRounding)
296
 	size = size - (size % mapsizeRounding)
284
-	key := strconv.FormatUint(size, 16) + "|" + strconv.FormatUint(m.Offset, 16)
285
-	buildIDKey = key + "B" + strconv.Quote(m.BuildID)
286
-	pathKey = key + "F" + strconv.Quote(m.File)
297
+
298
+	buildIDKey = mappingKey{
299
+		size,
300
+		m.Offset,
301
+		m.BuildID,
302
+	}
303
+
304
+	pathKey = mappingKey{
305
+		size,
306
+		m.Offset,
307
+		m.File,
308
+	}
287
 	return
309
 	return
288
 }
310
 }
289
 
311
 
312
+type mappingKey struct {
313
+	size, offset    uint64
314
+	buildidIDOrFile string
315
+}
316
+
290
 func (pm *profileMerger) mapLine(src Line) Line {
317
 func (pm *profileMerger) mapLine(src Line) Line {
291
 	ln := Line{
318
 	ln := Line{
292
 		Function: pm.mapFunction(src.Function),
319
 		Function: pm.mapFunction(src.Function),
320
 	return f
347
 	return f
321
 }
348
 }
322
 
349
 
323
-// key generates encoded string of Function to be used as a key for maps.
324
-func (f *Function) key() string {
325
-	return fmt.Sprintf("%x%q%q%q", f.StartLine, f.Name, f.SystemName, f.Filename)
350
+// key generates a struct to be used as a key for maps.
351
+func (f *Function) key() functionKey {
352
+	return functionKey{
353
+		f.StartLine,
354
+		f.Name,
355
+		f.SystemName,
356
+		f.Filename,
357
+	}
358
+}
359
+
360
+type functionKey struct {
361
+	startLine                  int64
362
+	name, systemName, fileName string
326
 }
363
 }
327
 
364
 
328
 // combineHeaders checks that all profiles can be merged and returns
365
 // combineHeaders checks that all profiles can be merged and returns