Pārlūkot izejas kodu

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 gadus atpakaļ
vecāks
revīzija
57b4d4871d
1 mainītis faili ar 81 papildinājumiem un 44 dzēšanām
  1. 81
    44
      profile/merge.go

+ 81
- 44
profile/merge.go Parādīt failu

@@ -40,10 +40,10 @@ func Merge(srcs []*Profile) (*Profile, error) {
40 40
 
41 41
 	pm := &profileMerger{
42 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 49
 	for _, src := range srcs {
@@ -96,10 +96,10 @@ type profileMerger struct {
96 96
 	mappingsByID  map[uint64]mapInfo
97 97
 
98 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 105
 type mapInfo struct {
@@ -143,30 +143,36 @@ func (pm *profileMerger) mapSample(src *Sample) *Sample {
143 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 148
 	ids := make([]string, len(sample.Location))
149 149
 	for i, l := range sample.Location {
150 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 178
 func (pm *profileMerger) mapLocation(src *Location) *Location {
@@ -202,21 +208,28 @@ func (pm *profileMerger) mapLocation(src *Location) *Location {
202 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 216
 	if l.Mapping != nil {
210 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 235
 func (pm *profileMerger) mapMapping(src *Mapping) mapInfo {
@@ -273,7 +286,7 @@ func (pm *profileMerger) mapMapping(src *Mapping) mapInfo {
273 286
 // key generates encoded strings of Mapping to be used as a key for
274 287
 // maps. The first key represents only the build id, while the second
275 288
 // represents only the file path.
276
-func (m *Mapping) key() (buildIDKey, pathKey string) {
289
+func (m *Mapping) key() (buildIDKey, pathKey mappingKey) {
277 290
 	// Normalize addresses to handle address space randomization.
278 291
 	// Round up to next 4K boundary to avoid minor discrepancies.
279 292
 	const mapsizeRounding = 0x1000
@@ -281,12 +294,26 @@ func (m *Mapping) key() (buildIDKey, pathKey string) {
281 294
 	size := m.Limit - m.Start
282 295
 	size = size + mapsizeRounding - 1
283 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 309
 	return
288 310
 }
289 311
 
312
+type mappingKey struct {
313
+	size, offset    uint64
314
+	buildidIDOrFile string
315
+}
316
+
290 317
 func (pm *profileMerger) mapLine(src Line) Line {
291 318
 	ln := Line{
292 319
 		Function: pm.mapFunction(src.Function),
@@ -320,9 +347,19 @@ func (pm *profileMerger) mapFunction(src *Function) *Function {
320 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 365
 // combineHeaders checks that all profiles can be merged and returns