Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(200)

Side by Side Diff: components/metrics/call_stack_profile_metrics_provider_unittest.cc

Issue 981143006: Metrics provider for statistical stack profiler (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkcr
Patch Set: handle unknown module (per other review) Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/metrics/call_stack_profile_metrics_provider.h"
6
7 #include "base/profiler/stack_sampling_profiler.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11
12 using base::StackSamplingProfiler;
13 using Frame = StackSamplingProfiler::Frame;
14 using Module = StackSamplingProfiler::Module;
15 using Profile = StackSamplingProfiler::Profile;
16 using Sample = StackSamplingProfiler::Sample;
17
18 namespace metrics {
19
20 // Checks that all properties from multiple profiles are filled as expected.
21 TEST(CallStackProfileMetricsProviderTest, MultipleProfiles) {
22 const uintptr_t module1_base_address = 0x1000;
23 const uintptr_t module2_base_address = 0x2000;
24 const uintptr_t module3_base_address = 0x3000;
25
26 const Module profile_modules[][2] = {
27 {
28 {
29 reinterpret_cast<const void*>(module1_base_address),
30 "ABCD",
31 #if defined(OS_WIN)
32 base::FilePath(L"c:\\some\\path\\to\\chrome.exe")
33 #else
34 base::FilePath("/some/path/to/chrome")
35 #endif
36 },
37 {
38 reinterpret_cast<const void*>(module2_base_address),
39 "EFGH",
40 #if defined(OS_WIN)
41 base::FilePath(L"c:\\some\\path\\to\\third_party.dll")
42 #else
43 base::FilePath("/some/path/to/third_party.so")
44 #endif
45 }
46 },
47 {
48 {
49 reinterpret_cast<const void*>(module3_base_address),
50 "MNOP",
51 #if defined(OS_WIN)
52 base::FilePath(L"c:\\some\\path\\to\\third_party2.dll")
53 #else
54 base::FilePath("/some/path/to/third_party2.so")
55 #endif
56 },
57 { // Repeated from the first profile.
58 reinterpret_cast<const void*>(module1_base_address),
59 "ABCD",
60 #if defined(OS_WIN)
61 base::FilePath(L"c:\\some\\path\\to\\chrome.exe")
62 #else
63 base::FilePath("/some/path/to/chrome")
64 #endif
65 },
66 }
67 };
68
69 // Values for Windows generated with:
70 // perl -MDigest::MD5=md5 -MEncode=encode \
71 // -e 'for(@ARGV){printf "%x\n", unpack "Q>", md5 encode "UTF-16LE", $_}' \
72 // chrome.exe third_party.dll third_party2.dll
73 //
74 // Values for Linux generated with:
75 // perl -MDigest::MD5=md5 \
76 // -e 'for(@ARGV){printf "%x\n", unpack "Q>", md5 $_}' \
77 // chrome third_party.so third_party2.so
78 const uint64 profile_expected_name_md5_prefixes[][2] = {
79 {
80 #if defined(OS_WIN)
81 0x46c3e4166659ac02ULL,
82 0x7e2b8bfddeae1abaULL
83 #else
84 0x554838a8451ac36cUL,
85 0x843661148659c9f8UL
86 #endif
87 },
88 {
89 #if defined(OS_WIN)
90 0x87b66f4573a4d5caULL,
91 0x46c3e4166659ac02ULL
92 #else
93 0xb4647e539fa6ec9eUL,
94 0x554838a8451ac36cUL
95 #endif
96 }
97 };
98
99 // Frames for all samples for all profiles in the test.
Ilya Sherman 2015/03/19 00:10:20 What I really meant with my previous request was,
Mike Wittman 2015/03/19 00:56:58 Done.
100 const Frame profile_sample_frames[][2][3] = {
101 {
102 {
103 { reinterpret_cast<const void*>(module1_base_address + 0x10), 0 },
104 { reinterpret_cast<const void*>(module2_base_address + 0x20), 1 },
105 { reinterpret_cast<const void*>(module1_base_address + 0x30), 0 }
106 },
107 {
108 { reinterpret_cast<const void*>(module2_base_address + 0x10), 1 },
109 { reinterpret_cast<const void*>(module1_base_address + 0x20), 0 },
110 { reinterpret_cast<const void*>(module2_base_address + 0x30), 1 }
111 }
112 },
113 {
114 {
115 { reinterpret_cast<const void*>(module3_base_address + 0x10), 0 },
116 { reinterpret_cast<const void*>(module1_base_address + 0x20), 1 },
117 { reinterpret_cast<const void*>(module3_base_address + 0x30), 0 }
118 },
119 {
120 { reinterpret_cast<const void*>(module1_base_address + 0x10), 1 },
121 { reinterpret_cast<const void*>(module3_base_address + 0x20), 0 },
122 { reinterpret_cast<const void*>(module1_base_address + 0x30), 1 }
123 }
124 }
125 };
126
127 base::TimeDelta profile_durations[2] = {
128 base::TimeDelta::FromMilliseconds(100),
129 base::TimeDelta::FromMilliseconds(200)
130 };
131
132 base::TimeDelta profile_sampling_periods[2] = {
133 base::TimeDelta::FromMilliseconds(10),
134 base::TimeDelta::FromMilliseconds(20)
135 };
136
137 std::vector<Profile> profiles;
138 for (size_t i = 0; i < arraysize(profile_sample_frames); ++i) {
139 Profile profile;
140 profile.modules.insert(
141 profile.modules.end(), &profile_modules[i][0],
142 &profile_modules[i][0] + arraysize(profile_modules[i]));
143
144 for (size_t j = 0; j < arraysize(profile_sample_frames[i]); ++j) {
145 profile.samples.push_back(Sample());
146 Sample& sample = profile.samples.back();
147 sample.insert(sample.end(), &profile_sample_frames[i][j][0],
148 &profile_sample_frames[i][j][0] +
149 arraysize(profile_sample_frames[i][j]));
150 }
151
152 profile.profile_duration = profile_durations[i];
153 profile.sampling_period = profile_sampling_periods[i];
154 profile.preserve_sample_ordering = false;
155
156 profiles.push_back(profile);
157 }
158
159 CallStackProfileMetricsProvider provider;
160 provider.SetSourceProfilesForTesting(profiles);
161 metrics::ChromeUserMetricsExtension uma_proto;
162 provider.ProvideGeneralMetrics(&uma_proto);
163
164 ASSERT_EQ(static_cast<int>(arraysize(profile_sample_frames)),
165 uma_proto.sampled_profile().size());
166 for (size_t i = 0; i < arraysize(profile_sample_frames); ++i) {
167 SCOPED_TRACE("profile " + base::IntToString(i));
168 const metrics::SampledProfile& sampled_profile =
169 uma_proto.sampled_profile().Get(i);
170 ASSERT_TRUE(sampled_profile.has_call_stack_profile());
171 const metrics::CallStackProfile& call_stack_profile =
172 sampled_profile.call_stack_profile();
173
174 ASSERT_EQ(static_cast<int>(arraysize(profile_sample_frames[i])),
175 call_stack_profile.sample().size());
176 for (size_t j = 0; j < arraysize(profile_sample_frames[i]); ++j) {
177 SCOPED_TRACE("sample " + base::IntToString(j));
178 const metrics::CallStackProfile::Sample& proto_sample =
179 call_stack_profile.sample().Get(j);
180 ASSERT_EQ(static_cast<int>(arraysize(profile_sample_frames[i][j])),
181 proto_sample.entry().size());
182 ASSERT_TRUE(proto_sample.has_count());
183 EXPECT_EQ(1u, proto_sample.count());
184 for (size_t k = 0; k < arraysize(profile_sample_frames[i][j]); ++k) {
185 SCOPED_TRACE("frame " + base::IntToString(k));
186 const metrics::CallStackEntry& entry = proto_sample.entry().Get(k);
187 ASSERT_TRUE(entry.has_address());
188 const char* instruction_pointer = reinterpret_cast<const char*>(
189 profile_sample_frames[i][j][k].instruction_pointer);
190 const char* module_base_address = reinterpret_cast<const char*>(
191 profile_modules[i][profile_sample_frames[i][j][k].module_index]
192 .base_address);
193 EXPECT_EQ(static_cast<uint64>(instruction_pointer -
194 module_base_address), entry.address());
195 ASSERT_TRUE(entry.has_module_id_index());
196 EXPECT_EQ(profile_sample_frames[i][j][k].module_index,
197 entry.module_id_index());
198 }
199 }
200
201 ASSERT_EQ(static_cast<int>(arraysize(profile_modules[i])),
202 call_stack_profile.module_id().size());
203 for (size_t j = 0; j < arraysize(profile_modules[i]); ++j) {
204 SCOPED_TRACE("module " + base::IntToString(j));
205 const metrics::ModuleIdentifier& module_identifier =
206 call_stack_profile.module_id().Get(j);
207 ASSERT_TRUE(module_identifier.has_build_id());
208 EXPECT_EQ(profile_modules[i][j].id, module_identifier.build_id());
209 ASSERT_TRUE(module_identifier.has_name_md5_prefix());
210 EXPECT_EQ(profile_expected_name_md5_prefixes[i][j],
211 module_identifier.name_md5_prefix());
212 }
213
214 ASSERT_TRUE(call_stack_profile.has_profile_duration_ms());
215 EXPECT_EQ(profile_durations[i].InMilliseconds(),
216 call_stack_profile.profile_duration_ms());
217 ASSERT_TRUE(call_stack_profile.has_sampling_period_ms());
218 EXPECT_EQ(profile_sampling_periods[i].InMilliseconds(),
219 call_stack_profile.sampling_period_ms());
220 }
221 }
222
223 // Checks that all duplicate samples are collapsed with
224 // preserve_sample_ordering = false.
225 TEST(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
226 const uintptr_t module_base_address = 0x1000;
227
228 const Module modules[] = {
229 {
230 reinterpret_cast<const void*>(module_base_address),
231 "ABCD",
232 #if defined(OS_WIN)
233 base::FilePath(L"c:\\some\\path\\to\\chrome.exe")
234 #else
235 base::FilePath("/some/path/to/chrome")
236 #endif
237 }
238 };
239
240 // Duplicate samples in slots 0, 2, and 3.
241 const Frame sample_frames[][1] = {
242 { { reinterpret_cast<const void*>(module_base_address + 0x10), 0 }, },
243 { { reinterpret_cast<const void*>(module_base_address + 0x20), 0 }, },
244 { { reinterpret_cast<const void*>(module_base_address + 0x10), 0 }, },
245 { { reinterpret_cast<const void*>(module_base_address + 0x10), 0 }, },
246 };
247
248 Profile profile;
249 profile.modules.insert(profile.modules.end(), &modules[0],
250 &modules[0] + arraysize(modules));
251
252 for (size_t i = 0; i < arraysize(sample_frames); ++i) {
253 profile.samples.push_back(Sample());
254 Sample& sample = profile.samples.back();
255 sample.insert(sample.end(), &sample_frames[i][0],
256 &sample_frames[i][0] + arraysize(sample_frames[i]));
257 }
258
259 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
260 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
261 profile.preserve_sample_ordering = false;
262
263 CallStackProfileMetricsProvider provider;
264 provider.SetSourceProfilesForTesting(std::vector<Profile>(1, profile));
265 metrics::ChromeUserMetricsExtension uma_proto;
266 provider.ProvideGeneralMetrics(&uma_proto);
267
268 ASSERT_EQ(1, uma_proto.sampled_profile().size());
269 const metrics::SampledProfile& sampled_profile =
270 uma_proto.sampled_profile().Get(0);
271 ASSERT_TRUE(sampled_profile.has_call_stack_profile());
272 const metrics::CallStackProfile& call_stack_profile =
273 sampled_profile.call_stack_profile();
274
275 ASSERT_EQ(2, call_stack_profile.sample().size());
276 for (int i = 0; i < 2; ++i) {
277 SCOPED_TRACE("sample " + base::IntToString(i));
278 const metrics::CallStackProfile::Sample& proto_sample =
279 call_stack_profile.sample().Get(i);
280 ASSERT_EQ(static_cast<int>(arraysize(sample_frames[i])),
281 proto_sample.entry().size());
282 ASSERT_TRUE(proto_sample.has_count());
283 EXPECT_EQ(i == 0 ? 3u : 1u, proto_sample.count());
284 for (size_t j = 0; j < arraysize(sample_frames[i]); ++j) {
285 SCOPED_TRACE("frame " + base::IntToString(j));
286 const metrics::CallStackEntry& entry = proto_sample.entry().Get(j);
287 ASSERT_TRUE(entry.has_address());
288 const char* instruction_pointer = reinterpret_cast<const char*>(
289 sample_frames[i][j].instruction_pointer);
290 const char* module_base_address = reinterpret_cast<const char*>(
291 modules[sample_frames[i][j].module_index].base_address);
292 EXPECT_EQ(static_cast<uint64>(instruction_pointer - module_base_address),
293 entry.address());
294 ASSERT_TRUE(entry.has_module_id_index());
295 EXPECT_EQ(sample_frames[i][j].module_index, entry.module_id_index());
296 }
297 }
298 }
299
300 // Checks that only contiguous duplicate samples are collapsed with
301 // preserve_sample_ordering = true.
302 TEST(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) {
303 const uintptr_t module_base_address = 0x1000;
304
305 const Module modules[] = {
306 {
307 reinterpret_cast<const void*>(module_base_address),
308 "ABCD",
309 #if defined(OS_WIN)
310 base::FilePath(L"c:\\some\\path\\to\\chrome.exe")
311 #else
312 base::FilePath("/some/path/to/chrome")
313 #endif
314 }
315 };
316
317 // Duplicate samples in slots 0, 2, and 3.
318 const Frame sample_frames[][1] = {
319 { { reinterpret_cast<const void*>(module_base_address + 0x10), 0 }, },
320 { { reinterpret_cast<const void*>(module_base_address + 0x20), 0 }, },
321 { { reinterpret_cast<const void*>(module_base_address + 0x10), 0 }, },
322 { { reinterpret_cast<const void*>(module_base_address + 0x10), 0 }, }
323 };
324
325 Profile profile;
326 profile.modules.insert(profile.modules.end(), &modules[0],
327 &modules[0] + arraysize(modules));
328
329 for (size_t i = 0; i < arraysize(sample_frames); ++i) {
330 profile.samples.push_back(Sample());
331 Sample& sample = profile.samples.back();
332 sample.insert(sample.end(), &sample_frames[i][0],
333 &sample_frames[i][0] + arraysize(sample_frames[i]));
334 }
335
336 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
337 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
338 profile.preserve_sample_ordering = true;
339
340 CallStackProfileMetricsProvider provider;
341 provider.SetSourceProfilesForTesting(std::vector<Profile>(1, profile));
342 metrics::ChromeUserMetricsExtension uma_proto;
343 provider.ProvideGeneralMetrics(&uma_proto);
344
345 ASSERT_EQ(1, uma_proto.sampled_profile().size());
346 const metrics::SampledProfile& sampled_profile =
347 uma_proto.sampled_profile().Get(0);
348 ASSERT_TRUE(sampled_profile.has_call_stack_profile());
349 const metrics::CallStackProfile& call_stack_profile =
350 sampled_profile.call_stack_profile();
351
352 ASSERT_EQ(3, call_stack_profile.sample().size());
353 for (int i = 0; i < 3; ++i) {
354 SCOPED_TRACE("sample " + base::IntToString(i));
355 const metrics::CallStackProfile::Sample& proto_sample =
356 call_stack_profile.sample().Get(i);
357 ASSERT_EQ(static_cast<int>(arraysize(sample_frames[i])),
358 proto_sample.entry().size());
359 ASSERT_TRUE(proto_sample.has_count());
360 EXPECT_EQ(i == 2 ? 2u : 1u, proto_sample.count());
361 for (size_t j = 0; j < arraysize(sample_frames[i]); ++j) {
362 SCOPED_TRACE("frame " + base::IntToString(j));
363 const metrics::CallStackEntry& entry = proto_sample.entry().Get(j);
364 ASSERT_TRUE(entry.has_address());
365 const char* instruction_pointer = reinterpret_cast<const char*>(
366 sample_frames[i][j].instruction_pointer);
367 const char* module_base_address = reinterpret_cast<const char*>(
368 modules[sample_frames[i][j].module_index].base_address);
369 EXPECT_EQ(static_cast<uint64>(instruction_pointer - module_base_address),
370 entry.address());
371 ASSERT_TRUE(entry.has_module_id_index());
372 EXPECT_EQ(sample_frames[i][j].module_index, entry.module_id_index());
373 }
374 }
375 }
376
377
378 // Checks that unknown modules produce an empty CallStackEntry.
379 TEST(CallStackProfileMetricsProviderTest, UnknownModule) {
380 // -1 indicates an unknown module.
381 const Frame frame = { reinterpret_cast<const void*>(0x1000), -1 };
382
383 Profile profile;
384
385 profile.samples.push_back(Sample(1, frame));
386
387 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
388 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
389 profile.preserve_sample_ordering = false;
390
391 CallStackProfileMetricsProvider provider;
392 provider.SetSourceProfilesForTesting(std::vector<Profile>(1, profile));
393 metrics::ChromeUserMetricsExtension uma_proto;
394 provider.ProvideGeneralMetrics(&uma_proto);
395
396 ASSERT_EQ(1, uma_proto.sampled_profile().size());
397 const metrics::SampledProfile& sampled_profile =
398 uma_proto.sampled_profile().Get(0);
399 ASSERT_TRUE(sampled_profile.has_call_stack_profile());
400 const metrics::CallStackProfile& call_stack_profile =
401 sampled_profile.call_stack_profile();
402
403 ASSERT_EQ(1u, call_stack_profile.sample().size());
404 const metrics::CallStackProfile::Sample& proto_sample =
405 call_stack_profile.sample().Get(0);
406 ASSERT_EQ(1u, proto_sample.entry().size());
407 ASSERT_TRUE(proto_sample.has_count());
408 EXPECT_EQ(1u, proto_sample.count());
409 const metrics::CallStackEntry& entry = proto_sample.entry().Get(0);
410 EXPECT_FALSE(entry.has_address());
411 EXPECT_FALSE(entry.has_module_id_index());
412 }
413
414 } // namespace metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698