blob: e4eceeceab77641b7599424a249196346f5c461a [file] [log] [blame]
Steve Block6ded16b2010-05-10 14:33:55 +01001// Copyright 2010 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +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.
Steve Block6ded16b2010-05-10 14:33:55 +010027//
28// Tests of profiles generator and utilities.
29
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030#include "src/v8.h"
Steve Block6ded16b2010-05-10 14:33:55 +010031
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032#include "include/v8-profiler.h"
33#include "src/base/platform/platform.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034#include "src/base/smart-pointers.h"
35#include "src/deoptimizer.h"
36#include "src/profiler/cpu-profiler-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037#include "src/utils.h"
38#include "test/cctest/cctest.h"
39#include "test/cctest/profiler-extension.h"
Steve Block6ded16b2010-05-10 14:33:55 +010040using i::CodeEntry;
41using i::CpuProfile;
Iain Merrick75681382010-08-19 15:07:18 +010042using i::CpuProfiler;
Steve Block6ded16b2010-05-10 14:33:55 +010043using i::CpuProfilesCollection;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000044using i::Heap;
Steve Block6ded16b2010-05-10 14:33:55 +010045using i::ProfileGenerator;
46using i::ProfileNode;
47using i::ProfilerEventsProcessor;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000048using i::ScopedVector;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049using i::Vector;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000050using v8::base::SmartPointer;
51
52
53// Helper methods
54static v8::Local<v8::Function> GetFunction(v8::Local<v8::Context> env,
55 const char* name) {
56 return v8::Local<v8::Function>::Cast(
57 env->Global()->Get(env, v8_str(name)).ToLocalChecked());
58}
59
60
61static size_t offset(const char* src, const char* substring) {
62 const char* it = strstr(src, substring);
63 CHECK(it);
64 return static_cast<size_t>(it - src);
65}
66
67
68static const char* reason(const i::Deoptimizer::DeoptReason reason) {
69 return i::Deoptimizer::GetDeoptReason(reason);
70}
Steve Block6ded16b2010-05-10 14:33:55 +010071
72
73TEST(StartStop) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000074 i::Isolate* isolate = CcTest::i_isolate();
75 CpuProfilesCollection profiles(isolate->heap());
Steve Block6ded16b2010-05-10 14:33:55 +010076 ProfileGenerator generator(&profiles);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000077 SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
Ben Murdoch097c5b22016-05-18 11:27:45 +010078 &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000079 processor->Start();
80 processor->StopSynchronously();
Steve Block6ded16b2010-05-10 14:33:55 +010081}
82
Steve Block6ded16b2010-05-10 14:33:55 +010083
84static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
85 i::Address frame1,
86 i::Address frame2 = NULL,
87 i::Address frame3 = NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000088 i::TickSample* sample = proc->StartTickSample();
Steve Block6ded16b2010-05-10 14:33:55 +010089 sample->pc = frame1;
Ben Murdoche0cee9b2011-05-25 10:26:03 +010090 sample->tos = frame1;
Steve Block6ded16b2010-05-10 14:33:55 +010091 sample->frames_count = 0;
92 if (frame2 != NULL) {
93 sample->stack[0] = frame2;
94 sample->frames_count = 1;
95 }
96 if (frame3 != NULL) {
97 sample->stack[1] = frame3;
98 sample->frames_count = 2;
99 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 proc->FinishTickSample();
Steve Block6ded16b2010-05-10 14:33:55 +0100101}
102
103namespace {
104
105class TestSetup {
106 public:
107 TestSetup()
108 : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) {
109 i::FLAG_prof_browser_mode = false;
110 }
111
112 ~TestSetup() {
113 i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_;
114 }
115
116 private:
117 bool old_flag_prof_browser_mode_;
118};
119
120} // namespace
121
Ben Murdochda12d292016-06-02 14:46:10 +0100122i::AbstractCode* CreateCode(LocalContext* env) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123 static int counter = 0;
124 i::EmbeddedVector<char, 256> script;
125 i::EmbeddedVector<char, 32> name;
126
127 i::SNPrintF(name, "function_%d", ++counter);
128 const char* name_start = name.start();
129 i::SNPrintF(script,
130 "function %s() {\n"
131 "var counter = 0;\n"
132 "for (var i = 0; i < %d; ++i) counter += i;\n"
133 "return '%s_' + counter;\n"
134 "}\n"
135 "%s();\n", name_start, counter, name_start, name_start);
136 CompileRun(script.start());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137
138 i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(
139 v8::Utils::OpenHandle(*GetFunction(env->local(), name_start)));
Ben Murdochda12d292016-06-02 14:46:10 +0100140 return fun->abstract_code();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141}
142
Steve Block6ded16b2010-05-10 14:33:55 +0100143TEST(CodeEvents) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 CcTest::InitializeVM();
145 LocalContext env;
146 i::Isolate* isolate = CcTest::i_isolate();
147 i::Factory* factory = isolate->factory();
Steve Block6ded16b2010-05-10 14:33:55 +0100148 TestSetup test_setup;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000149
150 i::HandleScope scope(isolate);
151
Ben Murdochda12d292016-06-02 14:46:10 +0100152 i::AbstractCode* aaa_code = CreateCode(&env);
153 i::AbstractCode* comment_code = CreateCode(&env);
154 i::AbstractCode* args5_code = CreateCode(&env);
155 i::AbstractCode* comment2_code = CreateCode(&env);
156 i::AbstractCode* moved_code = CreateCode(&env);
157 i::AbstractCode* args3_code = CreateCode(&env);
158 i::AbstractCode* args4_code = CreateCode(&env);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159
160 CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
161 profiles->StartProfiling("", false);
162 ProfileGenerator generator(profiles);
163 SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
164 &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100)));
165 processor->Start();
166 CpuProfiler profiler(isolate, profiles, &generator, processor.get());
Steve Block6ded16b2010-05-10 14:33:55 +0100167
168 // Enqueue code creation events.
Steve Block6ded16b2010-05-10 14:33:55 +0100169 const char* aaa_str = "aaa";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000170 i::Handle<i::String> aaa_name = factory->NewStringFromAsciiChecked(aaa_str);
171 profiler.CodeCreateEvent(i::Logger::FUNCTION_TAG, aaa_code, *aaa_name);
172 profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment_code, "comment");
173 profiler.CodeCreateEvent(i::Logger::STUB_TAG, args5_code, 5);
174 profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment2_code, "comment2");
Ben Murdochda12d292016-06-02 14:46:10 +0100175 profiler.CodeMoveEvent(comment2_code, moved_code->address());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176 profiler.CodeCreateEvent(i::Logger::STUB_TAG, args3_code, 3);
177 profiler.CodeCreateEvent(i::Logger::STUB_TAG, args4_code, 4);
Steve Block6ded16b2010-05-10 14:33:55 +0100178
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000179 // Enqueue a tick event to enable code events processing.
180 EnqueueTickSampleEvent(processor.get(), aaa_code->address());
181
182 processor->StopSynchronously();
Steve Block6ded16b2010-05-10 14:33:55 +0100183
184 // Check the state of profile generator.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 CodeEntry* aaa = generator.code_map()->FindEntry(aaa_code->address());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000186 CHECK(aaa);
187 CHECK_EQ(0, strcmp(aaa_str, aaa->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188
189 CodeEntry* comment = generator.code_map()->FindEntry(comment_code->address());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190 CHECK(comment);
191 CHECK_EQ(0, strcmp("comment", comment->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192
193 CodeEntry* args5 = generator.code_map()->FindEntry(args5_code->address());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000194 CHECK(args5);
195 CHECK_EQ(0, strcmp("5", args5->name()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197 CHECK(!generator.code_map()->FindEntry(comment2_code->address()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000198
199 CodeEntry* comment2 = generator.code_map()->FindEntry(moved_code->address());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200 CHECK(comment2);
201 CHECK_EQ(0, strcmp("comment2", comment2->name()));
Steve Block6ded16b2010-05-10 14:33:55 +0100202}
203
Steve Block6ded16b2010-05-10 14:33:55 +0100204template<typename T>
205static int CompareProfileNodes(const T* p1, const T* p2) {
206 return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
207}
208
209TEST(TickEvents) {
210 TestSetup test_setup;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000211 LocalContext env;
212 i::Isolate* isolate = CcTest::i_isolate();
213 i::HandleScope scope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100214
Ben Murdochda12d292016-06-02 14:46:10 +0100215 i::AbstractCode* frame1_code = CreateCode(&env);
216 i::AbstractCode* frame2_code = CreateCode(&env);
217 i::AbstractCode* frame3_code = CreateCode(&env);
Steve Block6ded16b2010-05-10 14:33:55 +0100218
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219 CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
220 profiles->StartProfiling("", false);
221 ProfileGenerator generator(profiles);
222 SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
223 &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100)));
224 processor->Start();
225 CpuProfiler profiler(isolate, profiles, &generator, processor.get());
226
227 profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame1_code, "bbb");
228 profiler.CodeCreateEvent(i::Logger::STUB_TAG, frame2_code, 5);
229 profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame3_code, "ddd");
230
231 EnqueueTickSampleEvent(processor.get(), frame1_code->instruction_start());
232 EnqueueTickSampleEvent(
233 processor.get(),
234 frame2_code->instruction_start() + frame2_code->ExecutableSize() / 2,
235 frame1_code->instruction_start() + frame2_code->ExecutableSize() / 2);
236 EnqueueTickSampleEvent(
237 processor.get(),
238 frame3_code->instruction_end() - 1,
239 frame2_code->instruction_end() - 1,
240 frame1_code->instruction_end() - 1);
241
242 processor->StopSynchronously();
243 CpuProfile* profile = profiles->StopProfiling("");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000244 CHECK(profile);
Steve Block6ded16b2010-05-10 14:33:55 +0100245
246 // Check call trees.
247 const i::List<ProfileNode*>* top_down_root_children =
248 profile->top_down()->root()->children();
249 CHECK_EQ(1, top_down_root_children->length());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000250 CHECK_EQ(0, strcmp("bbb", top_down_root_children->last()->entry()->name()));
Steve Block6ded16b2010-05-10 14:33:55 +0100251 const i::List<ProfileNode*>* top_down_bbb_children =
252 top_down_root_children->last()->children();
253 CHECK_EQ(1, top_down_bbb_children->length());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254 CHECK_EQ(0, strcmp("5", top_down_bbb_children->last()->entry()->name()));
Steve Block6ded16b2010-05-10 14:33:55 +0100255 const i::List<ProfileNode*>* top_down_stub_children =
256 top_down_bbb_children->last()->children();
257 CHECK_EQ(1, top_down_stub_children->length());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000258 CHECK_EQ(0, strcmp("ddd", top_down_stub_children->last()->entry()->name()));
Steve Block6ded16b2010-05-10 14:33:55 +0100259 const i::List<ProfileNode*>* top_down_ddd_children =
260 top_down_stub_children->last()->children();
261 CHECK_EQ(0, top_down_ddd_children->length());
Steve Block6ded16b2010-05-10 14:33:55 +0100262}
263
Iain Merrick75681382010-08-19 15:07:18 +0100264// http://crbug/51594
265// This test must not crash.
266TEST(CrashIfStoppingLastNonExistentProfile) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000267 CcTest::InitializeVM();
Iain Merrick75681382010-08-19 15:07:18 +0100268 TestSetup test_setup;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000269 CpuProfiler* profiler = CcTest::i_isolate()->cpu_profiler();
270 profiler->StartProfiling("1");
271 profiler->StopProfiling("2");
272 profiler->StartProfiling("1");
273 profiler->StopProfiling("");
Iain Merrick75681382010-08-19 15:07:18 +0100274}
275
Steve Block053d10c2011-06-13 19:13:29 +0100276// http://code.google.com/p/v8/issues/detail?id=1398
277// Long stacks (exceeding max frames limit) must not be erased.
278TEST(Issue1398) {
279 TestSetup test_setup;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000280 LocalContext env;
281 i::Isolate* isolate = CcTest::i_isolate();
282 i::HandleScope scope(isolate);
Steve Block053d10c2011-06-13 19:13:29 +0100283
Ben Murdochda12d292016-06-02 14:46:10 +0100284 i::AbstractCode* code = CreateCode(&env);
Steve Block053d10c2011-06-13 19:13:29 +0100285
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
287 profiles->StartProfiling("", false);
288 ProfileGenerator generator(profiles);
289 SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
290 &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100)));
291 processor->Start();
292 CpuProfiler profiler(isolate, profiles, &generator, processor.get());
293
294 profiler.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb");
295
296 i::TickSample* sample = processor->StartTickSample();
297 sample->pc = code->address();
Steve Block053d10c2011-06-13 19:13:29 +0100298 sample->tos = 0;
299 sample->frames_count = i::TickSample::kMaxFramesCount;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000300 for (unsigned i = 0; i < sample->frames_count; ++i) {
301 sample->stack[i] = code->address();
Steve Block053d10c2011-06-13 19:13:29 +0100302 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000303 processor->FinishTickSample();
Steve Block053d10c2011-06-13 19:13:29 +0100304
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000305 processor->StopSynchronously();
306 CpuProfile* profile = profiles->StopProfiling("");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000307 CHECK(profile);
Steve Block053d10c2011-06-13 19:13:29 +0100308
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000309 unsigned actual_depth = 0;
Steve Block053d10c2011-06-13 19:13:29 +0100310 const ProfileNode* node = profile->top_down()->root();
311 while (node->children()->length() > 0) {
312 node = node->children()->last();
313 ++actual_depth;
314 }
315
316 CHECK_EQ(1 + i::TickSample::kMaxFramesCount, actual_depth); // +1 for PC.
317}
318
Steve Block44f0eee2011-05-26 01:26:41 +0100319TEST(DeleteAllCpuProfiles) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000320 CcTest::InitializeVM();
Steve Block44f0eee2011-05-26 01:26:41 +0100321 TestSetup test_setup;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000322 CpuProfiler* profiler = CcTest::i_isolate()->cpu_profiler();
323 CHECK_EQ(0, profiler->GetProfilesCount());
324 profiler->DeleteAllProfiles();
325 CHECK_EQ(0, profiler->GetProfilesCount());
Steve Block44f0eee2011-05-26 01:26:41 +0100326
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000327 profiler->StartProfiling("1");
328 profiler->StopProfiling("1");
329 CHECK_EQ(1, profiler->GetProfilesCount());
330 profiler->DeleteAllProfiles();
331 CHECK_EQ(0, profiler->GetProfilesCount());
332 profiler->StartProfiling("1");
333 profiler->StartProfiling("2");
334 profiler->StopProfiling("2");
335 profiler->StopProfiling("1");
336 CHECK_EQ(2, profiler->GetProfilesCount());
337 profiler->DeleteAllProfiles();
338 CHECK_EQ(0, profiler->GetProfilesCount());
Steve Block44f0eee2011-05-26 01:26:41 +0100339
340 // Test profiling cancellation by the 'delete' command.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000341 profiler->StartProfiling("1");
342 profiler->StartProfiling("2");
343 CHECK_EQ(0, profiler->GetProfilesCount());
344 profiler->DeleteAllProfiles();
345 CHECK_EQ(0, profiler->GetProfilesCount());
346}
Steve Block44f0eee2011-05-26 01:26:41 +0100347
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000348
349static bool FindCpuProfile(v8::CpuProfiler* v8profiler,
350 const v8::CpuProfile* v8profile) {
351 i::CpuProfiler* profiler = reinterpret_cast<i::CpuProfiler*>(v8profiler);
352 const i::CpuProfile* profile =
353 reinterpret_cast<const i::CpuProfile*>(v8profile);
354 int length = profiler->GetProfilesCount();
355 for (int i = 0; i < length; i++) {
356 if (profile == profiler->GetProfile(i))
357 return true;
358 }
359 return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100360}
361
362
363TEST(DeleteCpuProfile) {
Steve Block44f0eee2011-05-26 01:26:41 +0100364 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000365 v8::HandleScope scope(env->GetIsolate());
366 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
367 i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(cpu_profiler);
Steve Block44f0eee2011-05-26 01:26:41 +0100368
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000369 CHECK_EQ(0, iprofiler->GetProfilesCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000370 v8::Local<v8::String> name1 = v8_str("1");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000371 cpu_profiler->StartProfiling(name1);
372 v8::CpuProfile* p1 = cpu_profiler->StopProfiling(name1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000373 CHECK(p1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000374 CHECK_EQ(1, iprofiler->GetProfilesCount());
375 CHECK(FindCpuProfile(cpu_profiler, p1));
376 p1->Delete();
377 CHECK_EQ(0, iprofiler->GetProfilesCount());
Steve Block44f0eee2011-05-26 01:26:41 +0100378
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000379 v8::Local<v8::String> name2 = v8_str("2");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000380 cpu_profiler->StartProfiling(name2);
381 v8::CpuProfile* p2 = cpu_profiler->StopProfiling(name2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000382 CHECK(p2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000383 CHECK_EQ(1, iprofiler->GetProfilesCount());
384 CHECK(FindCpuProfile(cpu_profiler, p2));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000385 v8::Local<v8::String> name3 = v8_str("3");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000386 cpu_profiler->StartProfiling(name3);
387 v8::CpuProfile* p3 = cpu_profiler->StopProfiling(name3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000388 CHECK(p3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000389 CHECK_EQ(2, iprofiler->GetProfilesCount());
390 CHECK_NE(p2, p3);
391 CHECK(FindCpuProfile(cpu_profiler, p3));
392 CHECK(FindCpuProfile(cpu_profiler, p2));
393 p2->Delete();
394 CHECK_EQ(1, iprofiler->GetProfilesCount());
395 CHECK(!FindCpuProfile(cpu_profiler, p2));
396 CHECK(FindCpuProfile(cpu_profiler, p3));
397 p3->Delete();
398 CHECK_EQ(0, iprofiler->GetProfilesCount());
Steve Block44f0eee2011-05-26 01:26:41 +0100399}
400
401
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000402TEST(ProfileStartEndTime) {
Steve Block44f0eee2011-05-26 01:26:41 +0100403 LocalContext env;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000404 v8::HandleScope scope(env->GetIsolate());
405 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
Steve Block44f0eee2011-05-26 01:26:41 +0100406
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000407 v8::Local<v8::String> profile_name = v8_str("test");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000408 cpu_profiler->StartProfiling(profile_name);
409 const v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
410 CHECK(profile->GetStartTime() <= profile->GetEndTime());
411}
Steve Block44f0eee2011-05-26 01:26:41 +0100412
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000413static v8::CpuProfile* RunProfiler(v8::Local<v8::Context> env,
414 v8::Local<v8::Function> function,
415 v8::Local<v8::Value> argv[], int argc,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100416 unsigned min_js_samples = 0,
417 unsigned min_external_samples = 0,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418 bool collect_samples = false) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000419 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000420 v8::Local<v8::String> profile_name = v8_str("my_profile");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000421
Ben Murdoch097c5b22016-05-18 11:27:45 +0100422 cpu_profiler->SetSamplingInterval(100);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000423 cpu_profiler->StartProfiling(profile_name, collect_samples);
424
425 i::Sampler* sampler =
426 reinterpret_cast<i::Isolate*>(env->GetIsolate())->logger()->sampler();
427 sampler->StartCountingSamples();
428 do {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000429 function->Call(env, env->Global(), argc, argv).ToLocalChecked();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100430 } while (sampler->js_sample_count() < min_js_samples ||
431 sampler->external_sample_count() < min_external_samples);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000432
433 v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
434
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000435 CHECK(profile);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000436 // Dump collected profile to have a better diagnostic in case of failure.
437 reinterpret_cast<i::CpuProfile*>(profile)->Print();
438
439 return profile;
440}
441
442
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000443static const v8::CpuProfileNode* FindChild(v8::Local<v8::Context> context,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000444 const v8::CpuProfileNode* node,
445 const char* name) {
446 int count = node->GetChildrenCount();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100447 v8::Local<v8::String> name_handle = v8_str(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000448 for (int i = 0; i < count; i++) {
449 const v8::CpuProfileNode* child = node->GetChild(i);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100450 if (name_handle->Equals(context, child->GetFunctionName()).FromJust()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000451 return child;
452 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000453 }
454 return NULL;
455}
456
457
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000458static const v8::CpuProfileNode* GetChild(v8::Local<v8::Context> context,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000459 const v8::CpuProfileNode* node,
460 const char* name) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000461 const v8::CpuProfileNode* result = FindChild(context, node, name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000462 if (!result) {
463 char buffer[100];
Ben Murdochc5610432016-08-08 18:44:38 +0100464 i::SNPrintF(i::ArrayVector(buffer), "Failed to GetChild: %s", name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 FATAL(buffer);
466 }
467 return result;
468}
469
470
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000471static void CheckSimpleBranch(v8::Local<v8::Context> context,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000472 const v8::CpuProfileNode* node,
473 const char* names[], int length) {
474 for (int i = 0; i < length; i++) {
475 const char* name = names[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000476 node = GetChild(context, node, name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000477 }
478}
479
480
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481static const ProfileNode* GetSimpleBranch(v8::Local<v8::Context> context,
482 v8::CpuProfile* profile,
483 const char* names[], int length) {
484 const v8::CpuProfileNode* node = profile->GetTopDownRoot();
485 for (int i = 0; i < length; i++) {
486 node = GetChild(context, node, names[i]);
487 }
488 return reinterpret_cast<const ProfileNode*>(node);
489}
490
Ben Murdoch097c5b22016-05-18 11:27:45 +0100491static void CallCollectSample(const v8::FunctionCallbackInfo<v8::Value>& info) {
492 info.GetIsolate()->GetCpuProfiler()->CollectSample();
493}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000494
Ben Murdoch097c5b22016-05-18 11:27:45 +0100495static const char* cpu_profiler_test_source =
496 "%NeverOptimizeFunction(loop);\n"
497 "%NeverOptimizeFunction(delay);\n"
498 "%NeverOptimizeFunction(bar);\n"
499 "%NeverOptimizeFunction(baz);\n"
500 "%NeverOptimizeFunction(foo);\n"
501 "%NeverOptimizeFunction(start);\n"
502 "function loop(timeout) {\n"
503 " this.mmm = 0;\n"
504 " var start = Date.now();\n"
505 " do {\n"
506 " var n = 1000;\n"
507 " while(n > 1) {\n"
508 " n--;\n"
509 " this.mmm += n * n * n;\n"
510 " }\n"
511 " } while (Date.now() - start < timeout);\n"
512 "}\n"
513 "function delay() { loop(10); }\n"
514 "function bar() { delay(); }\n"
515 "function baz() { delay(); }\n"
516 "function foo() {\n"
517 " delay();\n"
518 " bar();\n"
519 " delay();\n"
520 " baz();\n"
521 "}\n"
522 "function start(duration) {\n"
523 " var start = Date.now();\n"
524 " do {\n"
525 " foo();\n"
526 " } while (Date.now() - start < duration);\n"
527 "}\n";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000528
529// Check that the profile tree for the script above will look like the
530// following:
531//
532// [Top down]:
533// 1062 0 (root) [-1]
534// 1054 0 start [-1]
535// 1054 1 foo [-1]
536// 265 0 baz [-1]
537// 265 1 delay [-1]
538// 264 264 loop [-1]
539// 525 3 delay [-1]
540// 522 522 loop [-1]
541// 263 0 bar [-1]
542// 263 1 delay [-1]
543// 262 262 loop [-1]
544// 2 2 (program) [-1]
545// 6 6 (garbage collector) [-1]
546TEST(CollectCpuProfile) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100547 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548 LocalContext env;
549 v8::HandleScope scope(env->GetIsolate());
550
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000551 CompileRun(cpu_profiler_test_source);
552 v8::Local<v8::Function> function = GetFunction(env.local(), "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000553
554 int32_t profiling_interval_ms = 200;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000555 v8::Local<v8::Value> args[] = {
556 v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000557 v8::CpuProfile* profile =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100558 RunProfiler(env.local(), function, args, arraysize(args), 1000);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000559
560 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100561 const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
562 const v8::CpuProfileNode* foo_node = GetChild(env.local(), start_node, "foo");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000563
Ben Murdoch097c5b22016-05-18 11:27:45 +0100564 const char* bar_branch[] = {"bar", "delay", "loop"};
565 CheckSimpleBranch(env.local(), foo_node, bar_branch, arraysize(bar_branch));
566 const char* baz_branch[] = {"baz", "delay", "loop"};
567 CheckSimpleBranch(env.local(), foo_node, baz_branch, arraysize(baz_branch));
568 const char* delay_branch[] = {"delay", "loop"};
569 CheckSimpleBranch(env.local(), foo_node, delay_branch,
570 arraysize(delay_branch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000571
572 profile->Delete();
573}
574
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575static const char* hot_deopt_no_frame_entry_test_source =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100576 "%NeverOptimizeFunction(foo);\n"
577 "%NeverOptimizeFunction(start);\n"
578 "function foo(a, b) {\n"
579 " return a + b;\n"
580 "}\n"
581 "function start(timeout) {\n"
582 " var start = Date.now();\n"
583 " do {\n"
584 " for (var i = 1; i < 1000; ++i) foo(1, i);\n"
585 " var duration = Date.now() - start;\n"
586 " } while (duration < timeout);\n"
587 " return duration;\n"
588 "}\n";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589
590// Check that the profile tree for the script above will look like the
591// following:
592//
593// [Top down]:
594// 1062 0 (root) [-1]
595// 1054 0 start [-1]
596// 1054 1 foo [-1]
597// 2 2 (program) [-1]
598// 6 6 (garbage collector) [-1]
599//
Ben Murdoch097c5b22016-05-18 11:27:45 +0100600// The test checks no FP ranges are present in a deoptimized function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601// If 'foo' has no ranges the samples falling into the prologue will miss the
602// 'start' function on the stack, so 'foo' will be attached to the (root).
603TEST(HotDeoptNoFrameEntry) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100604 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000605 LocalContext env;
606 v8::HandleScope scope(env->GetIsolate());
607
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608 CompileRun(hot_deopt_no_frame_entry_test_source);
609 v8::Local<v8::Function> function = GetFunction(env.local(), "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000610
611 int32_t profiling_interval_ms = 200;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000612 v8::Local<v8::Value> args[] = {
613 v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000614 v8::CpuProfile* profile =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100615 RunProfiler(env.local(), function, args, arraysize(args), 1000);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000616 function->Call(env.local(), env->Global(), arraysize(args), args)
617 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000618
619 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100620 const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
621 GetChild(env.local(), start_node, "foo");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000622
623 profile->Delete();
624}
625
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000626TEST(CollectCpuProfileSamples) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100627 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000628 LocalContext env;
629 v8::HandleScope scope(env->GetIsolate());
630
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000631 CompileRun(cpu_profiler_test_source);
632 v8::Local<v8::Function> function = GetFunction(env.local(), "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000633
634 int32_t profiling_interval_ms = 200;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000635 v8::Local<v8::Value> args[] = {
636 v8::Integer::New(env->GetIsolate(), profiling_interval_ms)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000637 v8::CpuProfile* profile =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100638 RunProfiler(env.local(), function, args, arraysize(args), 1000, 0, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000639
640 CHECK_LE(200, profile->GetSamplesCount());
641 uint64_t end_time = profile->GetEndTime();
642 uint64_t current_time = profile->GetStartTime();
643 CHECK_LE(current_time, end_time);
644 for (int i = 0; i < profile->GetSamplesCount(); i++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000645 CHECK(profile->GetSample(i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000646 uint64_t timestamp = profile->GetSampleTimestamp(i);
647 CHECK_LE(current_time, timestamp);
648 CHECK_LE(timestamp, end_time);
649 current_time = timestamp;
650 }
651
652 profile->Delete();
653}
654
Ben Murdoch097c5b22016-05-18 11:27:45 +0100655static const char* cpu_profiler_test_source2 =
656 "%NeverOptimizeFunction(loop);\n"
657 "%NeverOptimizeFunction(delay);\n"
658 "%NeverOptimizeFunction(start);\n"
659 "function loop() {}\n"
660 "function delay() { loop(); }\n"
661 "function start(duration) {\n"
662 " var start = Date.now();\n"
663 " do {\n"
664 " for (var i = 0; i < 10000; ++i) delay();\n"
665 " } while (Date.now() - start < duration);\n"
666 "}";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000667
668// Check that the profile tree doesn't contain unexpected traces:
669// - 'loop' can be called only by 'delay'
670// - 'delay' may be called only by 'start'
671// The profile will look like the following:
672//
673// [Top down]:
674// 135 0 (root) [-1] #1
675// 121 72 start [-1] #3
676// 49 33 delay [-1] #4
677// 16 16 loop [-1] #5
678// 14 14 (program) [-1] #2
679TEST(SampleWhenFrameIsNotSetup) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100680 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681 LocalContext env;
682 v8::HandleScope scope(env->GetIsolate());
683
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000684 CompileRun(cpu_profiler_test_source2);
685 v8::Local<v8::Function> function = GetFunction(env.local(), "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000686
Ben Murdoch097c5b22016-05-18 11:27:45 +0100687 int32_t duration_ms = 100;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000688 v8::Local<v8::Value> args[] = {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100689 v8::Integer::New(env->GetIsolate(), duration_ms)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000690 v8::CpuProfile* profile =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100691 RunProfiler(env.local(), function, args, arraysize(args), 1000);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000692
693 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100694 const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
695 const v8::CpuProfileNode* delay_node =
696 GetChild(env.local(), start_node, "delay");
697 GetChild(env.local(), delay_node, "loop");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000698
699 profile->Delete();
700}
701
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000702static const char* native_accessor_test_source = "function start(count) {\n"
703" for (var i = 0; i < count; i++) {\n"
704" var o = instance.foo;\n"
705" instance.foo = o + 1;\n"
706" }\n"
707"}\n";
708
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000709class TestApiCallbacks {
710 public:
711 explicit TestApiCallbacks(int min_duration_ms)
712 : min_duration_ms_(min_duration_ms),
713 is_warming_up_(false) {}
714
715 static void Getter(v8::Local<v8::String> name,
716 const v8::PropertyCallbackInfo<v8::Value>& info) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100717 TestApiCallbacks* data = FromInfo(info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000718 data->Wait();
719 }
720
721 static void Setter(v8::Local<v8::String> name,
722 v8::Local<v8::Value> value,
723 const v8::PropertyCallbackInfo<void>& info) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100724 TestApiCallbacks* data = FromInfo(info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000725 data->Wait();
726 }
727
728 static void Callback(const v8::FunctionCallbackInfo<v8::Value>& info) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100729 TestApiCallbacks* data = FromInfo(info);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000730 data->Wait();
731 }
732
733 void set_warming_up(bool value) { is_warming_up_ = value; }
734
735 private:
736 void Wait() {
737 if (is_warming_up_) return;
738 double start = v8::base::OS::TimeCurrentMillis();
739 double duration = 0;
740 while (duration < min_duration_ms_) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000741 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742 duration = v8::base::OS::TimeCurrentMillis() - start;
743 }
744 }
745
Ben Murdoch097c5b22016-05-18 11:27:45 +0100746 template <typename T>
747 static TestApiCallbacks* FromInfo(const T& info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000748 void* data = v8::External::Cast(*info.Data())->Value();
749 return reinterpret_cast<TestApiCallbacks*>(data);
750 }
751
752 int min_duration_ms_;
753 bool is_warming_up_;
754};
755
756
757// Test that native accessors are properly reported in the CPU profile.
758// This test checks the case when the long-running accessors are called
759// only once and the optimizer doesn't have chance to change the invocation
760// code.
761TEST(NativeAccessorUninitializedIC) {
762 LocalContext env;
763 v8::Isolate* isolate = env->GetIsolate();
764 v8::HandleScope scope(isolate);
765
766 v8::Local<v8::FunctionTemplate> func_template =
767 v8::FunctionTemplate::New(isolate);
768 v8::Local<v8::ObjectTemplate> instance_template =
769 func_template->InstanceTemplate();
770
771 TestApiCallbacks accessors(100);
772 v8::Local<v8::External> data =
773 v8::External::New(isolate, &accessors);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000774 instance_template->SetAccessor(v8_str("foo"), &TestApiCallbacks::Getter,
775 &TestApiCallbacks::Setter, data);
776 v8::Local<v8::Function> func =
777 func_template->GetFunction(env.local()).ToLocalChecked();
778 v8::Local<v8::Object> instance =
779 func->NewInstance(env.local()).ToLocalChecked();
780 env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000781
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000782 CompileRun(native_accessor_test_source);
783 v8::Local<v8::Function> function = GetFunction(env.local(), "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000784
785 int32_t repeat_count = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000786 v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000787 v8::CpuProfile* profile =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100788 RunProfiler(env.local(), function, args, arraysize(args), 0, 100);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000789
790 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100791 const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
792 GetChild(env.local(), start_node, "get foo");
793 GetChild(env.local(), start_node, "set foo");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000794
795 profile->Delete();
796}
797
798
799// Test that native accessors are properly reported in the CPU profile.
800// This test makes sure that the accessors are called enough times to become
801// hot and to trigger optimizations.
802TEST(NativeAccessorMonomorphicIC) {
803 LocalContext env;
804 v8::Isolate* isolate = env->GetIsolate();
805 v8::HandleScope scope(isolate);
806
807 v8::Local<v8::FunctionTemplate> func_template =
808 v8::FunctionTemplate::New(isolate);
809 v8::Local<v8::ObjectTemplate> instance_template =
810 func_template->InstanceTemplate();
811
812 TestApiCallbacks accessors(1);
813 v8::Local<v8::External> data =
814 v8::External::New(isolate, &accessors);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000815 instance_template->SetAccessor(v8_str("foo"), &TestApiCallbacks::Getter,
816 &TestApiCallbacks::Setter, data);
817 v8::Local<v8::Function> func =
818 func_template->GetFunction(env.local()).ToLocalChecked();
819 v8::Local<v8::Object> instance =
820 func->NewInstance(env.local()).ToLocalChecked();
821 env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000822
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000823 CompileRun(native_accessor_test_source);
824 v8::Local<v8::Function> function = GetFunction(env.local(), "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000825
826 {
827 // Make sure accessors ICs are in monomorphic state before starting
828 // profiling.
829 accessors.set_warming_up(true);
830 int32_t warm_up_iterations = 3;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000831 v8::Local<v8::Value> args[] = {
832 v8::Integer::New(isolate, warm_up_iterations)};
833 function->Call(env.local(), env->Global(), arraysize(args), args)
834 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000835 accessors.set_warming_up(false);
836 }
837
838 int32_t repeat_count = 100;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000839 v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000840 v8::CpuProfile* profile =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100841 RunProfiler(env.local(), function, args, arraysize(args), 0, 100);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000842
843 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100844 const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
845 GetChild(env.local(), start_node, "get foo");
846 GetChild(env.local(), start_node, "set foo");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000847
848 profile->Delete();
849}
850
851
852static const char* native_method_test_source = "function start(count) {\n"
853" for (var i = 0; i < count; i++) {\n"
854" instance.fooMethod();\n"
855" }\n"
856"}\n";
857
858
859TEST(NativeMethodUninitializedIC) {
860 LocalContext env;
861 v8::Isolate* isolate = env->GetIsolate();
862 v8::HandleScope scope(isolate);
863
864 TestApiCallbacks callbacks(100);
865 v8::Local<v8::External> data =
866 v8::External::New(isolate, &callbacks);
867
868 v8::Local<v8::FunctionTemplate> func_template =
869 v8::FunctionTemplate::New(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000870 func_template->SetClassName(v8_str("Test_InstanceCostructor"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000871 v8::Local<v8::ObjectTemplate> proto_template =
872 func_template->PrototypeTemplate();
873 v8::Local<v8::Signature> signature =
874 v8::Signature::New(isolate, func_template);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000875 proto_template->Set(
876 v8_str("fooMethod"),
877 v8::FunctionTemplate::New(isolate, &TestApiCallbacks::Callback, data,
878 signature, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000879
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000880 v8::Local<v8::Function> func =
881 func_template->GetFunction(env.local()).ToLocalChecked();
882 v8::Local<v8::Object> instance =
883 func->NewInstance(env.local()).ToLocalChecked();
884 env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000885
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000886 CompileRun(native_method_test_source);
887 v8::Local<v8::Function> function = GetFunction(env.local(), "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000888
889 int32_t repeat_count = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000890 v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000891 v8::CpuProfile* profile =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100892 RunProfiler(env.local(), function, args, arraysize(args), 0, 100);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000893
894 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100895 const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
896 GetChild(env.local(), start_node, "fooMethod");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000897
898 profile->Delete();
899}
900
901
902TEST(NativeMethodMonomorphicIC) {
903 LocalContext env;
904 v8::Isolate* isolate = env->GetIsolate();
905 v8::HandleScope scope(isolate);
906
907 TestApiCallbacks callbacks(1);
908 v8::Local<v8::External> data =
909 v8::External::New(isolate, &callbacks);
910
911 v8::Local<v8::FunctionTemplate> func_template =
912 v8::FunctionTemplate::New(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000913 func_template->SetClassName(v8_str("Test_InstanceCostructor"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000914 v8::Local<v8::ObjectTemplate> proto_template =
915 func_template->PrototypeTemplate();
916 v8::Local<v8::Signature> signature =
917 v8::Signature::New(isolate, func_template);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000918 proto_template->Set(
919 v8_str("fooMethod"),
920 v8::FunctionTemplate::New(isolate, &TestApiCallbacks::Callback, data,
921 signature, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000922
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000923 v8::Local<v8::Function> func =
924 func_template->GetFunction(env.local()).ToLocalChecked();
925 v8::Local<v8::Object> instance =
926 func->NewInstance(env.local()).ToLocalChecked();
927 env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000928
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000929 CompileRun(native_method_test_source);
930 v8::Local<v8::Function> function = GetFunction(env.local(), "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000931 {
932 // Make sure method ICs are in monomorphic state before starting
933 // profiling.
934 callbacks.set_warming_up(true);
935 int32_t warm_up_iterations = 3;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000936 v8::Local<v8::Value> args[] = {
937 v8::Integer::New(isolate, warm_up_iterations)};
938 function->Call(env.local(), env->Global(), arraysize(args), args)
939 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000940 callbacks.set_warming_up(false);
941 }
942
943 int32_t repeat_count = 100;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000944 v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000945 v8::CpuProfile* profile =
Ben Murdoch097c5b22016-05-18 11:27:45 +0100946 RunProfiler(env.local(), function, args, arraysize(args), 0, 200);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000947
948 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000949 GetChild(env.local(), root, "start");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100950 const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
951 GetChild(env.local(), start_node, "fooMethod");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000952
953 profile->Delete();
954}
955
956
957static const char* bound_function_test_source =
958 "function foo() {\n"
959 " startProfiling('my_profile');\n"
960 "}\n"
961 "function start() {\n"
962 " var callback = foo.bind(this);\n"
963 " callback();\n"
964 "}";
965
966
967TEST(BoundFunctionCall) {
968 v8::HandleScope scope(CcTest::isolate());
969 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
970 v8::Context::Scope context_scope(env);
971
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000972 CompileRun(bound_function_test_source);
973 v8::Local<v8::Function> function = GetFunction(env, "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000974
Ben Murdoch097c5b22016-05-18 11:27:45 +0100975 v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000976
977 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000978
Ben Murdoch097c5b22016-05-18 11:27:45 +0100979 const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
980 GetChild(env, start_node, "foo");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000981
982 profile->Delete();
983}
984
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400985// This tests checks distribution of the samples through the source lines.
Ben Murdochda12d292016-06-02 14:46:10 +0100986static void TickLines(bool optimize) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400987 CcTest::InitializeVM();
988 LocalContext env;
Ben Murdochda12d292016-06-02 14:46:10 +0100989 i::FLAG_allow_natives_syntax = true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400990 i::FLAG_turbo_source_positions = true;
991 i::Isolate* isolate = CcTest::i_isolate();
992 i::Factory* factory = isolate->factory();
993 i::HandleScope scope(isolate);
994
995 i::EmbeddedVector<char, 512> script;
996
997 const char* func_name = "func";
Ben Murdochda12d292016-06-02 14:46:10 +0100998 const char* opt_func =
999 optimize ? "%OptimizeFunctionOnNextCall" : "%NeverOptimizeFunction";
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001000 i::SNPrintF(script,
1001 "function %s() {\n"
1002 " var n = 0;\n"
1003 " var m = 100*100;\n"
1004 " while (m > 1) {\n"
1005 " m--;\n"
1006 " n += m * m * m;\n"
1007 " }\n"
1008 "}\n"
Ben Murdochda12d292016-06-02 14:46:10 +01001009 "%s(%s);\n"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001010 "%s();\n",
Ben Murdochda12d292016-06-02 14:46:10 +01001011 func_name, opt_func, func_name, func_name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001012
1013 CompileRun(script.start());
1014
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001015 i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(
1016 v8::Utils::OpenHandle(*GetFunction(env.local(), func_name)));
1017 CHECK(func->shared());
Ben Murdochda12d292016-06-02 14:46:10 +01001018 CHECK(func->shared()->abstract_code());
1019 i::AbstractCode* code = func->abstract_code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001020 CHECK(code);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001021 i::Address code_address = code->instruction_start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001022 CHECK(code_address);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001023
1024 CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
1025 profiles->StartProfiling("", false);
1026 ProfileGenerator generator(profiles);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001027 SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
1028 &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001029 processor->Start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001030 CpuProfiler profiler(isolate, profiles, &generator, processor.get());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001031
1032 // Enqueue code creation events.
1033 i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name);
1034 int line = 1;
1035 int column = 1;
Ben Murdochc5610432016-08-08 18:44:38 +01001036 profiler.CodeCreateEvent(i::Logger::FUNCTION_TAG, code, func->shared(), *str,
1037 line, column);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001038
1039 // Enqueue a tick event to enable code events processing.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001040 EnqueueTickSampleEvent(processor.get(), code_address);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001041
1042 processor->StopSynchronously();
1043
1044 CpuProfile* profile = profiles->StopProfiling("");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001045 CHECK(profile);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001046
1047 // Check the state of profile generator.
1048 CodeEntry* func_entry = generator.code_map()->FindEntry(code_address);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001049 CHECK(func_entry);
1050 CHECK_EQ(0, strcmp(func_name, func_entry->name()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001051 const i::JITLineInfoTable* line_info = func_entry->line_info();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001052 CHECK(line_info);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001053 CHECK(!line_info->empty());
1054
1055 // Check the hit source lines using V8 Public APIs.
1056 const i::ProfileTree* tree = profile->top_down();
1057 ProfileNode* root = tree->root();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001058 CHECK(root);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001059 ProfileNode* func_node = root->FindChild(func_entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001060 CHECK(func_node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001061
1062 // Add 10 faked ticks to source line #5.
1063 int hit_line = 5;
1064 int hit_count = 10;
1065 for (int i = 0; i < hit_count; i++) func_node->IncrementLineTicks(hit_line);
1066
1067 unsigned int line_count = func_node->GetHitLineCount();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001068 CHECK_EQ(2u, line_count); // Expect two hit source lines - #1 and #5.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001069 ScopedVector<v8::CpuProfileNode::LineTick> entries(line_count);
1070 CHECK(func_node->GetLineTicks(&entries[0], line_count));
1071 int value = 0;
1072 for (int i = 0; i < entries.length(); i++)
1073 if (entries[i].line == hit_line) {
1074 value = entries[i].hit_count;
1075 break;
1076 }
1077 CHECK_EQ(hit_count, value);
1078}
1079
Ben Murdochda12d292016-06-02 14:46:10 +01001080TEST(TickLinesBaseline) { TickLines(false); }
1081
1082TEST(TickLinesOptimized) { TickLines(true); }
1083
Ben Murdoch097c5b22016-05-18 11:27:45 +01001084static const char* call_function_test_source =
1085 "%NeverOptimizeFunction(bar);\n"
1086 "%NeverOptimizeFunction(start);\n"
1087 "function bar(n) {\n"
1088 " var s = 0;\n"
1089 " for (var i = 0; i < n; i++) s += i * i * i;\n"
1090 " return s;\n"
1091 "}\n"
1092 "function start(duration) {\n"
1093 " var start = Date.now();\n"
1094 " do {\n"
1095 " for (var i = 0; i < 100; ++i)\n"
1096 " bar.call(this, 1000);\n"
1097 " } while (Date.now() - start < duration);\n"
1098 "}";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001099
1100// Test that if we sampled thread when it was inside FunctionCall buitin then
1101// its caller frame will be '(unresolved function)' as we have no reliable way
1102// to resolve it.
1103//
1104// [Top down]:
1105// 96 0 (root) [-1] #1
1106// 1 1 (garbage collector) [-1] #4
1107// 5 0 (unresolved function) [-1] #5
1108// 5 5 call [-1] #6
1109// 71 70 start [-1] #3
1110// 1 1 bar [-1] #7
1111// 19 19 (program) [-1] #2
1112TEST(FunctionCallSample) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001113 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001114 LocalContext env;
1115 v8::HandleScope scope(env->GetIsolate());
1116
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001117 // Collect garbage that might have be generated while installing
1118 // extensions.
1119 CcTest::heap()->CollectAllGarbage();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001120
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001121 CompileRun(call_function_test_source);
1122 v8::Local<v8::Function> function = GetFunction(env.local(), "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001123
1124 int32_t duration_ms = 100;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001125 v8::Local<v8::Value> args[] = {
1126 v8::Integer::New(env->GetIsolate(), duration_ms)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001127 v8::CpuProfile* profile =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001128 RunProfiler(env.local(), function, args, arraysize(args), 1000);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001129
1130 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001131 const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
1132 GetChild(env.local(), start_node, "bar");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001133
Ben Murdoch097c5b22016-05-18 11:27:45 +01001134 const v8::CpuProfileNode* unresolved_node = FindChild(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001135 env.local(), root, i::ProfileGenerator::kUnresolvedFunctionName);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001136 CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "call"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001137
1138 profile->Delete();
1139}
1140
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001141static const char* function_apply_test_source =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001142 "%NeverOptimizeFunction(bar);\n"
1143 "%NeverOptimizeFunction(test);\n"
1144 "%NeverOptimizeFunction(start);\n"
1145 "function bar(n) {\n"
1146 " var s = 0;\n"
1147 " for (var i = 0; i < n; i++) s += i * i * i;\n"
1148 " return s;\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001149 "}\n"
1150 "function test() {\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01001151 " bar.apply(this, [1000]);\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001152 "}\n"
1153 "function start(duration) {\n"
1154 " var start = Date.now();\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01001155 " do {\n"
1156 " for (var i = 0; i < 100; ++i) test();\n"
1157 " } while (Date.now() - start < duration);\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001158 "}";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001159
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001160// [Top down]:
1161// 94 0 (root) [-1] #0 1
1162// 2 2 (garbage collector) [-1] #0 7
1163// 82 49 start [-1] #16 3
1164// 1 0 (unresolved function) [-1] #0 8
1165// 1 1 apply [-1] #0 9
1166// 32 21 test [-1] #16 4
1167// 2 2 bar [-1] #16 6
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001168// 10 10 (program) [-1] #0 2
1169TEST(FunctionApplySample) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001170 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001171 LocalContext env;
1172 v8::HandleScope scope(env->GetIsolate());
1173
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001174 CompileRun(function_apply_test_source);
1175 v8::Local<v8::Function> function = GetFunction(env.local(), "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001176
1177 int32_t duration_ms = 100;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001178 v8::Local<v8::Value> args[] = {
1179 v8::Integer::New(env->GetIsolate(), duration_ms)};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001180
1181 v8::CpuProfile* profile =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001182 RunProfiler(env.local(), function, args, arraysize(args), 1000);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001183
1184 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001185 const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
1186 const v8::CpuProfileNode* test_node =
1187 GetChild(env.local(), start_node, "test");
1188 GetChild(env.local(), test_node, "bar");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001189
Ben Murdoch097c5b22016-05-18 11:27:45 +01001190 const v8::CpuProfileNode* unresolved_node = FindChild(
1191 env.local(), start_node, ProfileGenerator::kUnresolvedFunctionName);
1192 CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "apply"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001193
1194 profile->Delete();
1195}
1196
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001197static const char* cpu_profiler_deep_stack_test_source =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001198 "function foo(n) {\n"
1199 " if (n)\n"
1200 " foo(n - 1);\n"
1201 " else\n"
1202 " collectSample();\n"
1203 "}\n"
1204 "function start() {\n"
1205 " startProfiling('my_profile');\n"
1206 " foo(250);\n"
1207 "}\n";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001208
1209// Check a deep stack
1210//
1211// [Top down]:
1212// 0 (root) 0 #1
1213// 2 (program) 0 #2
1214// 0 start 21 #3 no reason
1215// 0 foo 21 #4 no reason
1216// 0 foo 21 #5 no reason
1217// ....
Ben Murdoch097c5b22016-05-18 11:27:45 +01001218// 0 foo 21 #254 no reason
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001219TEST(CpuProfileDeepStack) {
1220 v8::HandleScope scope(CcTest::isolate());
1221 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1222 v8::Context::Scope context_scope(env);
1223
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001224 CompileRun(cpu_profiler_deep_stack_test_source);
1225 v8::Local<v8::Function> function = GetFunction(env, "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001226
1227 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001228 v8::Local<v8::String> profile_name = v8_str("my_profile");
1229 function->Call(env, env->Global(), 0, NULL).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001230 v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001231 CHECK(profile);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001232 // Dump collected profile to have a better diagnostic in case of failure.
1233 reinterpret_cast<i::CpuProfile*>(profile)->Print();
1234
1235 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001236 const v8::CpuProfileNode* node = GetChild(env, root, "start");
Ben Murdoch097c5b22016-05-18 11:27:45 +01001237 for (int i = 0; i <= 250; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001238 node = GetChild(env, node, "foo");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001239 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001240 CHECK(!FindChild(env, node, "foo"));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001241
1242 profile->Delete();
1243}
1244
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001245static const char* js_native_js_test_source =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001246 "%NeverOptimizeFunction(foo);\n"
1247 "%NeverOptimizeFunction(bar);\n"
1248 "%NeverOptimizeFunction(start);\n"
1249 "function foo(n) {\n"
1250 " var s = 0;\n"
1251 " for (var i = 0; i < n; i++) s += i * i * i;\n"
1252 " return s;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001253 "}\n"
1254 "function bar() {\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01001255 " foo(1000);\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001256 "}\n"
1257 "function start() {\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01001258 " CallJsFunction(bar);\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001259 "}";
1260
1261static void CallJsFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001262 v8::Local<v8::Function> function = info[0].As<v8::Function>();
1263 v8::Local<v8::Value> argv[] = {info[1]};
1264 function->Call(info.GetIsolate()->GetCurrentContext(), info.This(),
1265 arraysize(argv), argv)
1266 .ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001267}
1268
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001269// [Top down]:
1270// 58 0 (root) #0 1
1271// 2 2 (program) #0 2
1272// 56 1 start #16 3
1273// 55 0 CallJsFunction #0 4
1274// 55 1 bar #16 5
1275// 54 54 foo #16 6
1276TEST(JsNativeJsSample) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001277 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001278 v8::HandleScope scope(CcTest::isolate());
1279 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1280 v8::Context::Scope context_scope(env);
1281
1282 v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
1283 env->GetIsolate(), CallJsFunction);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001284 v8::Local<v8::Function> func =
1285 func_template->GetFunction(env).ToLocalChecked();
1286 func->SetName(v8_str("CallJsFunction"));
1287 env->Global()->Set(env, v8_str("CallJsFunction"), func).FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001288
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001289 CompileRun(js_native_js_test_source);
1290 v8::Local<v8::Function> function = GetFunction(env, "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001291
Ben Murdoch097c5b22016-05-18 11:27:45 +01001292 v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 1000);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001293
1294 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001295 const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
1296 const v8::CpuProfileNode* native_node =
1297 GetChild(env, start_node, "CallJsFunction");
1298 const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar");
1299 GetChild(env, bar_node, "foo");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001300
1301 profile->Delete();
1302}
1303
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001304static const char* js_native_js_runtime_js_test_source =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001305 "%NeverOptimizeFunction(foo);\n"
1306 "%NeverOptimizeFunction(bar);\n"
1307 "%NeverOptimizeFunction(start);\n"
1308 "function foo(n) {\n"
1309 " var s = 0;\n"
1310 " for (var i = 0; i < n; i++) s += i * i * i;\n"
1311 " return s;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001312 "}\n"
1313 "var bound = foo.bind(this);\n"
1314 "function bar() {\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01001315 " bound(1000);\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001316 "}\n"
1317 "function start() {\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01001318 " CallJsFunction(bar);\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001319 "}";
1320
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001321// [Top down]:
1322// 57 0 (root) #0 1
1323// 55 1 start #16 3
1324// 54 0 CallJsFunction #0 4
1325// 54 3 bar #16 5
1326// 51 51 foo #16 6
1327// 2 2 (program) #0 2
1328TEST(JsNativeJsRuntimeJsSample) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001329 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001330 v8::HandleScope scope(CcTest::isolate());
1331 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1332 v8::Context::Scope context_scope(env);
1333
1334 v8::Local<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(
1335 env->GetIsolate(), CallJsFunction);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001336 v8::Local<v8::Function> func =
1337 func_template->GetFunction(env).ToLocalChecked();
1338 func->SetName(v8_str("CallJsFunction"));
1339 env->Global()->Set(env, v8_str("CallJsFunction"), func).FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001340
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001341 CompileRun(js_native_js_runtime_js_test_source);
1342 v8::Local<v8::Function> function = GetFunction(env, "start");
Ben Murdoch097c5b22016-05-18 11:27:45 +01001343 v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 1000);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001344
1345 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001346 const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
1347 const v8::CpuProfileNode* native_node =
1348 GetChild(env, start_node, "CallJsFunction");
1349 const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar");
1350 GetChild(env, bar_node, "foo");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001351
1352 profile->Delete();
1353}
1354
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001355static void CallJsFunction2(const v8::FunctionCallbackInfo<v8::Value>& info) {
1356 v8::base::OS::Print("In CallJsFunction2\n");
1357 CallJsFunction(info);
1358}
1359
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001360static const char* js_native1_js_native2_js_test_source =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001361 "%NeverOptimizeFunction(foo);\n"
1362 "%NeverOptimizeFunction(bar);\n"
1363 "%NeverOptimizeFunction(start);\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001364 "function foo() {\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01001365 " var s = 0;\n"
1366 " for (var i = 0; i < 1000; i++) s += i * i * i;\n"
1367 " return s;\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001368 "}\n"
1369 "function bar() {\n"
1370 " CallJsFunction2(foo);\n"
1371 "}\n"
1372 "function start() {\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01001373 " CallJsFunction1(bar);\n"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001374 "}";
1375
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001376// [Top down]:
1377// 57 0 (root) #0 1
1378// 55 1 start #16 3
1379// 54 0 CallJsFunction1 #0 4
1380// 54 0 bar #16 5
1381// 54 0 CallJsFunction2 #0 6
1382// 54 54 foo #16 7
1383// 2 2 (program) #0 2
1384TEST(JsNative1JsNative2JsSample) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001385 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001386 v8::HandleScope scope(CcTest::isolate());
1387 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1388 v8::Context::Scope context_scope(env);
1389
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001390 v8::Local<v8::Function> func1 =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001391 v8::FunctionTemplate::New(env->GetIsolate(), CallJsFunction)
1392 ->GetFunction(env)
1393 .ToLocalChecked();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001394 func1->SetName(v8_str("CallJsFunction1"));
1395 env->Global()->Set(env, v8_str("CallJsFunction1"), func1).FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001396
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001397 v8::Local<v8::Function> func2 =
1398 v8::FunctionTemplate::New(env->GetIsolate(), CallJsFunction2)
1399 ->GetFunction(env)
1400 .ToLocalChecked();
1401 func2->SetName(v8_str("CallJsFunction2"));
1402 env->Global()->Set(env, v8_str("CallJsFunction2"), func2).FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001403
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001404 CompileRun(js_native1_js_native2_js_test_source);
1405 v8::Local<v8::Function> function = GetFunction(env, "start");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001406
Ben Murdoch097c5b22016-05-18 11:27:45 +01001407 v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 1000);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001408
1409 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001410 const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
1411 const v8::CpuProfileNode* native_node1 =
1412 GetChild(env, start_node, "CallJsFunction1");
1413 const v8::CpuProfileNode* bar_node = GetChild(env, native_node1, "bar");
1414 const v8::CpuProfileNode* native_node2 =
1415 GetChild(env, bar_node, "CallJsFunction2");
1416 GetChild(env, native_node2, "foo");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001417
1418 profile->Delete();
1419}
1420
Ben Murdoch097c5b22016-05-18 11:27:45 +01001421static const char* js_force_collect_sample_source =
1422 "function start() {\n"
1423 " CallCollectSample();\n"
1424 "}";
1425
1426TEST(CollectSampleAPI) {
1427 v8::HandleScope scope(CcTest::isolate());
1428 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1429 v8::Context::Scope context_scope(env);
1430
1431 v8::Local<v8::FunctionTemplate> func_template =
1432 v8::FunctionTemplate::New(env->GetIsolate(), CallCollectSample);
1433 v8::Local<v8::Function> func =
1434 func_template->GetFunction(env).ToLocalChecked();
1435 func->SetName(v8_str("CallCollectSample"));
1436 env->Global()->Set(env, v8_str("CallCollectSample"), func).FromJust();
1437
1438 CompileRun(js_force_collect_sample_source);
1439 v8::Local<v8::Function> function = GetFunction(env, "start");
1440 v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 0);
1441
1442 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
1443 const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
1444 CHECK_LE(1, start_node->GetChildrenCount());
1445 GetChild(env, start_node, "CallCollectSample");
1446
1447 profile->Delete();
1448}
1449
1450static const char* js_native_js_runtime_multiple_test_source =
1451 "%NeverOptimizeFunction(foo);\n"
1452 "%NeverOptimizeFunction(bar);\n"
1453 "%NeverOptimizeFunction(start);\n"
1454 "function foo() {\n"
1455 " return Math.sin(Math.random());\n"
1456 "}\n"
1457 "var bound = foo.bind(this);\n"
1458 "function bar() {\n"
1459 " return bound();\n"
1460 "}\n"
1461 "function start() {\n"
1462 " startProfiling('my_profile');\n"
1463 " var startTime = Date.now();\n"
1464 " do {\n"
1465 " CallJsFunction(bar);\n"
1466 " } while (Date.now() - startTime < 200);\n"
1467 "}";
1468
1469// The test check multiple entrances/exits between JS and native code.
1470//
1471// [Top down]:
1472// (root) #0 1
1473// start #16 3
1474// CallJsFunction #0 4
1475// bar #16 5
1476// foo #16 6
1477// (program) #0 2
1478TEST(JsNativeJsRuntimeJsSampleMultiple) {
1479 i::FLAG_allow_natives_syntax = true;
1480 v8::HandleScope scope(CcTest::isolate());
1481 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1482 v8::Context::Scope context_scope(env);
1483
1484 v8::Local<v8::FunctionTemplate> func_template =
1485 v8::FunctionTemplate::New(env->GetIsolate(), CallJsFunction);
1486 v8::Local<v8::Function> func =
1487 func_template->GetFunction(env).ToLocalChecked();
1488 func->SetName(v8_str("CallJsFunction"));
1489 env->Global()->Set(env, v8_str("CallJsFunction"), func).FromJust();
1490
1491 CompileRun(js_native_js_runtime_multiple_test_source);
1492 v8::Local<v8::Function> function = GetFunction(env, "start");
1493
1494 v8::CpuProfile* profile = RunProfiler(env, function, NULL, 0, 500, 500);
1495
1496 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
1497 const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
1498 const v8::CpuProfileNode* native_node =
1499 GetChild(env, start_node, "CallJsFunction");
1500 const v8::CpuProfileNode* bar_node = GetChild(env, native_node, "bar");
1501 GetChild(env, bar_node, "foo");
1502
1503 profile->Delete();
1504}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001505
Ben Murdochda12d292016-06-02 14:46:10 +01001506static const char* inlining_test_source =
1507 "%NeverOptimizeFunction(action);\n"
1508 "%NeverOptimizeFunction(start);\n"
1509 "%OptimizeFunctionOnNextCall(level1);\n"
1510 "%OptimizeFunctionOnNextCall(level2);\n"
1511 "%OptimizeFunctionOnNextCall(level3);\n"
1512 "var finish = false;\n"
1513 "function action(n) {\n"
1514 " var s = 0;\n"
1515 " for (var i = 0; i < n; ++i) s += i*i*i;\n"
1516 " if (finish)\n"
1517 " startProfiling('my_profile');\n"
1518 " return s;\n"
1519 "}\n"
1520 "function level3() { return action(100); }\n"
1521 "function level2() { return level3() * 2; }\n"
1522 "function level1() { return level2(); }\n"
1523 "function start() {\n"
1524 " var n = 100;\n"
1525 " while (--n)\n"
1526 " level1();\n"
1527 " finish = true;\n"
1528 " level1();\n"
1529 "}";
1530
1531// The test check multiple entrances/exits between JS and native code.
1532//
1533// [Top down]:
1534// (root) #0 1
1535// start #16 3
1536// level1 #0 4
1537// level2 #16 5
1538// level3 #16 6
1539// action #16 7
1540// (program) #0 2
1541TEST(Inlining) {
1542 i::FLAG_allow_natives_syntax = true;
1543 v8::HandleScope scope(CcTest::isolate());
1544 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1545 v8::Context::Scope context_scope(env);
1546
1547 CompileRun(inlining_test_source);
1548 v8::Local<v8::Function> function = GetFunction(env, "start");
1549
1550 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
1551 v8::Local<v8::String> profile_name = v8_str("my_profile");
1552 function->Call(env, env->Global(), 0, NULL).ToLocalChecked();
1553 v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
1554 CHECK(profile);
1555 // Dump collected profile to have a better diagnostic in case of failure.
1556 reinterpret_cast<i::CpuProfile*>(profile)->Print();
1557
1558 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
1559 const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
1560 const v8::CpuProfileNode* level1_node = GetChild(env, start_node, "level1");
1561 const v8::CpuProfileNode* level2_node = GetChild(env, level1_node, "level2");
1562 const v8::CpuProfileNode* level3_node = GetChild(env, level2_node, "level3");
1563 GetChild(env, level3_node, "action");
1564
1565 profile->Delete();
1566}
1567
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001568// [Top down]:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001569// 0 (root) #0 1
1570// 2 (program) #0 2
1571// 3 (idle) #0 3
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001572TEST(IdleTime) {
1573 LocalContext env;
1574 v8::HandleScope scope(env->GetIsolate());
1575 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
1576
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001577 v8::Local<v8::String> profile_name = v8_str("my_profile");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001578 cpu_profiler->StartProfiling(profile_name);
1579
1580 i::Isolate* isolate = CcTest::i_isolate();
1581 i::ProfilerEventsProcessor* processor = isolate->cpu_profiler()->processor();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001582
Ben Murdoch097c5b22016-05-18 11:27:45 +01001583 processor->AddCurrentStack(isolate, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001584 cpu_profiler->SetIdle(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001585 for (int i = 0; i < 3; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001586 processor->AddCurrentStack(isolate, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001587 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001588 cpu_profiler->SetIdle(false);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001589 processor->AddCurrentStack(isolate, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001590
1591 v8::CpuProfile* profile = cpu_profiler->StopProfiling(profile_name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001592 CHECK(profile);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001593 // Dump collected profile to have a better diagnostic in case of failure.
1594 reinterpret_cast<i::CpuProfile*>(profile)->Print();
1595
1596 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001597 const v8::CpuProfileNode* program_node =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001598 GetChild(env.local(), root, ProfileGenerator::kProgramEntryName);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001599 CHECK_EQ(0, program_node->GetChildrenCount());
1600 CHECK_GE(program_node->GetHitCount(), 2u);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001601
Ben Murdoch097c5b22016-05-18 11:27:45 +01001602 const v8::CpuProfileNode* idle_node =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001603 GetChild(env.local(), root, ProfileGenerator::kIdleEntryName);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001604 CHECK_EQ(0, idle_node->GetChildrenCount());
1605 CHECK_GE(idle_node->GetHitCount(), 3u);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001606
1607 profile->Delete();
1608}
1609
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001610static void CheckFunctionDetails(v8::Isolate* isolate,
1611 const v8::CpuProfileNode* node,
1612 const char* name, const char* script_name,
1613 int script_id, int line, int column) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001614 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1615 CHECK(v8_str(name)->Equals(context, node->GetFunctionName()).FromJust());
1616 CHECK(v8_str(script_name)
1617 ->Equals(context, node->GetScriptResourceName())
1618 .FromJust());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001619 CHECK_EQ(script_id, node->GetScriptId());
1620 CHECK_EQ(line, node->GetLineNumber());
1621 CHECK_EQ(column, node->GetColumnNumber());
1622}
1623
1624
1625TEST(FunctionDetails) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001626 i::FLAG_allow_natives_syntax = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001627 v8::HandleScope scope(CcTest::isolate());
1628 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1629 v8::Context::Scope context_scope(env);
1630
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001631 v8::Local<v8::Script> script_a = CompileWithOrigin(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001632 "%NeverOptimizeFunction(foo);\n"
1633 "%NeverOptimizeFunction(bar);\n"
1634 " function foo\n() { bar(); }\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001635 " function bar() { startProfiling(); }\n",
1636 "script_a");
1637 script_a->Run(env).ToLocalChecked();
1638 v8::Local<v8::Script> script_b = CompileWithOrigin(
Ben Murdoch097c5b22016-05-18 11:27:45 +01001639 "%NeverOptimizeFunction(baz);"
1640 "\n\n function baz() { foo(); }\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001641 "\n\nbaz();\n"
1642 "stopProfiling();\n",
1643 "script_b");
1644 script_b->Run(env).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001645 const v8::CpuProfile* profile = i::ProfilerExtension::last_profile;
1646 const v8::CpuProfileNode* current = profile->GetTopDownRoot();
1647 reinterpret_cast<ProfileNode*>(
1648 const_cast<v8::CpuProfileNode*>(current))->Print(0);
1649 // The tree should look like this:
1650 // 0 (root) 0 #1
1651 // 0 "" 19 #2 no reason script_b:1
1652 // 0 baz 19 #3 TryCatchStatement script_b:3
1653 // 0 foo 18 #4 TryCatchStatement script_a:2
1654 // 1 bar 18 #5 no reason script_a:3
1655 const v8::CpuProfileNode* root = profile->GetTopDownRoot();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001656 const v8::CpuProfileNode* script = GetChild(env, root, "");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001657 CheckFunctionDetails(env->GetIsolate(), script, "", "script_b",
1658 script_b->GetUnboundScript()->GetId(), 1, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001659 const v8::CpuProfileNode* baz = GetChild(env, script, "baz");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001660 CheckFunctionDetails(env->GetIsolate(), baz, "baz", "script_b",
1661 script_b->GetUnboundScript()->GetId(), 3, 16);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001662 const v8::CpuProfileNode* foo = GetChild(env, baz, "foo");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001663 CheckFunctionDetails(env->GetIsolate(), foo, "foo", "script_a",
Ben Murdoch097c5b22016-05-18 11:27:45 +01001664 script_a->GetUnboundScript()->GetId(), 4, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001665 const v8::CpuProfileNode* bar = GetChild(env, foo, "bar");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001666 CheckFunctionDetails(env->GetIsolate(), bar, "bar", "script_a",
Ben Murdoch097c5b22016-05-18 11:27:45 +01001667 script_a->GetUnboundScript()->GetId(), 5, 14);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001668}
1669
1670
1671TEST(DontStopOnFinishedProfileDelete) {
1672 v8::HandleScope scope(CcTest::isolate());
1673 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1674 v8::Context::Scope context_scope(env);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001675
1676 v8::CpuProfiler* profiler = env->GetIsolate()->GetCpuProfiler();
1677 i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
1678
1679 CHECK_EQ(0, iprofiler->GetProfilesCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001680 v8::Local<v8::String> outer = v8_str("outer");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001681 profiler->StartProfiling(outer);
1682 CHECK_EQ(0, iprofiler->GetProfilesCount());
1683
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001684 v8::Local<v8::String> inner = v8_str("inner");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001685 profiler->StartProfiling(inner);
1686 CHECK_EQ(0, iprofiler->GetProfilesCount());
1687
1688 v8::CpuProfile* inner_profile = profiler->StopProfiling(inner);
1689 CHECK(inner_profile);
1690 CHECK_EQ(1, iprofiler->GetProfilesCount());
1691 inner_profile->Delete();
1692 inner_profile = NULL;
1693 CHECK_EQ(0, iprofiler->GetProfilesCount());
1694
1695 v8::CpuProfile* outer_profile = profiler->StopProfiling(outer);
1696 CHECK(outer_profile);
1697 CHECK_EQ(1, iprofiler->GetProfilesCount());
1698 outer_profile->Delete();
1699 outer_profile = NULL;
1700 CHECK_EQ(0, iprofiler->GetProfilesCount());
Steve Block44f0eee2011-05-26 01:26:41 +01001701}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001702
1703
1704const char* GetBranchDeoptReason(v8::Local<v8::Context> context,
1705 i::CpuProfile* iprofile, const char* branch[],
1706 int length) {
1707 v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
1708 const ProfileNode* iopt_function = NULL;
1709 iopt_function = GetSimpleBranch(context, profile, branch, length);
1710 CHECK_EQ(1U, iopt_function->deopt_infos().size());
1711 return iopt_function->deopt_infos()[0].deopt_reason;
1712}
1713
1714
1715// deopt at top function
1716TEST(CollectDeoptEvents) {
1717 if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
1718 i::FLAG_allow_natives_syntax = true;
1719 v8::HandleScope scope(CcTest::isolate());
1720 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1721 v8::Context::Scope context_scope(env);
1722 v8::Isolate* isolate = env->GetIsolate();
1723 v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
1724 i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
1725
1726 const char opt_source[] =
1727 "function opt_function%d(value, depth) {\n"
1728 " if (depth) return opt_function%d(value, depth - 1);\n"
1729 "\n"
1730 " return 10 / value;\n"
1731 "}\n"
1732 "\n";
1733
1734 for (int i = 0; i < 3; ++i) {
1735 i::EmbeddedVector<char, sizeof(opt_source) + 100> buffer;
1736 i::SNPrintF(buffer, opt_source, i, i);
1737 v8::Script::Compile(env, v8_str(buffer.start()))
1738 .ToLocalChecked()
1739 ->Run(env)
1740 .ToLocalChecked();
1741 }
1742
1743 const char* source =
1744 "startProfiling();\n"
1745 "\n"
1746 "opt_function0(1, 1);\n"
1747 "\n"
1748 "%OptimizeFunctionOnNextCall(opt_function0)\n"
1749 "\n"
1750 "opt_function0(1, 1);\n"
1751 "\n"
1752 "opt_function0(undefined, 1);\n"
1753 "\n"
1754 "opt_function1(1, 1);\n"
1755 "\n"
1756 "%OptimizeFunctionOnNextCall(opt_function1)\n"
1757 "\n"
1758 "opt_function1(1, 1);\n"
1759 "\n"
1760 "opt_function1(NaN, 1);\n"
1761 "\n"
1762 "opt_function2(1, 1);\n"
1763 "\n"
1764 "%OptimizeFunctionOnNextCall(opt_function2)\n"
1765 "\n"
1766 "opt_function2(1, 1);\n"
1767 "\n"
1768 "opt_function2(0, 1);\n"
1769 "\n"
1770 "stopProfiling();\n"
1771 "\n";
1772
1773 v8::Script::Compile(env, v8_str(source))
1774 .ToLocalChecked()
1775 ->Run(env)
1776 .ToLocalChecked();
1777 i::CpuProfile* iprofile = iprofiler->GetProfile(0);
1778 iprofile->Print();
1779 /* The expected profile
1780 [Top down]:
1781 0 (root) 0 #1
1782 23 32 #2
1783 1 opt_function2 31 #7
1784 1 opt_function2 31 #8
1785 ;;; deopted at script_id: 31 position: 106 with reason
1786 'division by zero'.
1787 2 opt_function0 29 #3
1788 4 opt_function0 29 #4
1789 ;;; deopted at script_id: 29 position: 108 with reason 'not a
1790 heap number'.
1791 0 opt_function1 30 #5
1792 1 opt_function1 30 #6
1793 ;;; deopted at script_id: 30 position: 108 with reason 'lost
1794 precision or NaN'.
1795 */
1796
1797 {
1798 const char* branch[] = {"", "opt_function0", "opt_function0"};
1799 CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber),
1800 GetBranchDeoptReason(env, iprofile, branch, arraysize(branch)));
1801 }
1802 {
1803 const char* branch[] = {"", "opt_function1", "opt_function1"};
1804 const char* deopt_reason =
1805 GetBranchDeoptReason(env, iprofile, branch, arraysize(branch));
1806 if (deopt_reason != reason(i::Deoptimizer::kNaN) &&
1807 deopt_reason != reason(i::Deoptimizer::kLostPrecisionOrNaN)) {
1808 FATAL(deopt_reason);
1809 }
1810 }
1811 {
1812 const char* branch[] = {"", "opt_function2", "opt_function2"};
1813 CHECK_EQ(reason(i::Deoptimizer::kDivisionByZero),
1814 GetBranchDeoptReason(env, iprofile, branch, arraysize(branch)));
1815 }
1816 iprofiler->DeleteProfile(iprofile);
1817}
1818
1819
1820TEST(SourceLocation) {
1821 i::FLAG_always_opt = true;
1822 i::FLAG_hydrogen_track_positions = true;
1823 LocalContext env;
1824 v8::HandleScope scope(CcTest::isolate());
1825
1826 const char* source =
1827 "function CompareStatementWithThis() {\n"
1828 " if (this === 1) {}\n"
1829 "}\n"
1830 "CompareStatementWithThis();\n";
1831
1832 v8::Script::Compile(env.local(), v8_str(source))
1833 .ToLocalChecked()
1834 ->Run(env.local())
1835 .ToLocalChecked();
1836}
1837
1838
1839static const char* inlined_source =
1840 "function opt_function(left, right) { var k = left / 10; var r = 10 / "
1841 "right; return k + r; }\n";
1842// 0.........1.........2.........3.........4....*....5.........6......*..7
1843
1844
1845// deopt at the first level inlined function
1846TEST(DeoptAtFirstLevelInlinedSource) {
1847 if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
1848 i::FLAG_allow_natives_syntax = true;
1849 v8::HandleScope scope(CcTest::isolate());
1850 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1851 v8::Context::Scope context_scope(env);
1852 v8::Isolate* isolate = env->GetIsolate();
1853 v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
1854 i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
1855
1856 // 0.........1.........2.........3.........4.........5.........6.........7
1857 const char* source =
1858 "function test(left, right) { return opt_function(left, right); }\n"
1859 "\n"
1860 "startProfiling();\n"
1861 "\n"
1862 "test(10, 10);\n"
1863 "\n"
1864 "%OptimizeFunctionOnNextCall(test)\n"
1865 "\n"
1866 "test(10, 10);\n"
1867 "\n"
1868 "test(undefined, 10);\n"
1869 "\n"
1870 "stopProfiling();\n"
1871 "\n";
1872
1873 v8::Local<v8::Script> inlined_script = v8_compile(inlined_source);
1874 inlined_script->Run(env).ToLocalChecked();
1875 int inlined_script_id = inlined_script->GetUnboundScript()->GetId();
1876
1877 v8::Local<v8::Script> script = v8_compile(source);
1878 script->Run(env).ToLocalChecked();
1879 int script_id = script->GetUnboundScript()->GetId();
1880
1881 i::CpuProfile* iprofile = iprofiler->GetProfile(0);
1882 iprofile->Print();
1883 /* The expected profile output
1884 [Top down]:
1885 0 (root) 0 #1
1886 10 30 #2
1887 1 test 30 #3
1888 ;;; deopted at script_id: 29 position: 45 with reason 'not a
1889 heap number'.
1890 ;;; Inline point: script_id 30 position: 36.
1891 4 opt_function 29 #4
1892 */
1893 v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
1894
1895 const char* branch[] = {"", "test"};
1896 const ProfileNode* itest_node =
1897 GetSimpleBranch(env, profile, branch, arraysize(branch));
1898 const std::vector<v8::CpuProfileDeoptInfo>& deopt_infos =
1899 itest_node->deopt_infos();
1900 CHECK_EQ(1U, deopt_infos.size());
1901
1902 const v8::CpuProfileDeoptInfo& info = deopt_infos[0];
1903 CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber), info.deopt_reason);
1904 CHECK_EQ(2U, info.stack.size());
1905 CHECK_EQ(inlined_script_id, info.stack[0].script_id);
1906 CHECK_EQ(offset(inlined_source, "left /"), info.stack[0].position);
1907 CHECK_EQ(script_id, info.stack[1].script_id);
1908 CHECK_EQ(offset(source, "opt_function(left,"), info.stack[1].position);
1909
1910 iprofiler->DeleteProfile(iprofile);
1911}
1912
1913
1914// deopt at the second level inlined function
1915TEST(DeoptAtSecondLevelInlinedSource) {
1916 if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
1917 i::FLAG_allow_natives_syntax = true;
1918 v8::HandleScope scope(CcTest::isolate());
1919 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1920 v8::Context::Scope context_scope(env);
1921 v8::Isolate* isolate = env->GetIsolate();
1922 v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
1923 i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
1924
1925 // 0.........1.........2.........3.........4.........5.........6.........7
1926 const char* source =
1927 "function test2(left, right) { return opt_function(left, right); }\n"
1928 "function test1(left, right) { return test2(left, right); }\n"
1929 "\n"
1930 "startProfiling();\n"
1931 "\n"
1932 "test1(10, 10);\n"
1933 "\n"
1934 "%OptimizeFunctionOnNextCall(test1)\n"
1935 "\n"
1936 "test1(10, 10);\n"
1937 "\n"
1938 "test1(undefined, 10);\n"
1939 "\n"
1940 "stopProfiling();\n"
1941 "\n";
1942
1943 v8::Local<v8::Script> inlined_script = v8_compile(inlined_source);
1944 inlined_script->Run(env).ToLocalChecked();
1945 int inlined_script_id = inlined_script->GetUnboundScript()->GetId();
1946
1947 v8::Local<v8::Script> script = v8_compile(source);
1948 script->Run(env).ToLocalChecked();
1949 int script_id = script->GetUnboundScript()->GetId();
1950
1951 i::CpuProfile* iprofile = iprofiler->GetProfile(0);
1952 iprofile->Print();
1953 /* The expected profile output
1954 [Top down]:
1955 0 (root) 0 #1
1956 11 30 #2
1957 1 test1 30 #3
1958 ;;; deopted at script_id: 29 position: 45 with reason 'not a
1959 heap number'.
1960 ;;; Inline point: script_id 30 position: 37.
1961 ;;; Inline point: script_id 30 position: 103.
1962 1 test2 30 #4
1963 3 opt_function 29 #5
1964 */
1965
1966 v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
1967
1968 const char* branch[] = {"", "test1"};
1969 const ProfileNode* itest_node =
1970 GetSimpleBranch(env, profile, branch, arraysize(branch));
1971 const std::vector<v8::CpuProfileDeoptInfo>& deopt_infos =
1972 itest_node->deopt_infos();
1973 CHECK_EQ(1U, deopt_infos.size());
1974
1975 const v8::CpuProfileDeoptInfo info = deopt_infos[0];
1976 CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber), info.deopt_reason);
1977 CHECK_EQ(3U, info.stack.size());
1978 CHECK_EQ(inlined_script_id, info.stack[0].script_id);
1979 CHECK_EQ(offset(inlined_source, "left /"), info.stack[0].position);
1980 CHECK_EQ(script_id, info.stack[1].script_id);
1981 CHECK_EQ(offset(source, "opt_function(left,"), info.stack[1].position);
1982 CHECK_EQ(offset(source, "test2(left, right);"), info.stack[2].position);
1983
1984 iprofiler->DeleteProfile(iprofile);
1985}
1986
1987
1988// deopt in untracked function
1989TEST(DeoptUntrackedFunction) {
1990 if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
1991 i::FLAG_allow_natives_syntax = true;
1992 v8::HandleScope scope(CcTest::isolate());
1993 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION);
1994 v8::Context::Scope context_scope(env);
1995 v8::Isolate* isolate = env->GetIsolate();
1996 v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
1997 i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
1998
1999 // 0.........1.........2.........3.........4.........5.........6.........7
2000 const char* source =
2001 "function test(left, right) { return opt_function(left, right); }\n"
2002 "\n"
2003 "test(10, 10);\n"
2004 "\n"
2005 "%OptimizeFunctionOnNextCall(test)\n"
2006 "\n"
2007 "test(10, 10);\n"
2008 "\n"
2009 "startProfiling();\n" // profiler started after compilation.
2010 "\n"
2011 "test(undefined, 10);\n"
2012 "\n"
2013 "stopProfiling();\n"
2014 "\n";
2015
2016 v8::Local<v8::Script> inlined_script = v8_compile(inlined_source);
2017 inlined_script->Run(env).ToLocalChecked();
2018
2019 v8::Local<v8::Script> script = v8_compile(source);
2020 script->Run(env).ToLocalChecked();
2021
2022 i::CpuProfile* iprofile = iprofiler->GetProfile(0);
2023 iprofile->Print();
2024 v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
2025
2026 const char* branch[] = {"", "test"};
2027 const ProfileNode* itest_node =
2028 GetSimpleBranch(env, profile, branch, arraysize(branch));
2029 CHECK_EQ(0U, itest_node->deopt_infos().size());
2030
2031 iprofiler->DeleteProfile(iprofile);
2032}