1 /* 2 * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "compiler/compileBroker.hpp" 26 #include "gc/shared/collectedHeap.hpp" 27 #include "jfr/jfrEvents.hpp" 28 #include "jfr/support/jfrThreadId.hpp" 29 #include "logging/log.hpp" 30 #include "logging/logStream.hpp" 31 #include "logging/logConfiguration.hpp" 32 #include "memory/resourceArea.hpp" 33 #include "memory/universe.hpp" 34 #include "oops/oop.inline.hpp" 35 #include "oops/verifyOopClosure.hpp" 36 #include "runtime/atomic.hpp" 37 #include "runtime/cpuTimeCounters.hpp" 38 #include "runtime/handles.inline.hpp" 39 #include "runtime/interfaceSupport.inline.hpp" 40 #include "runtime/java.hpp" 41 #include "runtime/javaThread.inline.hpp" 42 #include "runtime/jniHandles.hpp" 43 #include "runtime/mutexLocker.hpp" 44 #include "runtime/os.hpp" 45 #include "runtime/perfData.inline.hpp" 46 #include "runtime/safepoint.hpp" 47 #include "runtime/synchronizer.hpp" 48 #include "runtime/timerTrace.hpp" 49 #include "runtime/vmThread.hpp" 50 #include "runtime/vmOperation.hpp" 51 #include "runtime/vmOperations.hpp" 52 #include "services/management.hpp" 53 #include "utilities/dtrace.hpp" 54 #include "utilities/events.hpp" 55 #include "utilities/vmError.hpp" 56 57 58 //------------------------------------------------------------------------------------------------------------------ 59 // Timeout machinery 60 61 void VMOperationTimeoutTask::task() { 62 assert(AbortVMOnVMOperationTimeout, "only if enabled"); 63 if (is_armed()) { 64 jlong delay = nanos_to_millis(os::javaTimeNanos() - _arm_time); 65 if (delay > AbortVMOnVMOperationTimeoutDelay) { 66 fatal("%s VM operation took too long: " JLONG_FORMAT " ms elapsed since VM-op start (timeout: %zd ms)", 67 _vm_op_name, delay, AbortVMOnVMOperationTimeoutDelay); 68 } 69 } 70 } 71 72 bool VMOperationTimeoutTask::is_armed() { 73 return Atomic::load_acquire(&_armed) != 0; 74 } 75 76 void VMOperationTimeoutTask::arm(const char* vm_op_name) { 77 _vm_op_name = vm_op_name; 78 _arm_time = os::javaTimeNanos(); 79 Atomic::release_store_fence(&_armed, 1); 80 } 81 82 void VMOperationTimeoutTask::disarm() { 83 Atomic::release_store_fence(&_armed, 0); 84 85 // The two stores to `_armed` are counted in VM-op, but they should be 86 // insignificant compared to the actual VM-op duration. 87 jlong vm_op_duration = nanos_to_millis(os::javaTimeNanos() - _arm_time); 88 89 // Repeat the timeout-check logic on the VM thread, because 90 // VMOperationTimeoutTask might miss the arm-disarm window depending on 91 // the scheduling. 92 if (vm_op_duration > AbortVMOnVMOperationTimeoutDelay) { 93 fatal("%s VM operation took too long: completed in " JLONG_FORMAT " ms (timeout: %zd ms)", 94 _vm_op_name, vm_op_duration, AbortVMOnVMOperationTimeoutDelay); 95 } 96 _vm_op_name = nullptr; 97 } 98 99 //------------------------------------------------------------------------------------------------------------------ 100 // Implementation of VMThread stuff 101 102 static VM_SafepointALot safepointALot_op; 103 static VM_ForceSafepoint no_op; 104 105 bool VMThread::_should_terminate = false; 106 bool VMThread::_terminated = false; 107 Monitor* VMThread::_terminate_lock = nullptr; 108 VMThread* VMThread::_vm_thread = nullptr; 109 VM_Operation* VMThread::_cur_vm_operation = nullptr; 110 VM_Operation* VMThread::_next_vm_operation = &no_op; // Prevent any thread from setting an operation until VM thread is ready. 111 PerfCounter* VMThread::_perf_accumulated_vm_operation_time = nullptr; 112 VMOperationTimeoutTask* VMThread::_timeout_task = nullptr; 113 114 115 void VMThread::create() { 116 assert(vm_thread() == nullptr, "we can only allocate one VMThread"); 117 _vm_thread = new VMThread(); 118 119 if (AbortVMOnVMOperationTimeout) { 120 // Make sure we call the timeout task frequently enough, but not too frequent. 121 // Try to make the interval 10% of the timeout delay, so that we miss the timeout 122 // by those 10% at max. Periodic task also expects it to fit min/max intervals. 123 size_t interval = (size_t)AbortVMOnVMOperationTimeoutDelay / 10; 124 interval = interval / PeriodicTask::interval_gran * PeriodicTask::interval_gran; 125 interval = MAX2<size_t>(interval, PeriodicTask::min_interval); 126 interval = MIN2<size_t>(interval, PeriodicTask::max_interval); 127 128 _timeout_task = new VMOperationTimeoutTask(interval); 129 _timeout_task->enroll(); 130 } else { 131 assert(_timeout_task == nullptr, "sanity"); 132 } 133 134 _terminate_lock = new Monitor(Mutex::nosafepoint, "VMThreadTerminate_lock"); 135 136 if (UsePerfData) { 137 // jvmstat performance counters 138 JavaThread* THREAD = JavaThread::current(); // For exception macros. 139 _perf_accumulated_vm_operation_time = 140 PerfDataManager::create_counter(SUN_THREADS, "vmOperationTime", 141 PerfData::U_Ticks, CHECK); 142 CPUTimeCounters::create_counter(CPUTimeGroups::CPUTimeType::vm); 143 } 144 } 145 146 VMThread::VMThread() : NamedThread(), _is_running(false) { 147 set_name("VM Thread"); 148 } 149 150 void VMThread::destroy() { 151 _vm_thread = nullptr; // VM thread is gone 152 } 153 154 static VM_Halt halt_op; 155 156 void VMThread::run() { 157 assert(this == vm_thread(), "check"); 158 159 // Notify_lock wait checks on is_running() to rewait in 160 // case of spurious wakeup, it should wait on the last 161 // value set prior to the notify 162 Atomic::store(&_is_running, true); 163 164 { 165 MutexLocker ml(Notify_lock); 166 Notify_lock->notify(); 167 } 168 // Notify_lock is destroyed by Threads::create_vm() 169 170 int prio = (VMThreadPriority == -1) 171 ? os::java_to_os_priority[NearMaxPriority] 172 : VMThreadPriority; 173 // Note that I cannot call os::set_priority because it expects Java 174 // priorities and I am *explicitly* using OS priorities so that it's 175 // possible to set the VM thread priority higher than any Java thread. 176 os::set_native_priority( this, prio ); 177 178 // Wait for VM_Operations until termination 179 this->loop(); 180 181 // Note the intention to exit before safepointing. 182 // 6295565 This has the effect of waiting for any large tty 183 // outputs to finish. 184 if (xtty != nullptr) { 185 ttyLocker ttyl; 186 xtty->begin_elem("destroy_vm"); 187 xtty->stamp(); 188 xtty->end_elem(); 189 assert(should_terminate(), "termination flag must be set"); 190 } 191 192 // 4526887 let VM thread exit at Safepoint 193 _cur_vm_operation = &halt_op; 194 SafepointSynchronize::begin(); 195 196 if (VerifyBeforeExit) { 197 HandleMark hm(VMThread::vm_thread()); 198 // Among other things, this ensures that Eden top is correct. 199 Universe::heap()->prepare_for_verify(); 200 // Silent verification so as not to pollute normal output, 201 // unless we really asked for it. 202 Universe::verify(); 203 } 204 205 CompileBroker::set_should_block(); 206 207 // wait for threads (compiler threads or daemon threads) in the 208 // _thread_in_native state to block. 209 VM_Exit::wait_for_threads_in_native_to_block(); 210 211 // The ObjectMonitor subsystem uses perf counters so do this before 212 // we signal that the VM thread is gone. We don't want to run afoul 213 // of perfMemory_exit() in exit_globals(). 214 ObjectSynchronizer::do_final_audit_and_print_stats(); 215 216 // signal other threads that VM process is gone 217 { 218 // Note: we must have the _no_safepoint_check_flag. Mutex::lock() allows 219 // VM thread to enter any lock at Safepoint as long as its _owner is null. 220 // If that happens after _terminate_lock->wait() has unset _owner 221 // but before it actually drops the lock and waits, the notification below 222 // may get lost and we will have a hang. To avoid this, we need to use 223 // Mutex::lock_without_safepoint_check(). 224 MonitorLocker ml(_terminate_lock, Mutex::_no_safepoint_check_flag); 225 _terminated = true; 226 ml.notify(); 227 } 228 229 // We are now racing with the VM termination being carried out in 230 // another thread, so we don't "delete this". Numerous threads don't 231 // get deleted when the VM terminates 232 233 } 234 235 236 // Notify the VMThread that the last non-daemon JavaThread has terminated, 237 // and wait until operation is performed. 238 void VMThread::wait_for_vm_thread_exit() { 239 assert(JavaThread::current()->is_terminated(), "Should be terminated"); 240 { 241 MonitorLocker mu(VMOperation_lock); 242 _should_terminate = true; 243 mu.notify_all(); 244 } 245 246 // Note: VM thread leaves at Safepoint. We are not stopped by Safepoint 247 // because this thread has been removed from the threads list. But anything 248 // that could get blocked by Safepoint should not be used after this point, 249 // otherwise we will hang, since there is no one can end the safepoint. 250 251 // Wait until VM thread is terminated 252 // Note: it should be OK to use Terminator_lock here. But this is called 253 // at a very delicate time (VM shutdown) and we are operating in non- VM 254 // thread at Safepoint. It's safer to not share lock with other threads. 255 { 256 MonitorLocker ml(_terminate_lock, Mutex::_no_safepoint_check_flag); 257 while (!VMThread::is_terminated()) { 258 ml.wait(); 259 } 260 } 261 } 262 263 static void post_vm_operation_event(EventExecuteVMOperation* event, VM_Operation* op) { 264 assert(event != nullptr, "invariant"); 265 assert(op != nullptr, "invariant"); 266 const bool evaluate_at_safepoint = op->evaluate_at_safepoint(); 267 event->set_operation(op->type()); 268 event->set_safepoint(evaluate_at_safepoint); 269 event->set_blocking(true); 270 event->set_caller(JFR_THREAD_ID(op->calling_thread())); 271 event->set_safepointId(evaluate_at_safepoint ? SafepointSynchronize::safepoint_id() : 0); 272 event->commit(); 273 } 274 275 void VMThread::evaluate_operation(VM_Operation* op) { 276 ResourceMark rm; 277 278 { 279 PerfTraceElapsedTime vm_op_timer(perf_accumulated_vm_operation_time()); 280 HOTSPOT_VMOPS_BEGIN( 281 (char *) op->name(), strlen(op->name()), 282 op->evaluate_at_safepoint() ? 0 : 1); 283 284 EventExecuteVMOperation event; 285 op->evaluate(); 286 if (event.should_commit()) { 287 post_vm_operation_event(&event, op); 288 } 289 290 HOTSPOT_VMOPS_END( 291 (char *) op->name(), strlen(op->name()), 292 op->evaluate_at_safepoint() ? 0 : 1); 293 } 294 295 if (UsePerfData && os::is_thread_cpu_time_supported()) { 296 assert(Thread::current() == this, "Must be called from VM thread"); 297 // Update vm_thread_cpu_time after each VM operation. 298 ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::vm); 299 tttc.do_thread(this); 300 } 301 } 302 303 class HandshakeALotClosure : public HandshakeClosure { 304 public: 305 HandshakeALotClosure() : HandshakeClosure("HandshakeALot") {} 306 void do_thread(Thread* thread) { 307 #ifdef ASSERT 308 JavaThread::cast(thread)->verify_states_for_handshake(); 309 #endif 310 } 311 }; 312 313 bool VMThread::handshake_or_safepoint_alot() { 314 assert(_cur_vm_operation == nullptr, "should not have an op yet"); 315 assert(_next_vm_operation == nullptr, "should not have an op yet"); 316 if (!HandshakeALot && !SafepointALot) { 317 return false; 318 } 319 static jlong last_alot_ms = 0; 320 jlong now_ms = nanos_to_millis(os::javaTimeNanos()); 321 // If HandshakeALot or SafepointALot are set, but GuaranteedSafepointInterval is explicitly 322 // set to 0 on the command line, we emit the operation if it's been more than a second 323 // since the last one. 324 jlong interval = GuaranteedSafepointInterval != 0 ? GuaranteedSafepointInterval : 1000; 325 jlong deadline_ms = interval + last_alot_ms; 326 if (now_ms > deadline_ms) { 327 last_alot_ms = now_ms; 328 return true; 329 } 330 return false; 331 } 332 333 bool VMThread::set_next_operation(VM_Operation *op) { 334 if (_next_vm_operation != nullptr) { 335 return false; 336 } 337 log_debug(vmthread)("Adding VM operation: %s", op->name()); 338 339 _next_vm_operation = op; 340 341 HOTSPOT_VMOPS_REQUEST( 342 (char *) op->name(), strlen(op->name()), 343 op->evaluate_at_safepoint() ? 0 : 1); 344 return true; 345 } 346 347 void VMThread::wait_until_executed(VM_Operation* op) { 348 MonitorLocker ml(VMOperation_lock, 349 Thread::current()->is_Java_thread() ? 350 Mutex::_safepoint_check_flag : 351 Mutex::_no_safepoint_check_flag); 352 { 353 TraceTime timer("Installing VM operation", TRACETIME_LOG(Trace, vmthread)); 354 while (true) { 355 if (VMThread::vm_thread()->set_next_operation(op)) { 356 ml.notify_all(); 357 break; 358 } 359 // Wait to install this operation as the next operation in the VM Thread 360 log_trace(vmthread)("A VM operation already set, waiting"); 361 ml.wait(); 362 } 363 } 364 { 365 // Wait until the operation has been processed 366 TraceTime timer("Waiting for VM operation to be completed", TRACETIME_LOG(Trace, vmthread)); 367 // _next_vm_operation is cleared holding VMOperation_lock after it has been 368 // executed. We wait until _next_vm_operation is not our op. 369 while (_next_vm_operation == op) { 370 // VM Thread can process it once we unlock the mutex on wait. 371 ml.wait(); 372 } 373 } 374 } 375 376 static void self_destruct_if_needed() { 377 // Support for self destruction 378 if ((SelfDestructTimer != 0.0) && !VMError::is_error_reported() && 379 (os::elapsedTime() > SelfDestructTimer * 60.0)) { 380 tty->print_cr("VM self-destructed"); 381 os::exit(-1); 382 } 383 } 384 385 void VMThread::inner_execute(VM_Operation* op) { 386 assert(Thread::current()->is_VM_thread(), "Must be the VM thread"); 387 388 VM_Operation* prev_vm_operation = nullptr; 389 if (_cur_vm_operation != nullptr) { 390 // Check that the VM operation allows nested VM operation. 391 // This is normally not the case, e.g., the compiler 392 // does not allow nested scavenges or compiles. 393 if (!_cur_vm_operation->allow_nested_vm_operations()) { 394 fatal("Unexpected nested VM operation %s requested by operation %s", 395 op->name(), _cur_vm_operation->name()); 396 } 397 op->set_calling_thread(_cur_vm_operation->calling_thread()); 398 prev_vm_operation = _cur_vm_operation; 399 } 400 401 _cur_vm_operation = op; 402 403 HandleMark hm(VMThread::vm_thread()); 404 405 const char* const cause = op->cause(); 406 stringStream ss; 407 ss.print("Executing%s%s VM operation: %s", 408 prev_vm_operation != nullptr ? " nested" : "", 409 op->evaluate_at_safepoint() ? " safepoint" : " non-safepoint", 410 op->name()); 411 if (cause != nullptr) { 412 ss.print(" (%s)", cause); 413 } 414 415 EventMarkVMOperation em("%s", ss.freeze()); 416 log_debug(vmthread)("%s", ss.freeze()); 417 418 bool end_safepoint = false; 419 bool has_timeout_task = (_timeout_task != nullptr); 420 if (_cur_vm_operation->evaluate_at_safepoint() && 421 !SafepointSynchronize::is_at_safepoint()) { 422 SafepointSynchronize::begin(); 423 if (has_timeout_task) { 424 _timeout_task->arm(_cur_vm_operation->name()); 425 } 426 end_safepoint = true; 427 } 428 429 evaluate_operation(_cur_vm_operation); 430 431 if (end_safepoint) { 432 if (has_timeout_task) { 433 _timeout_task->disarm(); 434 } 435 SafepointSynchronize::end(); 436 } 437 438 _cur_vm_operation = prev_vm_operation; 439 } 440 441 void VMThread::wait_for_operation() { 442 assert(Thread::current()->is_VM_thread(), "Must be the VM thread"); 443 MonitorLocker ml_op_lock(VMOperation_lock, Mutex::_no_safepoint_check_flag); 444 445 // Clear previous operation. 446 // On first call this clears a dummy place-holder. 447 _next_vm_operation = nullptr; 448 // Notify operation is done and notify a next operation can be installed. 449 ml_op_lock.notify_all(); 450 451 while (!should_terminate()) { 452 self_destruct_if_needed(); 453 if (_next_vm_operation != nullptr) { 454 return; 455 } 456 if (handshake_or_safepoint_alot()) { 457 if (HandshakeALot) { 458 MutexUnlocker mul(VMOperation_lock); 459 HandshakeALotClosure hal_cl; 460 Handshake::execute(&hal_cl); 461 } 462 // When we unlocked above someone might have setup a new op. 463 if (_next_vm_operation != nullptr) { 464 return; 465 } 466 if (SafepointALot) { 467 _next_vm_operation = &safepointALot_op; 468 return; 469 } 470 } 471 assert(_next_vm_operation == nullptr, "Must be"); 472 assert(_cur_vm_operation == nullptr, "Must be"); 473 474 // We didn't find anything to execute, notify any waiter so they can install an op. 475 ml_op_lock.notify_all(); 476 ml_op_lock.wait(GuaranteedSafepointInterval); 477 } 478 } 479 480 void VMThread::loop() { 481 assert(_cur_vm_operation == nullptr, "no current one should be executing"); 482 483 SafepointSynchronize::init(_vm_thread); 484 485 // Need to set a calling thread for ops not passed 486 // via the normal way. 487 no_op.set_calling_thread(_vm_thread); 488 safepointALot_op.set_calling_thread(_vm_thread); 489 490 while (true) { 491 if (should_terminate()) break; 492 wait_for_operation(); 493 if (should_terminate()) break; 494 assert(_next_vm_operation != nullptr, "Must have one"); 495 inner_execute(_next_vm_operation); 496 } 497 } 498 499 // A SkipGCALot object is used to elide the usual effect of gc-a-lot 500 // over a section of execution by a thread. Currently, it's used only to 501 // prevent re-entrant calls to GC. 502 class SkipGCALot : public StackObj { 503 private: 504 bool _saved; 505 Thread* _t; 506 507 public: 508 #ifdef ASSERT 509 SkipGCALot(Thread* t) : _t(t) { 510 _saved = _t->skip_gcalot(); 511 _t->set_skip_gcalot(true); 512 } 513 514 ~SkipGCALot() { 515 assert(_t->skip_gcalot(), "Save-restore protocol invariant"); 516 _t->set_skip_gcalot(_saved); 517 } 518 #else 519 SkipGCALot(Thread* t) { } 520 ~SkipGCALot() { } 521 #endif 522 }; 523 524 void VMThread::execute(VM_Operation* op) { 525 Thread* t = Thread::current(); 526 527 PerfTraceTimedEvent p(VMThread::get_perf_timer_for(op), VMThread::get_perf_counter_for(op), \ 528 Thread::current()->profile_vm_ops()); \ 529 530 if (t->is_VM_thread()) { 531 op->set_calling_thread(t); 532 ((VMThread*)t)->inner_execute(op); 533 return; 534 } 535 536 // Avoid re-entrant attempts to gc-a-lot 537 SkipGCALot sgcalot(t); 538 539 // JavaThread or WatcherThread 540 if (t->is_Java_thread()) { 541 JavaThread::cast(t)->check_for_valid_safepoint_state(); 542 } 543 544 // New request from Java thread, evaluate prologue 545 if (!op->doit_prologue()) { 546 return; // op was cancelled 547 } 548 549 op->set_calling_thread(t); 550 551 wait_until_executed(op); 552 553 op->doit_epilogue(); 554 } 555 556 void VMThread::verify() { 557 oops_do(&VerifyOopClosure::verify_oop, nullptr); 558 } 559 560 #define DECLARE_COUNTER(name) \ 561 PerfTickCounters* _perf_##name##_timer = nullptr; \ 562 PerfCounter* _perf_##name##_count = nullptr; 563 564 VM_OPS_DO(DECLARE_COUNTER) 565 566 #undef DECLARE_COUNTER 567 568 #define SWITCH_TIMER(name) \ 569 case VM_Operation::VMOp_##name: return _perf_##name##_timer; 570 571 PerfTickCounters* VMThread::get_perf_timer_for(VM_Operation *op) { 572 switch(op->type()) { 573 VM_OPS_DO(SWITCH_TIMER) 574 default: ShouldNotReachHere(); 575 } 576 } 577 578 #undef SWITCH_TIMER 579 580 #define SWITCH_COUNT(name) \ 581 case VM_Operation::VMOp_##name: return _perf_##name##_count; 582 583 PerfCounter* VMThread::get_perf_counter_for(VM_Operation *op) { 584 switch(op->type()) { 585 VM_OPS_DO(SWITCH_COUNT) 586 default: ShouldNotReachHere(); 587 } 588 } 589 590 #undef SWITCH_COUNT 591 592 #define INIT_COUNTER(name) \ 593 NEWPERFTICKCOUNTERS(_perf_##name##_timer, SUN_RT, #name "_time"); \ 594 NEWPERFEVENTCOUNTER(_perf_##name##_count, SUN_RT, #name "_count"); \ 595 596 void VMThread::init_counters() { 597 if (ProfileVMOps && UsePerfData) { 598 EXCEPTION_MARK; 599 600 VM_OPS_DO(INIT_COUNTER) 601 602 if (HAS_PENDING_EXCEPTION) { 603 vm_exit_during_initialization("jvm_perf_init failed unexpectedly"); 604 } 605 } 606 } 607 608 #undef INIT_COUNTER 609 610 static jlong total_count() { 611 jlong total = 0; 612 #define ACC_COUNT(name) total += _perf_##name##_count->get_value(); 613 VM_OPS_DO(ACC_COUNT) 614 #undef ACC_COUNT 615 return total; 616 } 617 618 static jlong total_elapsed_time_in_ms() { 619 jlong total_elapsed_ticks = 0; 620 #define ACC_COUNT(name) total_elapsed_ticks += _perf_##name##_timer->elapsed_counter_value(); 621 VM_OPS_DO(ACC_COUNT) 622 #undef ACC_COUNT 623 return Management::ticks_to_ms(total_elapsed_ticks); 624 } 625 626 #define PRINT_COUNTER(name) {\ 627 jlong count = _perf_##name##_count->get_value(); \ 628 if (count > 0) { \ 629 st->print_cr(" %-40s = " JLONG_FORMAT_W(6) "us (" JLONG_FORMAT_W(5) " events)", #name, _perf_##name##_timer->elapsed_counter_value_us(), count); \ 630 }} 631 632 void VMThread::print_counters_on(outputStream* st) { 633 if (ProfileVMOps && UsePerfData) { 634 st->print_cr("VMOperation: Total: " JLONG_FORMAT " events (elapsed " JLONG_FORMAT "ms) for thread \"main\":", 635 total_count(), total_elapsed_time_in_ms()); 636 VM_OPS_DO(PRINT_COUNTER) 637 } else { 638 st->print_cr(" VMOperations: no info (%s is disabled)", (UsePerfData ? "ProfileVMCalls" : "UsePerfData")); 639 } 640 } 641 642 #undef PRINT_COUNTER --- EOF ---