Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 : // Tests of sampler functionalities.
5 :
6 : #include "src/libsampler/sampler.h"
7 :
8 : #include "src/base/platform/platform.h"
9 : #include "src/base/platform/time.h"
10 : #include "test/cctest/cctest.h"
11 :
12 :
13 : namespace v8 {
14 : namespace sampler {
15 :
16 : namespace {
17 :
18 0 : class TestSamplingThread : public base::Thread {
19 : public:
20 : static const int kSamplerThreadStackSize = 64 * 1024;
21 :
22 : explicit TestSamplingThread(Sampler* sampler)
23 : : Thread(base::Thread::Options("TestSamplingThread",
24 : kSamplerThreadStackSize)),
25 0 : sampler_(sampler) {}
26 :
27 : // Implement Thread::Run().
28 0 : void Run() override {
29 0 : while (sampler_->IsActive()) {
30 0 : sampler_->DoSample();
31 0 : base::OS::Sleep(base::TimeDelta::FromMilliseconds(1));
32 : }
33 0 : }
34 :
35 : private:
36 : Sampler* sampler_;
37 : };
38 :
39 :
40 0 : class TestSampler : public Sampler {
41 : public:
42 0 : explicit TestSampler(Isolate* isolate) : Sampler(isolate) {}
43 :
44 0 : void SampleStack(const v8::RegisterState& regs) override {
45 : void* frames[kMaxFramesCount];
46 : SampleInfo sample_info;
47 0 : isolate()->GetStackSample(regs, frames, kMaxFramesCount, &sample_info);
48 0 : if (is_counting_samples_) {
49 0 : if (sample_info.vm_state == JS) ++js_sample_count_;
50 0 : if (sample_info.vm_state == EXTERNAL) ++external_sample_count_;
51 : }
52 0 : }
53 : };
54 :
55 :
56 : class TestApiCallbacks {
57 : public:
58 : TestApiCallbacks() = default;
59 :
60 0 : static void Getter(v8::Local<v8::String> name,
61 : const v8::PropertyCallbackInfo<v8::Value>& info) {
62 0 : }
63 :
64 0 : static void Setter(v8::Local<v8::String> name,
65 : v8::Local<v8::Value> value,
66 : const v8::PropertyCallbackInfo<void>& info) {
67 0 : }
68 : };
69 :
70 :
71 0 : static void RunSampler(v8::Local<v8::Context> env,
72 : v8::Local<v8::Function> function,
73 : v8::Local<v8::Value> argv[], int argc,
74 : unsigned min_js_samples = 0,
75 : unsigned min_external_samples = 0) {
76 0 : TestSampler sampler(env->GetIsolate());
77 : TestSamplingThread thread(&sampler);
78 0 : sampler.Start();
79 : sampler.StartCountingSamples();
80 0 : thread.StartSynchronously();
81 0 : do {
82 0 : function->Call(env, env->Global(), argc, argv).ToLocalChecked();
83 0 : } while (sampler.js_sample_count() < min_js_samples ||
84 : sampler.external_sample_count() < min_external_samples);
85 0 : sampler.Stop();
86 0 : thread.Join();
87 0 : }
88 :
89 : } // namespace
90 :
91 : static const char* sampler_test_source = "function start(count) {\n"
92 : " for (var i = 0; i < count; i++) {\n"
93 : " var o = instance.foo;\n"
94 : " instance.foo = o + 1;\n"
95 : " }\n"
96 : "}\n";
97 :
98 0 : static v8::Local<v8::Function> GetFunction(v8::Local<v8::Context> env,
99 : const char* name) {
100 : return v8::Local<v8::Function>::Cast(
101 0 : env->Global()->Get(env, v8_str(name)).ToLocalChecked());
102 : }
103 :
104 :
105 26656 : TEST(LibSamplerCollectSample) {
106 0 : LocalContext env;
107 0 : v8::Isolate* isolate = env->GetIsolate();
108 0 : v8::HandleScope scope(isolate);
109 :
110 : v8::Local<v8::FunctionTemplate> func_template =
111 0 : v8::FunctionTemplate::New(isolate);
112 : v8::Local<v8::ObjectTemplate> instance_template =
113 0 : func_template->InstanceTemplate();
114 :
115 : TestApiCallbacks accessors;
116 : v8::Local<v8::External> data =
117 0 : v8::External::New(isolate, &accessors);
118 0 : instance_template->SetAccessor(v8_str("foo"), &TestApiCallbacks::Getter,
119 0 : &TestApiCallbacks::Setter, data);
120 : v8::Local<v8::Function> func =
121 0 : func_template->GetFunction(env.local()).ToLocalChecked();
122 : v8::Local<v8::Object> instance =
123 : func->NewInstance(env.local()).ToLocalChecked();
124 0 : env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust();
125 :
126 0 : CompileRun(sampler_test_source);
127 0 : v8::Local<v8::Function> function = GetFunction(env.local(), "start");
128 :
129 : int32_t repeat_count = 100;
130 0 : v8::Local<v8::Value> args[] = {v8::Integer::New(isolate, repeat_count)};
131 0 : RunSampler(env.local(), function, args, arraysize(args), 100, 100);
132 0 : }
133 :
134 : #ifdef USE_SIGNALS
135 :
136 10 : class CountingSampler : public Sampler {
137 : public:
138 10 : explicit CountingSampler(Isolate* isolate) : Sampler(isolate) {}
139 :
140 10 : void SampleStack(const v8::RegisterState& regs) override { sample_count_++; }
141 :
142 : int sample_count() { return sample_count_; }
143 : void set_active(bool active) { SetActive(active); }
144 : void set_should_record_sample() { SetShouldRecordSample(); }
145 :
146 : private:
147 : int sample_count_ = 0;
148 : };
149 :
150 26661 : TEST(SamplerManager_AddRemoveSampler) {
151 5 : LocalContext env;
152 5 : v8::Isolate* isolate = env->GetIsolate();
153 :
154 5 : SamplerManager* manager = SamplerManager::instance();
155 : CountingSampler sampler1(isolate);
156 : sampler1.set_active(true);
157 : sampler1.set_should_record_sample();
158 5 : CHECK_EQ(0, sampler1.sample_count());
159 :
160 5 : manager->AddSampler(&sampler1);
161 :
162 : RegisterState state;
163 5 : manager->DoSample(state);
164 5 : CHECK_EQ(1, sampler1.sample_count());
165 :
166 : sampler1.set_active(true);
167 : sampler1.set_should_record_sample();
168 5 : manager->RemoveSampler(&sampler1);
169 : sampler1.set_active(false);
170 :
171 5 : manager->DoSample(state);
172 5 : CHECK_EQ(1, sampler1.sample_count());
173 5 : }
174 :
175 26661 : TEST(SamplerManager_DoesNotReAdd) {
176 5 : LocalContext env;
177 5 : v8::Isolate* isolate = env->GetIsolate();
178 :
179 : // Add the same sampler twice, but check we only get one sample for it.
180 5 : SamplerManager* manager = SamplerManager::instance();
181 : CountingSampler sampler1(isolate);
182 : sampler1.set_active(true);
183 : sampler1.set_should_record_sample();
184 5 : manager->AddSampler(&sampler1);
185 5 : manager->AddSampler(&sampler1);
186 :
187 : RegisterState state;
188 5 : manager->DoSample(state);
189 5 : CHECK_EQ(1, sampler1.sample_count());
190 : sampler1.set_active(false);
191 5 : }
192 :
193 26661 : TEST(AtomicGuard_GetNonBlockingSuccess) {
194 5 : std::atomic_bool atomic{false};
195 : {
196 10 : AtomicGuard guard(&atomic, false);
197 5 : CHECK(guard.is_success());
198 :
199 10 : AtomicGuard guard2(&atomic, false);
200 5 : CHECK(!guard2.is_success());
201 : }
202 10 : AtomicGuard guard(&atomic, false);
203 5 : CHECK(guard.is_success());
204 5 : }
205 :
206 26661 : TEST(AtomicGuard_GetBlockingSuccess) {
207 5 : std::atomic_bool atomic{false};
208 : {
209 10 : AtomicGuard guard(&atomic);
210 5 : CHECK(guard.is_success());
211 :
212 10 : AtomicGuard guard2(&atomic, false);
213 5 : CHECK(!guard2.is_success());
214 : }
215 10 : AtomicGuard guard(&atomic);
216 5 : CHECK(guard.is_success());
217 5 : }
218 :
219 : #endif // USE_SIGNALS
220 :
221 : } // namespace sampler
222 79968 : } // namespace v8
|