Sfoglia il codice sorgente

Fake mappings should be merged into a single one during merging (#357)

Jianqiao Li 7 anni fa
parent
commit
2c640795af
2 ha cambiato i file con 190 aggiunte e 35 eliminazioni
  1. 23
    35
      profile/merge.go
  2. 167
    0
      profile/merge_test.go

+ 23
- 35
profile/merge.go Vedi File

@@ -294,20 +294,11 @@ func (pm *profileMerger) mapMapping(src *Mapping) mapInfo {
294 294
 	}
295 295
 
296 296
 	// Check memoization tables.
297
-	bk, pk := src.key()
298
-	if src.BuildID != "" {
299
-		if m, ok := pm.mappings[bk]; ok {
300
-			mi := mapInfo{m, int64(m.Start) - int64(src.Start)}
301
-			pm.mappingsByID[src.ID] = mi
302
-			return mi
303
-		}
304
-	}
305
-	if src.File != "" {
306
-		if m, ok := pm.mappings[pk]; ok {
307
-			mi := mapInfo{m, int64(m.Start) - int64(src.Start)}
308
-			pm.mappingsByID[src.ID] = mi
309
-			return mi
310
-		}
297
+	mk := src.key()
298
+	if m, ok := pm.mappings[mk]; ok {
299
+		mi := mapInfo{m, int64(m.Start) - int64(src.Start)}
300
+		pm.mappingsByID[src.ID] = mi
301
+		return mi
311 302
 	}
312 303
 	m := &Mapping{
313 304
 		ID:              uint64(len(pm.p.Mapping) + 1),
@@ -324,21 +315,15 @@ func (pm *profileMerger) mapMapping(src *Mapping) mapInfo {
324 315
 	pm.p.Mapping = append(pm.p.Mapping, m)
325 316
 
326 317
 	// Update memoization tables.
327
-	if m.BuildID != "" {
328
-		pm.mappings[bk] = m
329
-	}
330
-	if m.File != "" {
331
-		pm.mappings[pk] = m
332
-	}
318
+	pm.mappings[mk] = m
333 319
 	mi := mapInfo{m, 0}
334 320
 	pm.mappingsByID[src.ID] = mi
335 321
 	return mi
336 322
 }
337 323
 
338 324
 // key generates encoded strings of Mapping to be used as a key for
339
-// maps. The first key represents only the build id, while the second
340
-// represents only the file path.
341
-func (m *Mapping) key() (buildIDKey, pathKey mappingKey) {
325
+// maps.
326
+func (m *Mapping) key() mappingKey {
342 327
 	// Normalize addresses to handle address space randomization.
343 328
 	// Round up to next 4K boundary to avoid minor discrepancies.
344 329
 	const mapsizeRounding = 0x1000
@@ -346,24 +331,27 @@ func (m *Mapping) key() (buildIDKey, pathKey mappingKey) {
346 331
 	size := m.Limit - m.Start
347 332
 	size = size + mapsizeRounding - 1
348 333
 	size = size - (size % mapsizeRounding)
349
-
350
-	buildIDKey = mappingKey{
351
-		size,
352
-		m.Offset,
353
-		m.BuildID,
334
+	key := mappingKey{
335
+		size:   size,
336
+		offset: m.Offset,
354 337
 	}
355 338
 
356
-	pathKey = mappingKey{
357
-		size,
358
-		m.Offset,
359
-		m.File,
339
+	switch {
340
+	case m.BuildID != "":
341
+		key.buildIDOrFile = m.BuildID
342
+	case m.File != "":
343
+		key.buildIDOrFile = m.File
344
+	default:
345
+		// A mapping containing neither build ID nor file name is a fake mapping. A
346
+		// key with empty buildIDOrFile is used for fake mappings so that they are
347
+		// treated as the same mapping during merging.
360 348
 	}
361
-	return
349
+	return key
362 350
 }
363 351
 
364 352
 type mappingKey struct {
365
-	size, offset    uint64
366
-	buildidIDOrFile string
353
+	size, offset  uint64
354
+	buildIDOrFile string
367 355
 }
368 356
 
369 357
 func (pm *profileMerger) mapLine(src Line) Line {

+ 167
- 0
profile/merge_test.go Vedi File

@@ -0,0 +1,167 @@
1
+// Copyright 2018 Google Inc. All Rights Reserved.
2
+//
3
+// Licensed under the Apache License, Version 2.0 (the "License");
4
+// you may not use this file except in compliance with the License.
5
+// You may obtain a copy of the License at
6
+//
7
+//     http://www.apache.org/licenses/LICENSE-2.0
8
+//
9
+// Unless required by applicable law or agreed to in writing, software
10
+// distributed under the License is distributed on an "AS IS" BASIS,
11
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+// See the License for the specific language governing permissions and
13
+// limitations under the License.
14
+
15
+package profile
16
+
17
+import (
18
+	"testing"
19
+)
20
+
21
+func TestMapMapping(t *testing.T) {
22
+	pm := &profileMerger{
23
+		p:            &Profile{},
24
+		mappings:     make(map[mappingKey]*Mapping),
25
+		mappingsByID: make(map[uint64]mapInfo),
26
+	}
27
+	for _, tc := range []struct {
28
+		desc       string
29
+		m1         Mapping
30
+		m2         Mapping
31
+		wantMerged bool
32
+	}{
33
+		{
34
+			desc: "same file name",
35
+			m1: Mapping{
36
+				ID:   1,
37
+				File: "test-file-1",
38
+			},
39
+			m2: Mapping{
40
+				ID:   2,
41
+				File: "test-file-1",
42
+			},
43
+			wantMerged: true,
44
+		},
45
+		{
46
+			desc: "same build ID",
47
+			m1: Mapping{
48
+				ID:      3,
49
+				BuildID: "test-build-id-1",
50
+			},
51
+			m2: Mapping{
52
+				ID:      4,
53
+				BuildID: "test-build-id-1",
54
+			},
55
+			wantMerged: true,
56
+		},
57
+		{
58
+			desc: "same fake mapping",
59
+			m1: Mapping{
60
+				ID: 5,
61
+			},
62
+			m2: Mapping{
63
+				ID: 6,
64
+			},
65
+			wantMerged: true,
66
+		},
67
+		{
68
+			desc: "different start",
69
+			m1: Mapping{
70
+				ID:      7,
71
+				Start:   0x1000,
72
+				Limit:   0x2000,
73
+				BuildID: "test-build-id-2",
74
+			},
75
+			m2: Mapping{
76
+				ID:      8,
77
+				Start:   0x3000,
78
+				Limit:   0x4000,
79
+				BuildID: "test-build-id-2",
80
+			},
81
+			wantMerged: true,
82
+		},
83
+		{
84
+			desc: "different file name",
85
+			m1: Mapping{
86
+				ID:   9,
87
+				File: "test-file-2",
88
+			},
89
+			m2: Mapping{
90
+				ID:   10,
91
+				File: "test-file-3",
92
+			},
93
+		},
94
+		{
95
+			desc: "different build id",
96
+			m1: Mapping{
97
+				ID:      11,
98
+				BuildID: "test-build-id-3",
99
+			},
100
+			m2: Mapping{
101
+				ID:      12,
102
+				BuildID: "test-build-id-4",
103
+			},
104
+		},
105
+		{
106
+			desc: "different size",
107
+			m1: Mapping{
108
+				ID:      13,
109
+				Start:   0x1000,
110
+				Limit:   0x3000,
111
+				BuildID: "test-build-id-5",
112
+			},
113
+			m2: Mapping{
114
+				ID:      14,
115
+				Start:   0x1000,
116
+				Limit:   0x5000,
117
+				BuildID: "test-build-id-5",
118
+			},
119
+		},
120
+		{
121
+			desc: "different offset",
122
+			m1: Mapping{
123
+				ID:      15,
124
+				Offset:  1,
125
+				BuildID: "test-build-id-6",
126
+			},
127
+			m2: Mapping{
128
+				ID:      16,
129
+				Offset:  2,
130
+				BuildID: "test-build-id-6",
131
+			},
132
+		},
133
+	} {
134
+		t.Run(tc.desc, func(t *testing.T) {
135
+			info1 := pm.mapMapping(&tc.m1)
136
+			info2 := pm.mapMapping(&tc.m2)
137
+			gotM1, gotM2 := *info1.m, *info2.m
138
+
139
+			wantM1 := tc.m1
140
+			wantM1.ID = gotM1.ID
141
+			if gotM1 != wantM1 {
142
+				t.Errorf("first mapping got %v, want %v", gotM1, wantM1)
143
+			}
144
+
145
+			if tc.wantMerged {
146
+				if gotM1 != gotM2 {
147
+					t.Errorf("first mapping got %v, second mapping got %v, want equal", gotM1, gotM2)
148
+				}
149
+				if info1.offset != 0 {
150
+					t.Errorf("first mapping info got offset %d, want 0", info1.offset)
151
+				}
152
+				if wantOffset := int64(tc.m1.Start) - int64(tc.m2.Start); wantOffset != info2.offset {
153
+					t.Errorf("second mapping info got offset %d, want %d", info2.offset, wantOffset)
154
+				}
155
+			} else {
156
+				if gotM1.ID == gotM2.ID {
157
+					t.Errorf("first mapping got %v, second mapping got %v, want different IDs", gotM1, gotM2)
158
+				}
159
+				wantM2 := tc.m2
160
+				wantM2.ID = gotM2.ID
161
+				if gotM2 != wantM2 {
162
+					t.Errorf("second mapping got %v, want %v", gotM2, wantM2)
163
+				}
164
+			}
165
+		})
166
+	}
167
+}