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

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: fix multiline comment 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 Module(
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 Module(
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 Module(
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 Module( // 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 // Represents two stack samples for each of two profiles, where each stack
100 // contains three frames. Each frame contains an instruction pointer and a
101 // module index corresponding to the module for the profile in
102 // profile_modules.
103 //
104 // So, the first stack sample below has its top frame in module 0 at an offset
105 // of 0x10 from the module's base address, the next-to-top frame in module 1
106 // at an offset of 0x20 from the module's base address, and the bottom frame
107 // in module 0 at an offset of 0x30 from the module's base address
108 const Frame profile_sample_frames[][2][3] = {
109 {
110 {
111 Frame(reinterpret_cast<const void*>(module1_base_address + 0x10), 0),
112 Frame(reinterpret_cast<const void*>(module2_base_address + 0x20), 1),
113 Frame(reinterpret_cast<const void*>(module1_base_address + 0x30), 0)
114 },
115 {
116 Frame(reinterpret_cast<const void*>(module2_base_address + 0x10), 1),
117 Frame(reinterpret_cast<const void*>(module1_base_address + 0x20), 0),
118 Frame(reinterpret_cast<const void*>(module2_base_address + 0x30), 1)
119 }
120 },
121 {
122 {
123 Frame(reinterpret_cast<const void*>(module3_base_address + 0x10), 0),
124 Frame(reinterpret_cast<const void*>(module1_base_address + 0x20), 1),
125 Frame(reinterpret_cast<const void*>(module3_base_address + 0x30), 0)
126 },
127 {
128 Frame(reinterpret_cast<const void*>(module1_base_address + 0x10), 1),
129 Frame(reinterpret_cast<const void*>(module3_base_address + 0x20), 0),
130 Frame(reinterpret_cast<const void*>(module1_base_address + 0x30), 1)
131 }
132 }
133 };
134
135 base::TimeDelta profile_durations[2] = {
136 base::TimeDelta::FromMilliseconds(100),
137 base::TimeDelta::FromMilliseconds(200)
138 };
139
140 base::TimeDelta profile_sampling_periods[2] = {
141 base::TimeDelta::FromMilliseconds(10),
142 base::TimeDelta::FromMilliseconds(20)
143 };
144
145 std::vector<Profile> profiles;
146 for (size_t i = 0; i < arraysize(profile_sample_frames); ++i) {
147 Profile profile;
148 profile.modules.insert(
149 profile.modules.end(), &profile_modules[i][0],
150 &profile_modules[i][0] + arraysize(profile_modules[i]));
151
152 for (size_t j = 0; j < arraysize(profile_sample_frames[i]); ++j) {
153 profile.samples.push_back(Sample());
154 Sample& sample = profile.samples.back();
155 sample.insert(sample.end(), &profile_sample_frames[i][j][0],
156 &profile_sample_frames[i][j][0] +
157 arraysize(profile_sample_frames[i][j]));
158 }
159
160 profile.profile_duration = profile_durations[i];
161 profile.sampling_period = profile_sampling_periods[i];
162 profile.preserve_sample_ordering = false;
163
164 profiles.push_back(profile);
165 }
166
167 CallStackProfileMetricsProvider provider;
168 provider.SetSourceProfilesForTesting(profiles);
169 ChromeUserMetricsExtension uma_proto;
170 provider.ProvideGeneralMetrics(&uma_proto);
171
172 ASSERT_EQ(static_cast<int>(arraysize(profile_sample_frames)),
173 uma_proto.sampled_profile().size());
174 for (size_t i = 0; i < arraysize(profile_sample_frames); ++i) {
175 SCOPED_TRACE("profile " + base::IntToString(i));
176 const SampledProfile& sampled_profile = uma_proto.sampled_profile().Get(i);
177 ASSERT_TRUE(sampled_profile.has_call_stack_profile());
178 const CallStackProfile& call_stack_profile =
179 sampled_profile.call_stack_profile();
180
181 ASSERT_EQ(static_cast<int>(arraysize(profile_sample_frames[i])),
182 call_stack_profile.sample().size());
183 for (size_t j = 0; j < arraysize(profile_sample_frames[i]); ++j) {
184 SCOPED_TRACE("sample " + base::IntToString(j));
185 const CallStackProfile::Sample& proto_sample =
186 call_stack_profile.sample().Get(j);
187 ASSERT_EQ(static_cast<int>(arraysize(profile_sample_frames[i][j])),
188 proto_sample.entry().size());
189 ASSERT_TRUE(proto_sample.has_count());
190 EXPECT_EQ(1u, proto_sample.count());
191 for (size_t k = 0; k < arraysize(profile_sample_frames[i][j]); ++k) {
192 SCOPED_TRACE("frame " + base::IntToString(k));
193 const CallStackProfile::Entry& entry = proto_sample.entry().Get(k);
194 ASSERT_TRUE(entry.has_address());
195 const char* instruction_pointer = reinterpret_cast<const char*>(
196 profile_sample_frames[i][j][k].instruction_pointer);
197 const char* module_base_address = reinterpret_cast<const char*>(
198 profile_modules[i][profile_sample_frames[i][j][k].module_index]
199 .base_address);
200 EXPECT_EQ(static_cast<uint64>(instruction_pointer -
201 module_base_address), entry.address());
202 ASSERT_TRUE(entry.has_module_id_index());
203 EXPECT_EQ(profile_sample_frames[i][j][k].module_index,
204 entry.module_id_index());
205 }
206 }
207
208 ASSERT_EQ(static_cast<int>(arraysize(profile_modules[i])),
209 call_stack_profile.module_id().size());
210 for (size_t j = 0; j < arraysize(profile_modules[i]); ++j) {
211 SCOPED_TRACE("module " + base::IntToString(j));
212 const CallStackProfile::ModuleIdentifier& module_identifier =
213 call_stack_profile.module_id().Get(j);
214 ASSERT_TRUE(module_identifier.has_build_id());
215 EXPECT_EQ(profile_modules[i][j].id, module_identifier.build_id());
216 ASSERT_TRUE(module_identifier.has_name_md5_prefix());
217 EXPECT_EQ(profile_expected_name_md5_prefixes[i][j],
218 module_identifier.name_md5_prefix());
219 }
220
221 ASSERT_TRUE(call_stack_profile.has_profile_duration_ms());
222 EXPECT_EQ(profile_durations[i].InMilliseconds(),
223 call_stack_profile.profile_duration_ms());
224 ASSERT_TRUE(call_stack_profile.has_sampling_period_ms());
225 EXPECT_EQ(profile_sampling_periods[i].InMilliseconds(),
226 call_stack_profile.sampling_period_ms());
227 }
228 }
229
230 // Checks that all duplicate samples are collapsed with
231 // preserve_sample_ordering = false.
232 TEST(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
233 const uintptr_t module_base_address = 0x1000;
234
235 const Module modules[] = {
236 Module(
237 reinterpret_cast<const void*>(module_base_address),
238 "ABCD",
239 #if defined(OS_WIN)
240 base::FilePath(L"c:\\some\\path\\to\\chrome.exe")
241 #else
242 base::FilePath("/some/path/to/chrome")
243 #endif
244 )
245 };
246
247 // Duplicate samples in slots 0, 2, and 3.
248 const Frame sample_frames[][1] = {
249 { Frame(reinterpret_cast<const void*>(module_base_address + 0x10), 0), },
250 { Frame(reinterpret_cast<const void*>(module_base_address + 0x20), 0), },
251 { Frame(reinterpret_cast<const void*>(module_base_address + 0x10), 0), },
252 { Frame(reinterpret_cast<const void*>(module_base_address + 0x10), 0) }
253 };
254
255 Profile profile;
256 profile.modules.insert(profile.modules.end(), &modules[0],
257 &modules[0] + arraysize(modules));
258
259 for (size_t i = 0; i < arraysize(sample_frames); ++i) {
260 profile.samples.push_back(Sample());
261 Sample& sample = profile.samples.back();
262 sample.insert(sample.end(), &sample_frames[i][0],
263 &sample_frames[i][0] + arraysize(sample_frames[i]));
264 }
265
266 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
267 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
268 profile.preserve_sample_ordering = false;
269
270 CallStackProfileMetricsProvider provider;
271 provider.SetSourceProfilesForTesting(std::vector<Profile>(1, profile));
272 ChromeUserMetricsExtension uma_proto;
273 provider.ProvideGeneralMetrics(&uma_proto);
274
275 ASSERT_EQ(1, uma_proto.sampled_profile().size());
276 const SampledProfile& sampled_profile = uma_proto.sampled_profile().Get(0);
277 ASSERT_TRUE(sampled_profile.has_call_stack_profile());
278 const CallStackProfile& call_stack_profile =
279 sampled_profile.call_stack_profile();
280
281 ASSERT_EQ(2, call_stack_profile.sample().size());
282 for (int i = 0; i < 2; ++i) {
283 SCOPED_TRACE("sample " + base::IntToString(i));
284 const CallStackProfile::Sample& proto_sample =
285 call_stack_profile.sample().Get(i);
286 ASSERT_EQ(static_cast<int>(arraysize(sample_frames[i])),
287 proto_sample.entry().size());
288 ASSERT_TRUE(proto_sample.has_count());
289 EXPECT_EQ(i == 0 ? 3u : 1u, proto_sample.count());
290 for (size_t j = 0; j < arraysize(sample_frames[i]); ++j) {
291 SCOPED_TRACE("frame " + base::IntToString(j));
292 const CallStackProfile::Entry& entry = proto_sample.entry().Get(j);
293 ASSERT_TRUE(entry.has_address());
294 const char* instruction_pointer = reinterpret_cast<const char*>(
295 sample_frames[i][j].instruction_pointer);
296 const char* module_base_address = reinterpret_cast<const char*>(
297 modules[sample_frames[i][j].module_index].base_address);
298 EXPECT_EQ(static_cast<uint64>(instruction_pointer - module_base_address),
299 entry.address());
300 ASSERT_TRUE(entry.has_module_id_index());
301 EXPECT_EQ(sample_frames[i][j].module_index, entry.module_id_index());
302 }
303 }
304 }
305
306 // Checks that only contiguous duplicate samples are collapsed with
307 // preserve_sample_ordering = true.
308 TEST(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) {
309 const uintptr_t module_base_address = 0x1000;
310
311 const Module modules[] = {
312 Module(
313 reinterpret_cast<const void*>(module_base_address),
314 "ABCD",
315 #if defined(OS_WIN)
316 base::FilePath(L"c:\\some\\path\\to\\chrome.exe")
317 #else
318 base::FilePath("/some/path/to/chrome")
319 #endif
320 )
321 };
322
323 // Duplicate samples in slots 0, 2, and 3.
324 const Frame sample_frames[][1] = {
325 { Frame(reinterpret_cast<const void*>(module_base_address + 0x10), 0), },
326 { Frame(reinterpret_cast<const void*>(module_base_address + 0x20), 0), },
327 { Frame(reinterpret_cast<const void*>(module_base_address + 0x10), 0), },
328 { Frame(reinterpret_cast<const void*>(module_base_address + 0x10), 0) }
329 };
330
331 Profile profile;
332 profile.modules.insert(profile.modules.end(), &modules[0],
333 &modules[0] + arraysize(modules));
334
335 for (size_t i = 0; i < arraysize(sample_frames); ++i) {
336 profile.samples.push_back(Sample());
337 Sample& sample = profile.samples.back();
338 sample.insert(sample.end(), &sample_frames[i][0],
339 &sample_frames[i][0] + arraysize(sample_frames[i]));
340 }
341
342 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
343 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
344 profile.preserve_sample_ordering = true;
345
346 CallStackProfileMetricsProvider provider;
347 provider.SetSourceProfilesForTesting(std::vector<Profile>(1, profile));
348 ChromeUserMetricsExtension uma_proto;
349 provider.ProvideGeneralMetrics(&uma_proto);
350
351 ASSERT_EQ(1, uma_proto.sampled_profile().size());
352 const SampledProfile& sampled_profile = uma_proto.sampled_profile().Get(0);
353 ASSERT_TRUE(sampled_profile.has_call_stack_profile());
354 const CallStackProfile& call_stack_profile =
355 sampled_profile.call_stack_profile();
356
357 ASSERT_EQ(3, call_stack_profile.sample().size());
358 for (int i = 0; i < 3; ++i) {
359 SCOPED_TRACE("sample " + base::IntToString(i));
360 const CallStackProfile::Sample& proto_sample =
361 call_stack_profile.sample().Get(i);
362 ASSERT_EQ(static_cast<int>(arraysize(sample_frames[i])),
363 proto_sample.entry().size());
364 ASSERT_TRUE(proto_sample.has_count());
365 EXPECT_EQ(i == 2 ? 2u : 1u, proto_sample.count());
366 for (size_t j = 0; j < arraysize(sample_frames[i]); ++j) {
367 SCOPED_TRACE("frame " + base::IntToString(j));
368 const CallStackProfile::Entry& entry = proto_sample.entry().Get(j);
369 ASSERT_TRUE(entry.has_address());
370 const char* instruction_pointer = reinterpret_cast<const char*>(
371 sample_frames[i][j].instruction_pointer);
372 const char* module_base_address = reinterpret_cast<const char*>(
373 modules[sample_frames[i][j].module_index].base_address);
374 EXPECT_EQ(static_cast<uint64>(instruction_pointer - module_base_address),
375 entry.address());
376 ASSERT_TRUE(entry.has_module_id_index());
377 EXPECT_EQ(sample_frames[i][j].module_index, entry.module_id_index());
378 }
379 }
380 }
381
382
383 // Checks that unknown modules produce an empty Entry.
384 TEST(CallStackProfileMetricsProviderTest, UnknownModule) {
385 // -1 indicates an unknown module.
386 const Frame frame(reinterpret_cast<const void*>(0x1000), -1);
387
388 Profile profile;
389
390 profile.samples.push_back(Sample(1, frame));
391
392 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
393 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
394 profile.preserve_sample_ordering = false;
395
396 CallStackProfileMetricsProvider provider;
397 provider.SetSourceProfilesForTesting(std::vector<Profile>(1, profile));
398 ChromeUserMetricsExtension uma_proto;
399 provider.ProvideGeneralMetrics(&uma_proto);
400
401 ASSERT_EQ(1, uma_proto.sampled_profile().size());
402 const SampledProfile& sampled_profile = uma_proto.sampled_profile().Get(0);
403 ASSERT_TRUE(sampled_profile.has_call_stack_profile());
404 const CallStackProfile& call_stack_profile =
405 sampled_profile.call_stack_profile();
406
407 ASSERT_EQ(1, call_stack_profile.sample().size());
408 const CallStackProfile::Sample& proto_sample =
409 call_stack_profile.sample().Get(0);
410 ASSERT_EQ(1, proto_sample.entry().size());
411 ASSERT_TRUE(proto_sample.has_count());
412 EXPECT_EQ(1u, proto_sample.count());
413 const CallStackProfile::Entry& entry = proto_sample.entry().Get(0);
414 EXPECT_FALSE(entry.has_address());
415 EXPECT_FALSE(entry.has_module_id_index());
416 }
417
418 } // namespace metrics
OLDNEW
« no previous file with comments | « components/metrics/call_stack_profile_metrics_provider.cc ('k') | components/metrics/proto/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698