blob: 2eece46230eb565fd17c815980384457fc383ee3 [file] [log] [blame]
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001// Copyright 2010 the V8 project authors. All rights reserved.
ulan@chromium.org750145a2013-03-07 15:14:13 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000027//
28// Tests of profiles generator and utilities.
29
30#include "v8.h"
31#include "cpu-profiler-inl.h"
32#include "cctest.h"
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000033#include "utils.h"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000034#include "../include/v8-profiler.h"
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000035
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000036using i::CodeEntry;
lrn@chromium.org25156de2010-04-06 13:10:27 +000037using i::CpuProfile;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +000038using i::CpuProfiler;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000039using i::CpuProfilesCollection;
40using i::ProfileGenerator;
41using i::ProfileNode;
42using i::ProfilerEventsProcessor;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000043using i::ScopedVector;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000044using i::TokenEnumerator;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000045using i::Vector;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000046
47
48TEST(StartStop) {
49 CpuProfilesCollection profiles;
50 ProfileGenerator generator(&profiles);
ulan@chromium.org750145a2013-03-07 15:14:13 +000051 ProfilerEventsProcessor processor(&generator);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000052 processor.Start();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000053 processor.Stop();
54 processor.Join();
55}
56
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000057static inline i::Address ToAddress(int n) {
58 return reinterpret_cast<i::Address>(n);
59}
60
mmassi@chromium.org49a44672012-12-04 13:52:03 +000061static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
62 i::Address frame1,
63 i::Address frame2 = NULL,
64 i::Address frame3 = NULL) {
65 i::TickSample* sample = proc->TickSampleEvent();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000066 sample->pc = frame1;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000067 sample->frames_count = 0;
68 if (frame2 != NULL) {
69 sample->stack[0] = frame2;
70 sample->frames_count = 1;
71 }
72 if (frame3 != NULL) {
73 sample->stack[1] = frame3;
74 sample->frames_count = 2;
75 }
76}
77
ager@chromium.org357bf652010-04-12 11:30:10 +000078namespace {
79
80class TestSetup {
81 public:
82 TestSetup()
83 : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
84 i::FLAG_prof_browser_mode = false;
85 }
86
87 ~TestSetup() {
88 i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
89 }
90
91 private:
92 bool old_flag_prof_browser_mode_;
93};
94
95} // namespace
96
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000097TEST(CodeEvents) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000098 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +000099 i::Isolate* isolate = i::Isolate::Current();
100 i::Heap* heap = isolate->heap();
101 i::Factory* factory = isolate->factory();
ager@chromium.org357bf652010-04-12 11:30:10 +0000102 TestSetup test_setup;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000103 CpuProfilesCollection profiles;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000104 profiles.StartProfiling("", 1, false);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000105 ProfileGenerator generator(&profiles);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000106 ProfilerEventsProcessor processor(&generator);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000107 processor.Start();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000108
109 // Enqueue code creation events.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000110 i::HandleScope scope(isolate);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000111 const char* aaa_str = "aaa";
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000112 i::Handle<i::String> aaa_name = factory->NewStringFromAscii(
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000113 i::Vector<const char>(aaa_str, i::StrLength(aaa_str)));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000114 processor.CodeCreateEvent(i::Logger::FUNCTION_TAG,
115 *aaa_name,
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000116 heap->empty_string(),
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000117 0,
118 ToAddress(0x1000),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000119 0x100,
120 ToAddress(0x10000));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000121 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
122 "bbb",
123 ToAddress(0x1200),
124 0x80);
125 processor.CodeCreateEvent(i::Logger::STUB_TAG, 5, ToAddress(0x1300), 0x10);
126 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
127 "ddd",
128 ToAddress(0x1400),
129 0x80);
130 processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
131 processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000132 processor.CodeCreateEvent(i::Logger::STUB_TAG, 4, ToAddress(0x1605), 0x10);
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000133 // Enqueue a tick event to enable code events processing.
134 EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000135
136 processor.Stop();
137 processor.Join();
138
139 // Check the state of profile generator.
140 CodeEntry* entry1 = generator.code_map()->FindEntry(ToAddress(0x1000));
141 CHECK_NE(NULL, entry1);
142 CHECK_EQ(aaa_str, entry1->name());
143 CodeEntry* entry2 = generator.code_map()->FindEntry(ToAddress(0x1200));
144 CHECK_NE(NULL, entry2);
145 CHECK_EQ("bbb", entry2->name());
146 CodeEntry* entry3 = generator.code_map()->FindEntry(ToAddress(0x1300));
147 CHECK_NE(NULL, entry3);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000148 CHECK_EQ("5", entry3->name());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000149 CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1400)));
150 CodeEntry* entry4 = generator.code_map()->FindEntry(ToAddress(0x1500));
151 CHECK_NE(NULL, entry4);
152 CHECK_EQ("ddd", entry4->name());
153 CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1600)));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000154}
155
156
157template<typename T>
158static int CompareProfileNodes(const T* p1, const T* p2) {
159 return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
160}
161
162TEST(TickEvents) {
ager@chromium.org357bf652010-04-12 11:30:10 +0000163 TestSetup test_setup;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000164 CpuProfilesCollection profiles;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000165 profiles.StartProfiling("", 1, false);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000166 ProfileGenerator generator(&profiles);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000167 ProfilerEventsProcessor processor(&generator);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000168 processor.Start();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000169
170 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
171 "bbb",
172 ToAddress(0x1200),
173 0x80);
174 processor.CodeCreateEvent(i::Logger::STUB_TAG, 5, ToAddress(0x1300), 0x10);
175 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
176 "ddd",
177 ToAddress(0x1400),
178 0x80);
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000179 EnqueueTickSampleEvent(&processor, ToAddress(0x1210));
180 EnqueueTickSampleEvent(&processor, ToAddress(0x1305), ToAddress(0x1220));
181 EnqueueTickSampleEvent(&processor,
182 ToAddress(0x1404),
183 ToAddress(0x1305),
184 ToAddress(0x1230));
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000185
186 processor.Stop();
187 processor.Join();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000188 CpuProfile* profile =
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000189 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000190 CHECK_NE(NULL, profile);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000191
192 // Check call trees.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000193 const i::List<ProfileNode*>* top_down_root_children =
194 profile->top_down()->root()->children();
195 CHECK_EQ(1, top_down_root_children->length());
196 CHECK_EQ("bbb", top_down_root_children->last()->entry()->name());
197 const i::List<ProfileNode*>* top_down_bbb_children =
198 top_down_root_children->last()->children();
199 CHECK_EQ(1, top_down_bbb_children->length());
200 CHECK_EQ("5", top_down_bbb_children->last()->entry()->name());
201 const i::List<ProfileNode*>* top_down_stub_children =
202 top_down_bbb_children->last()->children();
203 CHECK_EQ(1, top_down_stub_children->length());
204 CHECK_EQ("ddd", top_down_stub_children->last()->entry()->name());
205 const i::List<ProfileNode*>* top_down_ddd_children =
206 top_down_stub_children->last()->children();
207 CHECK_EQ(0, top_down_ddd_children->length());
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000208}
lrn@chromium.org25156de2010-04-06 13:10:27 +0000209
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000210
211// http://crbug/51594
212// This test must not crash.
213TEST(CrashIfStoppingLastNonExistentProfile) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000214 CcTest::InitializeVM();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000215 TestSetup test_setup;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000216 CpuProfiler* profiler = i::Isolate::Current()->cpu_profiler();
217 profiler->StartProfiling("1");
218 profiler->StopProfiling("2");
219 profiler->StartProfiling("1");
220 profiler->StopProfiling("");
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000221}
222
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000223
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000224// http://code.google.com/p/v8/issues/detail?id=1398
225// Long stacks (exceeding max frames limit) must not be erased.
226TEST(Issue1398) {
227 TestSetup test_setup;
228 CpuProfilesCollection profiles;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000229 profiles.StartProfiling("", 1, false);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000230 ProfileGenerator generator(&profiles);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000231 ProfilerEventsProcessor processor(&generator);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000232 processor.Start();
233
234 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
235 "bbb",
236 ToAddress(0x1200),
237 0x80);
238
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000239 i::TickSample* sample = processor.TickSampleEvent();
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000240 sample->pc = ToAddress(0x1200);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000241 sample->frames_count = i::TickSample::kMaxFramesCount;
242 for (int i = 0; i < sample->frames_count; ++i) {
243 sample->stack[i] = ToAddress(0x1200);
244 }
245
246 processor.Stop();
247 processor.Join();
248 CpuProfile* profile =
249 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
250 CHECK_NE(NULL, profile);
251
252 int actual_depth = 0;
253 const ProfileNode* node = profile->top_down()->root();
254 while (node->children()->length() > 0) {
255 node = node->children()->last();
256 ++actual_depth;
257 }
258
259 CHECK_EQ(1 + i::TickSample::kMaxFramesCount, actual_depth); // +1 for PC.
260}
261
262
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000263TEST(DeleteAllCpuProfiles) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000264 CcTest::InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000265 TestSetup test_setup;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000266 CpuProfiler* profiler = i::Isolate::Current()->cpu_profiler();
267 CHECK_EQ(0, profiler->GetProfilesCount());
268 profiler->DeleteAllProfiles();
269 CHECK_EQ(0, profiler->GetProfilesCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000270
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000271 profiler->StartProfiling("1");
272 profiler->StopProfiling("1");
273 CHECK_EQ(1, profiler->GetProfilesCount());
274 profiler->DeleteAllProfiles();
275 CHECK_EQ(0, profiler->GetProfilesCount());
276 profiler->StartProfiling("1");
277 profiler->StartProfiling("2");
278 profiler->StopProfiling("2");
279 profiler->StopProfiling("1");
280 CHECK_EQ(2, profiler->GetProfilesCount());
281 profiler->DeleteAllProfiles();
282 CHECK_EQ(0, profiler->GetProfilesCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000283
284 // Test profiling cancellation by the 'delete' command.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000285 profiler->StartProfiling("1");
286 profiler->StartProfiling("2");
287 CHECK_EQ(0, profiler->GetProfilesCount());
288 profiler->DeleteAllProfiles();
289 CHECK_EQ(0, profiler->GetProfilesCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000290}
291
292
293TEST(DeleteCpuProfile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000294 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000295 v8::HandleScope scope(env->GetIsolate());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000296 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000297
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000298 CHECK_EQ(0, cpu_profiler->GetProfileCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000299 v8::Local<v8::String> name1 = v8::String::New("1");
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000300 cpu_profiler->StartCpuProfiling(name1);
301 const v8::CpuProfile* p1 = cpu_profiler->StopCpuProfiling(name1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 CHECK_NE(NULL, p1);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000303 CHECK_EQ(1, cpu_profiler->GetProfileCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 unsigned uid1 = p1->GetUid();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000305 CHECK_EQ(p1, cpu_profiler->FindCpuProfile(uid1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000306 const_cast<v8::CpuProfile*>(p1)->Delete();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000307 CHECK_EQ(0, cpu_profiler->GetProfileCount());
308 CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000309
310 v8::Local<v8::String> name2 = v8::String::New("2");
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000311 cpu_profiler->StartCpuProfiling(name2);
312 const v8::CpuProfile* p2 = cpu_profiler->StopCpuProfiling(name2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000313 CHECK_NE(NULL, p2);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000314 CHECK_EQ(1, cpu_profiler->GetProfileCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 unsigned uid2 = p2->GetUid();
316 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000317 CHECK_EQ(p2, cpu_profiler->FindCpuProfile(uid2));
318 CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000319 v8::Local<v8::String> name3 = v8::String::New("3");
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000320 cpu_profiler->StartCpuProfiling(name3);
321 const v8::CpuProfile* p3 = cpu_profiler->StopCpuProfiling(name3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000322 CHECK_NE(NULL, p3);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000323 CHECK_EQ(2, cpu_profiler->GetProfileCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 unsigned uid3 = p3->GetUid();
325 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000326 CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3));
327 CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000328 const_cast<v8::CpuProfile*>(p2)->Delete();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000329 CHECK_EQ(1, cpu_profiler->GetProfileCount());
330 CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid2));
331 CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 const_cast<v8::CpuProfile*>(p3)->Delete();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000333 CHECK_EQ(0, cpu_profiler->GetProfileCount());
334 CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid3));
335 CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid2));
336 CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000337}
338
339
340TEST(DeleteCpuProfileDifferentTokens) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000341 LocalContext env;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000342 v8::HandleScope scope(env->GetIsolate());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000343 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000344
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000345 CHECK_EQ(0, cpu_profiler->GetProfileCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000346 v8::Local<v8::String> name1 = v8::String::New("1");
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000347 cpu_profiler->StartCpuProfiling(name1);
348 const v8::CpuProfile* p1 = cpu_profiler->StopCpuProfiling(name1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000349 CHECK_NE(NULL, p1);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000350 CHECK_EQ(1, cpu_profiler->GetProfileCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 unsigned uid1 = p1->GetUid();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000352 CHECK_EQ(p1, cpu_profiler->FindCpuProfile(uid1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000353 v8::Local<v8::String> token1 = v8::String::New("token1");
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000354 const v8::CpuProfile* p1_t1 = cpu_profiler->FindCpuProfile(uid1, token1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000355 CHECK_NE(NULL, p1_t1);
356 CHECK_NE(p1, p1_t1);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000357 CHECK_EQ(1, cpu_profiler->GetProfileCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000358 const_cast<v8::CpuProfile*>(p1)->Delete();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000359 CHECK_EQ(0, cpu_profiler->GetProfileCount());
360 CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1));
361 CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1, token1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 const_cast<v8::CpuProfile*>(p1_t1)->Delete();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000363 CHECK_EQ(0, cpu_profiler->GetProfileCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000364
365 v8::Local<v8::String> name2 = v8::String::New("2");
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000366 cpu_profiler->StartCpuProfiling(name2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 v8::Local<v8::String> token2 = v8::String::New("token2");
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000368 const v8::CpuProfile* p2_t2 = cpu_profiler->StopCpuProfiling(name2, token2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000369 CHECK_NE(NULL, p2_t2);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000370 CHECK_EQ(1, cpu_profiler->GetProfileCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000371 unsigned uid2 = p2_t2->GetUid();
372 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000373 const v8::CpuProfile* p2 = cpu_profiler->FindCpuProfile(uid2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000374 CHECK_NE(p2_t2, p2);
375 v8::Local<v8::String> name3 = v8::String::New("3");
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000376 cpu_profiler->StartCpuProfiling(name3);
377 const v8::CpuProfile* p3 = cpu_profiler->StopCpuProfiling(name3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000378 CHECK_NE(NULL, p3);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000379 CHECK_EQ(2, cpu_profiler->GetProfileCount());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000380 unsigned uid3 = p3->GetUid();
381 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000382 CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000383 const_cast<v8::CpuProfile*>(p2_t2)->Delete();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000384 CHECK_EQ(1, cpu_profiler->GetProfileCount());
385 CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid2));
386 CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000387 const_cast<v8::CpuProfile*>(p2)->Delete();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000388 CHECK_EQ(1, cpu_profiler->GetProfileCount());
389 CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid2));
390 CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000391 const_cast<v8::CpuProfile*>(p3)->Delete();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000392 CHECK_EQ(0, cpu_profiler->GetProfileCount());
393 CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000394}
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000395
396
397static bool ContainsString(v8::Handle<v8::String> string,
398 const Vector<v8::Handle<v8::String> >& vector) {
399 for (int i = 0; i < vector.length(); i++) {
400 if (string->Equals(vector[i]))
401 return true;
402 }
403 return false;
404}
405
406
407static void CheckChildrenNames(const v8::CpuProfileNode* node,
408 const Vector<v8::Handle<v8::String> >& names) {
409 int count = node->GetChildrenCount();
410 for (int i = 0; i < count; i++) {
411 v8::Handle<v8::String> name = node->GetChild(i)->GetFunctionName();
412 CHECK(ContainsString(name, names));
413 // Check that there are no duplicates.
414 for (int j = 0; j < count; j++) {
415 if (j == i) continue;
416 CHECK_NE(name, node->GetChild(j)->GetFunctionName());
417 }
418 }
419}
420
421
422static const v8::CpuProfileNode* FindChild(const v8::CpuProfileNode* node,
423 const char* name) {
424 int count = node->GetChildrenCount();
425 v8::Handle<v8::String> nameHandle = v8::String::New(name);
426 for (int i = 0; i < count; i++) {
427 const v8::CpuProfileNode* child = node->GetChild(i);
428 if (nameHandle->Equals(child->GetFunctionName())) return child;
429 }
430 CHECK(false);
431 return NULL;
432}
433
434
435static void CheckSimpleBranch(const v8::CpuProfileNode* node,
436 const char* names[], int length) {
437 for (int i = 0; i < length; i++) {
438 const char* name = names[i];
439 node = FindChild(node, name);
440 CHECK(node);
441 int expectedChildrenCount = (i == length - 1) ? 0 : 1;
442 CHECK_EQ(expectedChildrenCount, node->GetChildrenCount());
443 }
444}
445
446
447static const char* cpu_profiler_test_source = "function loop(timeout) {\n"
448" this.mmm = 0;\n"
449" var start = Date.now();\n"
450" while (Date.now() - start < timeout) {\n"
451" var n = 100*1000;\n"
452" while(n > 1) {\n"
453" n--;\n"
454" this.mmm += n * n * n;\n"
455" }\n"
456" }\n"
457"}\n"
458"function delay() { try { loop(10); } catch(e) { } }\n"
459"function bar() { delay(); }\n"
460"function baz() { delay(); }\n"
461"function foo() {\n"
462" try {\n"
463" delay();\n"
464" bar();\n"
465" delay();\n"
466" baz();\n"
467" } catch (e) { }\n"
468"}\n"
469"function start(timeout) {\n"
470" var start = Date.now();\n"
471" do {\n"
472" foo();\n"
473" var duration = Date.now() - start;\n"
474" } while (duration < timeout);\n"
475" return duration;\n"
476"}\n";
477
478
479// Check that the profile tree for the script above will look like the
480// following:
481//
482// [Top down]:
483// 1062 0 (root) [-1]
484// 1054 0 start [-1]
485// 1054 1 foo [-1]
486// 265 0 baz [-1]
487// 265 1 delay [-1]
488// 264 264 loop [-1]
489// 525 3 delay [-1]
490// 522 522 loop [-1]
491// 263 0 bar [-1]
492// 263 1 delay [-1]
493// 262 262 loop [-1]
494// 2 2 (program) [-1]
495// 6 6 (garbage collector) [-1]
496TEST(CollectCpuProfile) {
497 LocalContext env;
498 v8::HandleScope scope(env->GetIsolate());
499
500 v8::Script::Compile(v8::String::New(cpu_profiler_test_source))->Run();
501 v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(
502 env->Global()->Get(v8::String::New("start")));
503
504 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
505 v8::Local<v8::String> profile_name = v8::String::New("my_profile");
506
507 cpu_profiler->StartCpuProfiling(profile_name);
508 int32_t profiling_interval_ms = 200;
509#if defined(_WIN32) || defined(_WIN64)
510 // 200ms is not enough on Windows. See
511 // https://code.google.com/p/v8/issues/detail?id=2628
512 profiling_interval_ms = 500;
513#endif
514 v8::Handle<v8::Value> args[] = { v8::Integer::New(profiling_interval_ms) };
515 function->Call(env->Global(), ARRAY_SIZE(args), args);
516 const v8::CpuProfile* profile = cpu_profiler->StopCpuProfiling(profile_name);
517
518 CHECK_NE(NULL, profile);
519 // Dump collected profile to have a better diagnostic in case of failure.
520 reinterpret_cast<i::CpuProfile*>(
521 const_cast<v8::CpuProfile*>(profile))->Print();
522
523 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
524
525 ScopedVector<v8::Handle<v8::String> > names(3);
526 names[0] = v8::String::New(ProfileGenerator::kGarbageCollectorEntryName);
527 names[1] = v8::String::New(ProfileGenerator::kProgramEntryName);
528 names[2] = v8::String::New("start");
529 CheckChildrenNames(root, names);
530
531 const v8::CpuProfileNode* startNode = FindChild(root, "start");
532 CHECK_EQ(1, startNode->GetChildrenCount());
533
534 const v8::CpuProfileNode* fooNode = FindChild(startNode, "foo");
535 CHECK_EQ(3, fooNode->GetChildrenCount());
536
537 const char* barBranch[] = { "bar", "delay", "loop" };
538 CheckSimpleBranch(fooNode, barBranch, ARRAY_SIZE(barBranch));
539 const char* bazBranch[] = { "baz", "delay", "loop" };
540 CheckSimpleBranch(fooNode, bazBranch, ARRAY_SIZE(bazBranch));
541 const char* delayBranch[] = { "delay", "loop" };
542 CheckSimpleBranch(fooNode, delayBranch, ARRAY_SIZE(delayBranch));
543
544 cpu_profiler->DeleteAllCpuProfiles();
545}