Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/assert.h" | 5 #include "platform/assert.h" |
| 6 #include "vm/isolate.h" | 6 #include "vm/isolate.h" |
| 7 #include "vm/lockers.h" | 7 #include "vm/lockers.h" |
| 8 #include "vm/unit_test.h" | 8 #include "vm/unit_test.h" |
| 9 #include "vm/profiler.h" | 9 #include "vm/profiler.h" |
| 10 #include "vm/thread_pool.h" | 10 #include "vm/thread_pool.h" |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 217 isos[1]->Shutdown(); | 217 isos[1]->Shutdown(); |
| 218 Thread::ExitIsolate(); | 218 Thread::ExitIsolate(); |
| 219 Thread::EnterIsolate(orig); | 219 Thread::EnterIsolate(orig); |
| 220 // Original zone should be preserved. | 220 // Original zone should be preserved. |
| 221 EXPECT_EQ(orig_zone, Thread::Current()->zone()); | 221 EXPECT_EQ(orig_zone, Thread::Current()->zone()); |
| 222 EXPECT_STREQ("foo", orig_str); | 222 EXPECT_STREQ("foo", orig_str); |
| 223 delete isos[0]; | 223 delete isos[0]; |
| 224 delete isos[1]; | 224 delete isos[1]; |
| 225 } | 225 } |
| 226 | 226 |
| 227 | |
| 228 // A helper thread that alternatingly cooperates and organizes | |
| 229 // safepoint rendezvous. At rendezvous, it explicitly visits the | |
| 230 // stacks looking for a specific marker (Smi) to verify that the expected | |
| 231 // number threads are actually visited. The task is "done" when it has | |
| 232 // successfully made all other tasks and the main thread rendezvous (may | |
| 233 // not happen in the first rendezvous, since tasks are still starting up). | |
| 234 class SafepointTestTask : public ThreadPool::Task { | |
| 235 public: | |
| 236 static const intptr_t kTaskCount = 5; | |
| 237 | |
| 238 SafepointTestTask(Isolate* isolate, | |
| 239 Mutex* mutex, | |
| 240 intptr_t* expected_count, | |
| 241 intptr_t* done, | |
| 242 intptr_t* exited) | |
| 243 : isolate_(isolate), | |
| 244 mutex_(mutex), | |
| 245 expected_count_(expected_count), | |
| 246 done_(done), | |
| 247 exited_(exited) {} | |
| 248 | |
| 249 virtual void Run() { | |
| 250 Thread::EnterIsolateAsHelper(isolate_); | |
| 251 for (int i = 0; ; ++i) { | |
| 252 Thread* thread = Thread::Current(); | |
| 253 StackZone stack_zone(thread); | |
| 254 Zone* zone = thread->zone(); | |
| 255 HANDLESCOPE(thread); | |
| 256 const intptr_t kUniqueSmi = 928327281; | |
| 257 Smi& smi = Smi::Handle(zone, Smi::New(kUniqueSmi)); | |
| 258 { | |
| 259 MutexLocker ml(mutex_); | |
| 260 ++*expected_count_; | |
| 261 } | |
| 262 if ((i % 100) != 0) { | |
| 263 // Usually, we just cooperate. | |
| 264 isolate_->thread_registry()->CheckSafepoint(); | |
| 265 } else { | |
| 266 // But occasionally, organize a rendezvous. | |
| 267 isolate_->thread_registry()->SafepointAllThreads(); | |
| 268 ObjectCounter counter(isolate_, &smi); | |
| 269 isolate_->thread_registry()->VisitObjectPointers(&counter); | |
| 270 { | |
| 271 MutexLocker ml(mutex_); | |
| 272 EXPECT_EQ(*expected_count_, counter.count()); | |
| 273 } | |
| 274 UserTag& tag = UserTag::Handle(zone, isolate_->current_tag()); | |
| 275 if (tag.raw() != isolate_->default_tag()) { | |
| 276 String& label = String::Handle(zone, tag.label()); | |
| 277 EXPECT(label.Equals("foo")); | |
| 278 MutexLocker ml(mutex_); | |
| 279 if (*expected_count_ == kTaskCount) { | |
| 280 ++*done_; | |
| 281 } | |
| 282 } | |
| 283 isolate_->thread_registry()->ResumeAllThreads(); | |
| 284 } | |
| 285 // Clear handle and adjust expectation. Check whether we're done. | |
| 286 smi = Smi::New(0); | |
| 287 { | |
| 288 MutexLocker ml(mutex_); | |
| 289 --*expected_count_; | |
| 290 if (*done_ == kTaskCount) { | |
| 291 break; | |
| 292 } | |
| 293 } | |
| 294 } | |
| 295 Thread::ExitIsolateAsHelper(); | |
| 296 { | |
| 297 MutexLocker ml(mutex_); | |
| 298 ++*exited_; | |
| 299 } | |
| 300 } | |
| 301 | |
| 302 private: | |
| 303 Isolate* isolate_; | |
| 304 Mutex* mutex_; | |
| 305 intptr_t* expected_count_; // # copies of kUniqueSmi we expect to visit. | |
| 306 intptr_t* done_; // # tasks that successfully safepointed once. | |
| 307 intptr_t* exited_; // # tasks that are no longer running. | |
| 308 }; | |
| 309 | |
| 310 | |
| 311 // Test rendezvous of: | |
| 312 // - helpers in VM code, | |
| 313 // - main thread in pure Dart, | |
| 314 // organized by | |
| 315 // - helpers. | |
| 316 TEST_CASE(SafepointTestDart) { | |
| 317 Isolate* isolate = Thread::Current()->isolate(); | |
| 318 Mutex mutex; | |
| 319 intptr_t expected_count = 0; | |
| 320 intptr_t done = 0; | |
| 321 intptr_t exited = 0; | |
| 322 const intptr_t num_tasks = SafepointTestTask::kTaskCount; // Please compiler. | |
|
Ivan Posva
2015/07/31 20:28:09
Comment does not parse.
koda
2015/07/31 22:40:44
Linker was unhappy with the inlined static constan
| |
| 323 for (int i = 0; i < num_tasks; i++) { | |
| 324 Dart::thread_pool()->Run(new SafepointTestTask( | |
| 325 isolate, &mutex, &expected_count, &done, &exited)); | |
| 326 } | |
| 327 // Run Dart code on the main thread long enough to allow all helpers | |
| 328 // to get their verification done and exit. Use a specific UserTag | |
| 329 // to enable the helpers to verify that the main thread is | |
| 330 // successfully interrupted in the pure Dart loop. | |
| 331 char buffer[1024]; | |
| 332 OS::SNPrint(buffer, sizeof(buffer), | |
| 333 "import 'dart:profiler';\n" | |
| 334 "int dummy = 0;\n" | |
| 335 "main() {\n" | |
| 336 " new UserTag('foo').makeCurrent();\n" | |
| 337 " for (dummy = 0; dummy < 1234567890; ++dummy) {\n" | |
|
Ivan Posva
2015/07/31 20:28:09
How long does this test execute on simulated archi
koda
2015/07/31 22:40:44
Now using smaller loop count if USING_SIMULATOR.
| |
| 338 " dummy += (dummy & 1);\n" | |
| 339 " }\n" | |
| 340 "}\n"); | |
| 341 Dart_Handle lib = TestCase::LoadTestScript(buffer, NULL); | |
| 342 EXPECT_VALID(lib); | |
| 343 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 344 EXPECT_VALID(result); | |
| 345 // Ensure we looped long enough to allow all helpers to succeed and exit. | |
| 346 { | |
| 347 MutexLocker ml(&mutex); | |
| 348 EXPECT_EQ(num_tasks, done); | |
| 349 EXPECT_EQ(num_tasks, exited); | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 | |
| 354 // Test rendezvous of: | |
| 355 // - helpers in VM code, and | |
| 356 // - main thread in VM code, | |
| 357 // organized by | |
| 358 // - helpers. | |
| 359 TEST_CASE(SafepointTestVM) { | |
| 360 Thread* thread = Thread::Current(); | |
| 361 Isolate* isolate = thread->isolate(); | |
| 362 Mutex mutex; | |
| 363 intptr_t expected_count = 0; | |
| 364 intptr_t done = 0; | |
| 365 intptr_t exited = 0; | |
| 366 const intptr_t num_tasks = SafepointTestTask::kTaskCount; // Please compiler. | |
| 367 for (int i = 0; i < num_tasks; i++) { | |
| 368 Dart::thread_pool()->Run(new SafepointTestTask( | |
| 369 isolate, &mutex, &expected_count, &done, &exited)); | |
| 370 } | |
| 371 String& label = String::Handle(String::New("foo")); | |
| 372 UserTag& tag = UserTag::Handle(UserTag::New(label)); | |
| 373 isolate->set_current_tag(tag); | |
| 374 while (true) { | |
| 375 isolate->thread_registry()->CheckSafepoint(); | |
| 376 MutexLocker ml(&mutex); | |
| 377 if (exited == num_tasks) { | |
| 378 break; | |
| 379 } | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 | |
| 384 // Test rendezvous of: | |
| 385 // - helpers in VM code, and | |
| 386 // - main thread in VM code, | |
| 387 // organized by | |
| 388 // - main thread, and | |
| 389 // - helpers. | |
| 390 TEST_CASE(SafepointTestVM2) { | |
| 391 Thread* thread = Thread::Current(); | |
| 392 Isolate* isolate = thread->isolate(); | |
| 393 Mutex mutex; | |
| 394 intptr_t expected_count = 0; | |
| 395 intptr_t done = 0; | |
| 396 intptr_t exited = 0; | |
| 397 const intptr_t num_tasks = SafepointTestTask::kTaskCount; // Please compiler. | |
| 398 for (int i = 0; i < num_tasks; i++) { | |
| 399 Dart::thread_pool()->Run(new SafepointTestTask( | |
| 400 isolate, &mutex, &expected_count, &done, &exited)); | |
| 401 } | |
| 402 bool all_helpers = false; | |
| 403 do { | |
| 404 isolate->thread_registry()->SafepointAllThreads(); | |
| 405 { | |
| 406 MutexLocker ml(&mutex); | |
| 407 if (expected_count == num_tasks) { | |
| 408 all_helpers = true; | |
| 409 } | |
| 410 } | |
| 411 isolate->thread_registry()->ResumeAllThreads(); | |
| 412 } while (!all_helpers); | |
| 413 String& label = String::Handle(String::New("foo")); | |
| 414 UserTag& tag = UserTag::Handle(UserTag::New(label)); | |
| 415 isolate->set_current_tag(tag); | |
| 416 while (true) { | |
| 417 isolate->thread_registry()->CheckSafepoint(); | |
| 418 MutexLocker ml(&mutex); | |
| 419 if (exited == num_tasks) { | |
| 420 break; | |
| 421 } | |
| 422 } | |
| 423 } | |
| 424 | |
| 227 } // namespace dart | 425 } // namespace dart |
| OLD | NEW |