# HG changeset patch # Parent 651dde0ce8f93cbd6f075b9302a4b301abaa5320 # User tschatzl diff -r 651dde0ce8f9 src/os/bsd/vm/os_bsd.cpp --- a/src/os/bsd/vm/os_bsd.cpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/os/bsd/vm/os_bsd.cpp Thu Jul 17 15:10:01 2014 +0200 @@ -755,6 +755,16 @@ return 0; } +bool os::get_process_cpu_times(double* user_time, double* system_time) { + // possibly the same as with Linux... + return false; +} + +bool os::get_thread_cpu_times(const Thread* t, double* user_time, double* system_time) { + // possibly the same as with Linux... + return false; +} + bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { assert(thread->osthread() == NULL, "caller responsible"); diff -r 651dde0ce8f9 src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/os/linux/vm/os_linux.cpp Thu Jul 17 15:10:01 2014 +0200 @@ -945,6 +945,76 @@ return true; } +static bool parse_cpu_times(char* fname, double* user_time, double* system_time) { +#define BUF_LENGTH 10 * 1024 +#define UTIME_ENTRY 14 + int fd = ::open(fname, O_RDONLY); + if (fd == -1) { + return false; + } + + char buf[BUF_LENGTH]; + // read in whole file data + int n = ::read(fd, buf, BUF_LENGTH); + if (n < 0) { + ::close(fd); + return false; + } + // assume that we read the whole file; safety NUL character + buf[n-1] = '\0'; + + char *token; + char *str = buf; + char * saveptr; + + for (int i = 0; i < UTIME_ENTRY - 1; ++i, str = NULL) { + token = strtok_r(str, " ", &saveptr); + if (token == NULL) { + ::close(fd); + return false; + } + } + + token = strtok_r(str, " ", &saveptr); + unsigned long utime = atol(token); + token = strtok_r(str, " ", &saveptr); + unsigned long stime = atol(token); + + long clock_tics_per_sec = sysconf(_SC_CLK_TCK); + + *user_time = (double)utime / clock_tics_per_sec; + *system_time = (double)stime / clock_tics_per_sec; + + ::close(fd); + + return true; +#undef BUF_LENGTH +#undef UTIME_ENTRY +} + +bool os::get_process_cpu_times(double* user_time, double* system_time) { +#define BUF_LENGTH 1 * 1024 + // get name of the file we need to parse + char fname[BUF_LENGTH]; + snprintf(fname, BUF_LENGTH, "/proc/%d/stat", getpid()); + + return parse_cpu_times(fname, user_time, system_time); +#undef BUF_LENGTH +} + +bool os::get_thread_cpu_times(const Thread* t, double* user_time, double* system_time) { +#define BUF_LENGTH 1 * 1024 + if (t == NULL) { + return false; + } + // get name of the file we need to parse + char fname[BUF_LENGTH]; + snprintf(fname, BUF_LENGTH, "/proc/%d/task/%d/stat", getpid(), t->osthread()->thread_id()); + + return parse_cpu_times(fname, user_time, system_time); +#undef BUF_LENGTH +} + ///////////////////////////////////////////////////////////////////////////// // attach existing thread diff -r 651dde0ce8f9 src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/os/solaris/vm/os_solaris.cpp Thu Jul 17 15:10:01 2014 +0200 @@ -1086,6 +1086,46 @@ return true; } +bool os::get_process_cpu_times(double* user_time, double* system_time) { +#define BUF_LENGTH 10 * 1024 + + char buf[BUF_LENGTH]; + snprintf(buf, BUF_LENGTH, "/proc/%d/lwpusage", getpid()); + + int fd = ::open(buf, O_RDONLY); + if (fd == -1) { + return false; + } + + struct prusage lu; + + ::read(fd, &lu, sizeof(lu)); + ::close(fd); + + *user_time = (double)lu.pr_stime.tv_sec + (double)lu.pr_stime.tv_nsec / 1e9f; + *system_time = (double)lu.pr_utime.tv_sec + (double)lu.pr_utime.tv_nsec / 1e9f; +} + +bool os::get_thread_cpu_times(const Thread* t, double* user_time, double* system_time) { +#define BUF_LENGTH 10 * 1024 + + char buf[BUF_LENGTH]; + snprintf(buf, BUF_LENGTH, "/proc/%d/lwp/%d/lwpusage", getpid(), t->osthread()->thread_id()); + + int fd = ::open(buf, O_RDONLY); + if (fd == -1) { + return false; + } + + struct prusage lu; + + ::read(fd, &lu, sizeof(lu)); + ::close(fd); + + *user_time = (double)lu.pr_stime.tv_sec + (double)lu.pr_stime.tv_nsec / 1e9f; + *system_time = (double)lu.pr_utime.tv_sec + (double)lu.pr_utime.tv_nsec / 1e9f; +} + /* defined for >= Solaris 10. This allows builds on earlier versions * of Solaris to take advantage of the newly reserved Solaris JVM signals * With SIGJVM1, SIGJVM2, INTERRUPT_SIGNAL is SIGJVM1, ASYNC_SIGNAL is SIGJVM2 diff -r 651dde0ce8f9 src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/os/windows/vm/os_windows.cpp Thu Jul 17 15:10:01 2014 +0200 @@ -521,6 +521,34 @@ return true; } +bool os::get_process_cpu_times(double* user_time, double* system_time) { + FILETIME created; + FILETIME exited; + FILETIME kernel; + FILETIME user; + if (GetThreadTimes(GetCurrentProcess(), &created, &exited, &kernel, &user) != 0) { + *user_time = fileTimeAsDouble(&user); + *system_time = fileTimeAsDouble(&kernel); + return true; + } else { + return false; + } +} + +bool os::get_thread_cpu_times(const Thread* t, double* user_time, double* system_time) { + FILETIME created; + FILETIME exited; + FILETIME kernel; + FILETIME user; + if (GetThreadTimes(t->osthread()->thread_handle(), &created, &exited, &kernel, &user) != 0) { + *user_time = fileTimeAsDouble(&user); + *system_time = fileTimeAsDouble(&kernel); + return true; + } else { + return false; + } +} + // Allocate and initialize a new OSThread bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { unsigned thread_id; diff -r 651dde0ce8f9 src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp --- a/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp Thu Jul 17 15:10:01 2014 +0200 @@ -136,7 +136,6 @@ void ConcurrentG1Refine::print_worker_threads_on(outputStream* st) const { for (uint i = 0; i < _n_threads; ++i) { _threads[i]->print_on(st); - st->cr(); } } diff -r 651dde0ce8f9 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Jul 17 15:10:01 2014 +0200 @@ -986,9 +986,10 @@ jlong lock_time = os::elapsed_counter(); uint count_before = total_collections(); MutexLockerEx x(Heap_lock); + heap_lock_slow_allocs++; if (count_before == total_collections()) { - heap_lock_tries++; - heap_lock_time += os::elapsed_counter() - lock_time; + heap_lock_mutator_waits++; + heap_lock_mutator_wait_time += os::elapsed_counter() - lock_time; } result = _mutator_alloc_region.attempt_allocation_locked(word_size, min_word_size, @@ -1988,7 +1989,7 @@ _mark_in_progress(false), _cg1r(NULL), _summary_bytes_used(0), _g1mm(NULL), - _refine_cte_cl(NULL), heap_lock_tries(0), heap_lock_time(0), + _refine_cte_cl(NULL), heap_lock_mutator_waits(0), heap_lock_mutator_wait_time(0), heap_lock_slow_allocs(0), _full_collection(false), _free_list("Master Free List", new MasterFreeRegionListMtSafeChecker()), _secondary_free_list("Secondary Free List", new SecondaryFreeRegionListMtSafeChecker()), @@ -3661,11 +3662,14 @@ if (G1CollectedHeap::use_parallel_gc_threads()) { workers()->print_worker_threads_on(st); } + st->cr(); _cmThread->print_on(st); st->cr(); _cm->print_worker_threads_on(st); + st->cr(); _cg1r->print_worker_threads_on(st); if (G1StringDedup::is_enabled()) { + st->cr(); G1StringDedup::print_worker_threads_on(st); } } @@ -3772,8 +3776,15 @@ } void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) { - - gclog_or_tty->print_cr("heap_lock stats %1.3f tries "SIZE_FORMAT, (double)heap_lock_time * 1000.f / os::elapsed_frequency(), heap_lock_tries); + gclog_or_tty->print_cr("heap_lock stats total slow allocs "SIZE_FORMAT" mutator slow allocs "SIZE_FORMAT" mutator wait-for-lock time %1.3fms total locks "SIZE_FORMAT" total contended "SIZE_FORMAT, heap_lock_slow_allocs, heap_lock_mutator_waits, (double)heap_lock_mutator_wait_time * 1000.f / os::elapsed_frequency(), Heap_lock->lock_count, Heap_lock->contended_count); + + if (total_collections() % 50 == 0) { + double user; + double sys; + os::get_process_cpu_times(&user, &sys); + gclog_or_tty->print_cr("VM time user=%1.3f sys=%1.3f", user, sys); + Universe::heap()->print_gc_threads_on(gclog_or_tty); + } if (G1SummarizeRSetStats && (G1SummarizeRSetStatsPeriod > 0) && // we are at the end of the GC. Total collections has already been increased. @@ -4459,9 +4470,11 @@ void G1CollectedHeap::init_mutator_alloc_region() { assert(_mutator_alloc_region.get() == NULL, "pre-condition"); _mutator_alloc_region.init(); + gclog_or_tty->print_cr("init: heap_lock stats: locked "SIZE_FORMAT" contended "SIZE_FORMAT, Heap_lock->lock_count, Heap_lock->contended_count); } void G1CollectedHeap::release_mutator_alloc_region() { + gclog_or_tty->print_cr("release: heap_lock stats: locked "SIZE_FORMAT" contended "SIZE_FORMAT, Heap_lock->lock_count, Heap_lock->contended_count); _mutator_alloc_region.release(true); assert(_mutator_alloc_region.get() == NULL, "post-condition"); } diff -r 651dde0ce8f9 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Jul 17 15:10:01 2014 +0200 @@ -754,8 +754,9 @@ void enqueue_discovered_references(uint no_of_gc_workers); public: - jlong heap_lock_tries; - jlong heap_lock_time; + jlong heap_lock_mutator_waits; + jlong heap_lock_slow_allocs; + jlong heap_lock_mutator_wait_time; G1MonitoringSupport* g1mm() { assert(_g1mm != NULL, "should have been initialized"); return _g1mm; diff -r 651dde0ce8f9 src/share/vm/gc_implementation/g1/g1StringDedup.cpp --- a/src/share/vm/gc_implementation/g1/g1StringDedup.cpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/share/vm/gc_implementation/g1/g1StringDedup.cpp Thu Jul 17 15:10:01 2014 +0200 @@ -176,7 +176,6 @@ void G1StringDedup::print_worker_threads_on(outputStream* st) { assert(is_enabled(), "String deduplication not enabled"); G1StringDedupThread::thread()->print_on(st); - st->cr(); } void G1StringDedup::verify() { diff -r 651dde0ce8f9 src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp Thu Jul 17 15:10:01 2014 +0200 @@ -568,7 +568,6 @@ uint num_thr = workers(); for (uint i = 0; i < num_thr; i++) { thread(i)->print_on(st); - st->cr(); } } diff -r 651dde0ce8f9 src/share/vm/runtime/mutex.cpp --- a/src/share/vm/runtime/mutex.cpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/share/vm/runtime/mutex.cpp Thu Jul 17 15:10:01 2014 +0200 @@ -1143,6 +1143,8 @@ } void Monitor::ClearMonitor (Monitor * m, const char *name) { + m->lock_count = 0; + m->contended_count = 0; m->_owner = NULL; m->_snuck = false; if (name == NULL) { diff -r 651dde0ce8f9 src/share/vm/runtime/mutex.hpp --- a/src/share/vm/runtime/mutex.hpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/share/vm/runtime/mutex.hpp Thu Jul 17 15:10:01 2014 +0200 @@ -128,7 +128,11 @@ volatile intptr_t _WaitLock [1] ; // Protects _WaitSet ParkEvent * volatile _WaitSet ; // LL of ParkEvents volatile bool _snuck; // Used for sneaky locking (evil). - int NotifyCount ; // diagnostic assist + int NotifyCount ; // diagnostic assist +public: + size_t lock_count; + size_t contended_count; +protected: char _name[MONITOR_NAME_LEN]; // Name of mutex // Debugging fields for naming, deadlock detection, etc. (some only used in debug mode) diff -r 651dde0ce8f9 src/share/vm/runtime/mutexLocker.hpp --- a/src/share/vm/runtime/mutexLocker.hpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/share/vm/runtime/mutexLocker.hpp Thu Jul 17 15:10:01 2014 +0200 @@ -219,12 +219,15 @@ MutexLockerEx(Monitor * mutex, bool no_safepoint_check = !Mutex::_no_safepoint_check_flag) { _mutex = mutex; if (_mutex != NULL) { + bool is_locked = _mutex->is_locked(); assert(mutex->rank() > Mutex::special || no_safepoint_check, "Mutexes with rank special or lower should not do safepoint checks"); if (no_safepoint_check) _mutex->lock_without_safepoint_check(); else _mutex->lock(); + _mutex->lock_count++; + _mutex->contended_count += is_locked; } } diff -r 651dde0ce8f9 src/share/vm/runtime/os.hpp --- a/src/share/vm/runtime/os.hpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/share/vm/runtime/os.hpp Thu Jul 17 15:10:01 2014 +0200 @@ -433,6 +433,9 @@ static void initialize_thread(Thread* thr); static void free_thread(OSThread* osthread); + static bool get_process_cpu_times(double* user_time, double* system_time); + static bool get_thread_cpu_times(const Thread* t, double* user_time, double* system_time); + // thread id on Linux/64bit is 64bit, on Windows and Solaris, it's 32bit static intx current_thread_id(); static int current_process_id(); diff -r 651dde0ce8f9 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/share/vm/runtime/thread.cpp Thu Jul 17 15:10:01 2014 +0200 @@ -837,6 +837,11 @@ st->print("os_prio=%d ", os_prio); } st->print("tid=" INTPTR_FORMAT " ", this); + double user_time; + double system_time; + if (os::get_thread_cpu_times(this, &user_time, &system_time)) { + st->print("user=%1.3f sys=%1.3f ", user_time, system_time); + } osthread()->print_on(st); } debug_only(if (WizardMode) print_owned_locks_on(st);) diff -r 651dde0ce8f9 src/share/vm/runtime/vm_operations.cpp --- a/src/share/vm/runtime/vm_operations.cpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/share/vm/runtime/vm_operations.cpp Thu Jul 17 15:10:01 2014 +0200 @@ -432,6 +432,15 @@ } void VM_Exit::doit() { + + { + double user; + double sys; + os::get_process_cpu_times(&user, &sys); + gclog_or_tty->print_cr("VM time user=%1.3f sys=%1.3f", user, sys); + Universe::heap()->print_gc_threads_on(gclog_or_tty); + } + CompileBroker::set_should_block(); // Wait for a short period for threads in native to block. Any thread diff -r 651dde0ce8f9 src/share/vm/utilities/workgroup.cpp --- a/src/share/vm/utilities/workgroup.cpp Thu Jul 17 14:49:42 2014 +0200 +++ b/src/share/vm/utilities/workgroup.cpp Thu Jul 17 15:10:01 2014 +0200 @@ -218,7 +218,6 @@ uint num_thr = total_workers(); for (uint i = 0; i < num_thr; i++) { gang_worker(i)->print_on(st); - st->cr(); } }