1 /* 2 * Copyright (c) 2014, 2015, Dynatrace and/or its affiliates. All rights reserved. 3 * 4 * This file is part of the Lock Contention Tracing Subsystem for the HotSpot 5 * Virtual Machine, which is developed at Christian Doppler Laboratory on 6 * Monitoring and Evolution of Very-Large-Scale Software Systems. Please 7 * contact us at <http://mevss.jku.at/> if you need additional information 8 * or have any questions. 9 * 10 * This code is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License version 2 only, as 12 * published by the Free Software Foundation. 13 * 14 * This code is distributed in the hope that it will be useful, but WITHOUT 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17 * version 2 for more details (a copy is included in the LICENSE file that 18 * accompanied this code). 19 * 20 * You should have received a copy of the GNU General Public License version 21 * 2 along with this work. If not, see <http://www.gnu.org/licenses/>. 22 * 23 */ 24 25 #include "evtrace/traceManager.hpp" 26 27 #include "evtrace/traceBuffer.hpp" 28 #include "evtrace/traceBufferQueue.hpp" 29 #include "evtrace/traceReaderThread.hpp" 30 #include "evtrace/traceEvents.hpp" 31 32 #include "runtime/javaCalls.hpp" 33 #include "runtime/thread.hpp" 34 35 volatile bool TraceManager::_is_initialized = false; 36 TraceReaderThread *TraceManager::_thread = NULL; 37 Monitor *TraceManager::_thread_mtx = NULL; 38 volatile bool TraceManager::_thread_running = false; 39 TraceBufferQueue *TraceManager::_flush_queue = NULL; 40 TraceBufferQueue *TraceManager::_free_queue = NULL; 41 TraceMetadata *TraceManager::_metadata = NULL; 42 bool TraceManager::_classes_unloaded_in_current_safepoint = false; 43 DEBUG_ONLY(int TraceManager::_current_safepoint_counter); 44 45 // statistics 46 volatile intptr_t TraceManager::_buffer_count = 0xdead; 47 volatile intptr_t TraceManager::_max_buffer_count = 0xdead; 48 volatile intptr_t TraceManager::_allocated_buffer_count = 0xdead; 49 volatile intptr_t TraceManager::_submitted_trace_bytes = 0xdead; 50 intptr_t TraceManager::_reclaimed_trace_bytes = 0xdead; 51 volatile intptr_t TraceManager::_reclaim_time_nanos = 0xdead; 52 intptr_t TraceManager::_stored_free_enqueue_ops = 0xdead; 53 intptr_t TraceManager::_stored_free_dequeue_ops = 0xdead; 54 intptr_t TraceManager::_stored_flush_enqueue_ops = 0xdead; 55 intptr_t TraceManager::_stored_flush_dequeue_ops = 0xdead; 56 volatile intptr_t TraceManager::_total_stack_traces = 0xdead; 57 volatile intptr_t TraceManager::_truncated_stack_traces = 0xdead; 58 volatile intptr_t TraceManager::_reused_memento_stack_traces = 0xdead; 59 volatile intptr_t TraceManager::_total_stack_frames = 0xdead; 60 volatile intptr_t TraceManager::_reused_memento_stack_frames = 0xdead; 61 62 void TraceManager::initialize() { 63 assert(!_is_initialized, "already initialized"); 64 assert(_flush_queue == NULL, "flush queue exists"); 65 assert(_free_queue == NULL, "free queue exists"); 66 assert(_thread == NULL, "thread exists"); 67 assert(!_thread_running, "thread running"); 68 assert(_metadata == NULL, "metadata exists"); 69 assert(!_classes_unloaded_in_current_safepoint, "must be unset"); 70 71 // nothing should be allocated before this point 72 // NOTE: requires -XX:NativeMemoryTracking=summary or =detail 73 assert(MallocMemorySummary::as_snapshot()->by_type(mtEventTracing)->malloc_size() == 0, "premature event tracing allocations"); 74 75 guarantee(EventTracingStackDepthLimit <= TRACE_STACK_MAX_FRAMES, "stack depth limit is too high"); 76 if (EventTracingStackDepthLimit == 0) { 77 EnableEventTracingStackTraces = false; 78 } 79 80 TraceEvents::initialize(); 81 82 _metadata = new TraceMetadata(); 83 84 _thread_mtx = new Monitor(Mutex::nonleaf + 1, "TraceManager::_thread_mtx"); 85 86 _buffer_count = 0; 87 _flush_queue = new TraceBufferQueue(); 88 89 if (EnableEventTracingBufferReuse) { 90 _free_queue = new TraceBufferQueue(); 91 92 for (uintx i = 0; i < EventTracingPreallocatedBuffers; i++) { 93 _free_queue->enqueue(allocate_buffer()); 94 } 95 assert((jlong)_free_queue->count() == (jlong) EventTracingPreallocatedBuffers, "sanity"); 96 } 97 98 _is_initialized = true; 99 100 reset_stats(); 101 } 102 103 Handle TraceManager::create_queue_object(TraceBufferQueue *q, instanceKlassHandle klass, TRAPS) { 104 JavaValue result(T_OBJECT); 105 result.set_jobject(NULL); 106 if (q != NULL) { 107 JavaCallArguments args; 108 args.push_long((jlong) q); 109 JavaCalls::call_static(&result, 110 klass, 111 vmSymbols::TraceBufferQueue_from_handle_method_name(), 112 vmSymbols::TraceBufferQueue_from_handle_method_signature(), 113 &args, 114 CHECK_NH); 115 } 116 return Handle(THREAD, (oop) result.get_jobject()); 117 } 118 119 void TraceManager::start_threads(TRAPS) { 120 assert(_thread == NULL && !_thread_running, "trace reader thread exists"); 121 122 Klass* qk = SystemDictionary::resolve_or_fail(vmSymbols::sun_evtracing_TraceBufferQueue(), true, CHECK); 123 instanceKlassHandle q_klass(THREAD, qk); 124 q_klass->initialize(CHECK); 125 126 Handle flushq = create_queue_object(_flush_queue, q_klass, CHECK); 127 Handle freeq = create_queue_object(_free_queue, q_klass, CHECK); 128 129 _thread = TraceReaderThread::start(flushq(), freeq(), THREAD); 130 _thread_running = true; 131 } 132 133 class TraceManager::ReclaimTraceBuffersClosure : public ThreadClosure { 134 bool _deinitialize; 135 jlong _reclaimed_bytes; 136 137 public: 138 ReclaimTraceBuffersClosure(bool deinit) 139 : _deinitialize(deinit), _reclaimed_bytes(0) 140 { 141 } 142 143 ~ReclaimTraceBuffersClosure() { } 144 145 virtual void do_thread(Thread *t) { 146 assert(t != NULL, "null thread"); 147 148 TraceBuffer *buffer = t->trace_buffer(); 149 if (buffer != NULL && (_deinitialize || buffer->filled_size() > 0)) { 150 TraceManager::pre_submit_buffer(buffer); 151 _reclaimed_bytes += buffer->filled_size(); 152 TraceManager::_flush_queue->enqueue(buffer); 153 154 buffer = NULL; 155 if (!_deinitialize && EnableEventTracingBufferReuse) { 156 buffer = TraceManager::_free_queue->try_dequeue(); 157 if (buffer != NULL) { 158 buffer->owner = t; 159 } 160 } 161 t->set_trace_buffer(buffer); 162 } 163 } 164 165 jlong reclaimed_bytes() { return _reclaimed_bytes; } 166 }; 167 168 class TraceManager::VM_ReclaimTraceBuffers : public VM_Operation { 169 bool _deinitialize; 170 jlong _queue_fill_mark; 171 172 public: 173 VM_ReclaimTraceBuffers(bool deinit) : _deinitialize(deinit) {} 174 VMOp_Type type() const { return VMOp_ReclaimTraceBuffers; } 175 void doit(); 176 177 jlong queue_fill_mark() { return _queue_fill_mark; } 178 }; 179 180 void TraceManager::VM_ReclaimTraceBuffers::doit() { 181 assert(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread(), "sanity"); 182 183 if (_deinitialize) { 184 TraceEvents::write_vm_end(); 185 186 // stop threads from acquiring buffers 187 TraceManager::_is_initialized = false; 188 } 189 190 TraceManager::ReclaimTraceBuffersClosure cl(_deinitialize); 191 Threads::threads_do(&cl); 192 193 _queue_fill_mark = TraceManager::_flush_queue->fill_mark(); 194 TraceManager::_reclaimed_trace_bytes += cl.reclaimed_bytes(); 195 196 if (_thread != NULL && _thread->is_polling_queue()) { 197 // reader thread is sleeping in poll loop, interrupt 198 199 // we don't want to interrupt the thread elsewhere, for example during 200 // NIO channel operations, when an interrupt shuts down the channel 201 Thread::interrupt(_thread); 202 } 203 } 204 205 void TraceManager::reclaim_buffers_in_safepoint(bool wait_until_processed) { 206 assert_initialized(); 207 208 jlong reclaim_start = os::javaTimeNanos(); 209 210 jlong fill_mark = do_reclaim_buffers_in_safepoint(false); 211 212 if (wait_until_processed) { 213 // NOTE: this doesn't actually wait until the last buffer has been 214 // *processed*, only until the reader thread has *dequeued* 215 // the last reclaimed buffer (usually when the second-to-last 216 // buffer has been processed) 217 while (!_flush_queue->has_dequeued_at_mark(fill_mark)) { 218 os::sleep(Thread::current(), 1, true); 219 } 220 } 221 222 if (EnableEventTracingDiagnostics) { 223 // FIXME: counter value depends on whether callers set wait_until_processed 224 jlong duration = os::javaTimeNanos() - reclaim_start; 225 Atomic::add_ptr(duration, &_reclaim_time_nanos); 226 } 227 } 228 229 jlong TraceManager::do_reclaim_buffers_in_safepoint(bool deinit) { 230 VM_ReclaimTraceBuffers op(deinit); 231 VMThread::execute(&op); 232 233 return op.queue_fill_mark(); 234 } 235 236 class TraceManager::VM_ResetTraceMetadata : public VM_Operation { 237 public: 238 VM_ResetTraceMetadata() {} 239 VMOp_Type type() const { return VMOp_ResetTraceMetadata; } 240 void doit(); 241 bool allow_nested_vm_operations() const { return true; } 242 }; 243 244 void TraceManager::VM_ResetTraceMetadata::doit() { 245 assert(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread(), "sanity"); 246 247 VM_ReclaimTraceBuffers reclaim_op(false); 248 VMThread::execute(&reclaim_op); 249 250 if (_thread != NULL && _thread->is_polling_queue() && _thread->trace_buffer() != NULL) { 251 // The ReclaimTraceBuffers VM op has interrupted the reader thread, which 252 // generated a ThreadInterrupt event containing a sequence number. 253 // Therefore, this event must be submitted before the metadata reset event. 254 255 submit_buffer(Thread::current()->trace_buffer()); 256 Thread::current()->set_trace_buffer(NULL); 257 } 258 259 TraceManager::_metadata->purge_all(); 260 261 TraceEvents::write_metadata_reset(); 262 if (Thread::current()->trace_buffer() != NULL) { 263 submit_buffer(Thread::current()->trace_buffer()); 264 Thread::current()->set_trace_buffer(NULL); 265 } 266 } 267 268 void TraceManager::reset_metadata() { 269 VM_ResetTraceMetadata op; 270 VMThread::execute(&op); 271 } 272 273 void TraceManager::nmethod_is_unloading(const nmethod *nm) { 274 if (_is_initialized) { 275 _metadata->purge_unloading_nmethod(nm); 276 } 277 } 278 279 void TraceManager::class_loader_is_unloading(ClassLoaderData *loader) { 280 assert(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread(), "sanity"); 281 282 if (!_is_initialized) 283 return; 284 285 // When classes and methods are unloaded during garbage collection, their 286 // memory is reclaimed and other classes and methods can be loaded in their 287 // place. Since we use addresses as unique identifiers, we need to observe 288 // such unload events and purge any references to unloaded metadata from 289 // our records. 290 // 291 // Trace analysis must also be aware of unloads as well since any trace 292 // events after an unload can use the same identifiers to refer to different 293 // data. Therefore, we reclaim the trace buffers from all threads at this 294 // point. We then write one or multiple unload events to the trace buffer of 295 // the VM thread, and finally enqueue that buffer before the end of the 296 // safepoint. Therefore, when processing the buffers in the order in which 297 // they are enqueued, trace analysis encounters the necessary unload events 298 // before any events after the unload. 299 300 if (!_classes_unloaded_in_current_safepoint) { 301 // G1 doesn't allow nested VM ops 302 VM_ReclaimTraceBuffers(false).doit(); 303 _classes_unloaded_in_current_safepoint = true; 304 DEBUG_ONLY(_current_safepoint_counter = SafepointSynchronize::_safepoint_counter); 305 } else { 306 assert(_current_safepoint_counter == SafepointSynchronize::_safepoint_counter, "different safepoint"); 307 } 308 309 TraceEvents::write_class_loader_unload(loader); 310 311 _metadata->purge_unloading_classes(loader); 312 } 313 314 void TraceManager::do_work_before_safepoint_end() { 315 assert(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread(), "sanity"); 316 317 if (_is_initialized) { 318 VM_ReclaimTraceBuffers(false).doit(); // don't bother with VM op 319 320 if (_classes_unloaded_in_current_safepoint) { 321 assert(_current_safepoint_counter == SafepointSynchronize::_safepoint_counter, "different safepoint"); 322 _classes_unloaded_in_current_safepoint = false; 323 } 324 325 _metadata->do_maintenance(); 326 } 327 } 328 329 void TraceManager::thread_is_exiting(TraceReaderThread* t) { 330 guarantee(!_is_initialized, "thread exiting prematurely"); 331 guarantee(t == _thread, "unexpected thread"); 332 guarantee(_thread_running, "not running?"); 333 334 MonitorLockerEx ml(_thread_mtx); 335 _thread_running = false; 336 ml.notify_all(); 337 } 338 339 void TraceManager::finish_and_destroy(TRAPS) { 340 assert_initialized(); 341 assert(_thread != NULL, "thread not initialized"); 342 343 jlong reclaim_start = os::javaTimeNanos(); 344 345 // This just sets a flag that the reader thread only checks once queue 346 // operations fail after the reclaim op 347 _thread->shutdown(CHECK); 348 349 _thread_mtx->lock(); 350 351 do_reclaim_buffers_in_safepoint(true); 352 353 while(_thread_running) { 354 _thread_mtx->wait(); // wait for trace reader thread to call back 355 } 356 _thread_mtx->unlock(); 357 delete _thread_mtx; 358 _thread_mtx = NULL; 359 _thread = NULL; // NOTE: thread deletes itself on exit 360 361 if (EnableEventTracingDiagnostics) { 362 _reclaim_time_nanos += (os::javaTimeNanos() - reclaim_start); 363 } 364 365 // We keep these around to provide statistics to agents after deinitialization (during shutdown) 366 // FIXME: we should fill a single TraceStatistics object instead of all those variables 367 if (EnableEventTracingBufferReuse) { 368 _stored_free_enqueue_ops = _free_queue->enqueue_ops() - _stored_free_enqueue_ops; 369 _stored_free_dequeue_ops = _free_queue->dequeue_ops() - _stored_free_dequeue_ops; 370 } 371 _stored_flush_enqueue_ops = _flush_queue->enqueue_ops() - _stored_flush_enqueue_ops; 372 _stored_flush_dequeue_ops = _flush_queue->dequeue_ops() - _stored_flush_dequeue_ops; 373 374 assert(_flush_queue->is_empty(), "flush queue not empty"); 375 delete _flush_queue; 376 _flush_queue = NULL; 377 378 if (EnableEventTracingBufferReuse) { 379 while (!_free_queue->is_empty()) { 380 TraceBuffer *buffer = _free_queue->try_dequeue(); 381 assert(buffer != NULL, "null buffer from non-empty queue"); 382 free_buffer(buffer); 383 } 384 delete _free_queue; 385 _free_queue = NULL; 386 } 387 assert(_free_queue == NULL, "sanity"); 388 389 delete _metadata; 390 _metadata = NULL; 391 392 // all event tracing memory must be deallocated here 393 // NOTE: requires -XX:NativeMemoryTracking=summary or =detail 394 assert(MallocMemorySummary::as_snapshot()->by_type(mtEventTracing)->malloc_size() == 0, "memory leak"); 395 } 396 397 void TraceManager::write_stats(TraceStatistics *stats) { 398 assert(!_is_initialized || _flush_queue != NULL, "sanity"); 399 400 if (EnableEventTracingBufferReuse) { 401 jlong free_enqueue_ops, free_dequeue_ops; 402 free_enqueue_ops = _is_initialized ? _free_queue->enqueue_ops() - _stored_free_enqueue_ops : _stored_free_enqueue_ops; 403 free_dequeue_ops = _is_initialized ? _free_queue->dequeue_ops() - _stored_free_dequeue_ops : _stored_free_dequeue_ops; 404 stats->add_entry("free_enqueue_ops", free_enqueue_ops); 405 stats->add_entry("free_dequeue_ops", free_dequeue_ops); 406 } 407 408 jlong flush_enqueue_ops, flush_dequeue_ops; 409 flush_enqueue_ops = _is_initialized ? _flush_queue->enqueue_ops() - _stored_flush_enqueue_ops : _stored_flush_enqueue_ops; 410 flush_dequeue_ops = _is_initialized ? _flush_queue->dequeue_ops() - _stored_flush_dequeue_ops : _stored_flush_dequeue_ops; 411 stats->add_entry("flush_enqueue_ops", flush_enqueue_ops); 412 stats->add_entry("flush_dequeue_ops", flush_dequeue_ops); 413 414 stats->add_entry("mean_buffer_capacity", EventTracingBufferCapacity); 415 stats->add_entry("reclaimed_trace_bytes", _reclaimed_trace_bytes); 416 417 if (EnableEventTracingDiagnostics) { 418 stats->add_entry("submitted_trace_bytes", _submitted_trace_bytes); 419 stats->add_entry("reclaim_time_nanos", _reclaim_time_nanos); 420 stats->add_entry("stack_cache_lookups", _metadata->stack_cache_lookups()); 421 stats->add_entry("stack_cache_lookup_misses", _metadata->stack_cache_lookup_misses()); 422 stats->add_entry("stack_cache_lookup_collisions", _metadata->stack_cache_lookup_collisions()); 423 stats->add_entry("stack_cache_probes", _metadata->stack_cache_probes()); 424 stats->add_entry("stack_cache_probe_collisions", _metadata->stack_cache_probe_collisions()); 425 stats->add_entry("stack_cache_purge_millis", _metadata->stack_cache_purge_millis()); 426 stats->add_entry("stack_cache_maintenance_millis", _metadata->stack_cache_maintenance_millis()); 427 stats->add_entry("total_stack_traces", _total_stack_traces); 428 stats->add_entry("truncated_stack_traces", _truncated_stack_traces); 429 stats->add_entry("reused_memento_stack_traces", _reused_memento_stack_traces); 430 stats->add_entry("total_stack_frames", _total_stack_frames); 431 stats->add_entry("reused_memento_stack_frames", _reused_memento_stack_frames); 432 stats->add_entry("buffer_count", _buffer_count); 433 stats->add_entry("max_buffer_count", _max_buffer_count); 434 stats->add_entry("allocated_buffer_count", _allocated_buffer_count); 435 } 436 } 437 438 void TraceManager::reset_stats() { 439 assert(!_is_initialized || _flush_queue != NULL, "sanity"); 440 441 if (_is_initialized) { 442 if (EnableEventTracingBufferReuse) { 443 _stored_free_enqueue_ops = _free_queue->enqueue_ops(); 444 _stored_free_dequeue_ops = _free_queue->dequeue_ops(); 445 } 446 447 _stored_flush_enqueue_ops = _flush_queue->enqueue_ops(); 448 _stored_flush_dequeue_ops = _flush_queue->dequeue_ops(); 449 } 450 451 _reclaimed_trace_bytes = 0; 452 453 if (EnableEventTracingDiagnostics) { 454 _submitted_trace_bytes = 0; 455 _reclaim_time_nanos = 0; 456 _total_stack_traces = 0; 457 _truncated_stack_traces = 0; 458 _reused_memento_stack_traces = 0; 459 _total_stack_frames = 0; 460 _reused_memento_stack_frames = 0; 461 _max_buffer_count = _buffer_count; 462 _allocated_buffer_count = 0; 463 464 _metadata->reset_stack_cache_stats(); 465 } 466 }