Mercurial > hg > truffle
comparison src/share/vm/services/management.cpp @ 2100:b1a2afa37ec4
7003271: Hotspot should track cumulative Java heap bytes allocated on a per-thread basis
Summary: Track allocated bytes in Thread's, update on TLAB retirement and direct allocation in Eden and tenured, add JNI methods for ThreadMXBean.
Reviewed-by: coleenp, kvn, dholmes, ysr
author | phh |
---|---|
date | Fri, 07 Jan 2011 10:42:32 -0500 |
parents | f95d63e2154a |
children | 3582bf76420e |
comparison
equal
deleted
inserted
replaced
2097:039eb4201e06 | 2100:b1a2afa37ec4 |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. | 2 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | 4 * |
5 * This code is free software; you can redistribute it and/or modify it | 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 | 6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
99 _optional_support.isOtherThreadCpuTimeSupported = 1; | 99 _optional_support.isOtherThreadCpuTimeSupported = 1; |
100 } else { | 100 } else { |
101 _optional_support.isCurrentThreadCpuTimeSupported = 0; | 101 _optional_support.isCurrentThreadCpuTimeSupported = 0; |
102 _optional_support.isOtherThreadCpuTimeSupported = 0; | 102 _optional_support.isOtherThreadCpuTimeSupported = 0; |
103 } | 103 } |
104 | |
104 _optional_support.isBootClassPathSupported = 1; | 105 _optional_support.isBootClassPathSupported = 1; |
105 _optional_support.isObjectMonitorUsageSupported = 1; | 106 _optional_support.isObjectMonitorUsageSupported = 1; |
106 #ifndef SERVICES_KERNEL | 107 #ifndef SERVICES_KERNEL |
107 // This depends on the heap inspector | 108 // This depends on the heap inspector |
108 _optional_support.isSynchronizerUsageSupported = 1; | 109 _optional_support.isSynchronizerUsageSupported = 1; |
109 #endif // SERVICES_KERNEL | 110 #endif // SERVICES_KERNEL |
111 _optional_support.isThreadAllocatedMemorySupported = 1; | |
110 } | 112 } |
111 | 113 |
112 void Management::initialize(TRAPS) { | 114 void Management::initialize(TRAPS) { |
113 // Start the low memory detector thread | 115 // Start the low memory detector thread |
114 LowMemoryDetector::initialize(); | 116 LowMemoryDetector::initialize(); |
384 return MemoryService::get_memory_pool(ph); | 386 return MemoryService::get_memory_pool(ph); |
385 } | 387 } |
386 | 388 |
387 static void validate_thread_id_array(typeArrayHandle ids_ah, TRAPS) { | 389 static void validate_thread_id_array(typeArrayHandle ids_ah, TRAPS) { |
388 int num_threads = ids_ah->length(); | 390 int num_threads = ids_ah->length(); |
389 // should be non-empty array | |
390 if (num_threads == 0) { | |
391 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), | |
392 "Empty array of thread IDs"); | |
393 } | |
394 | 391 |
395 // Validate input thread IDs | 392 // Validate input thread IDs |
396 int i = 0; | 393 int i = 0; |
397 for (i = 0; i < num_threads; i++) { | 394 for (i = 0; i < num_threads; i++) { |
398 jlong tid = ids_ah->long_at(i); | 395 jlong tid = ids_ah->long_at(i); |
400 // throw exception if invalid thread id. | 397 // throw exception if invalid thread id. |
401 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), | 398 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
402 "Invalid thread ID entry"); | 399 "Invalid thread ID entry"); |
403 } | 400 } |
404 } | 401 } |
405 | |
406 } | 402 } |
407 | 403 |
408 static void validate_thread_info_array(objArrayHandle infoArray_h, TRAPS) { | 404 static void validate_thread_info_array(objArrayHandle infoArray_h, TRAPS) { |
409 | |
410 // check if the element of infoArray is of type ThreadInfo class | 405 // check if the element of infoArray is of type ThreadInfo class |
411 klassOop threadinfo_klass = Management::java_lang_management_ThreadInfo_klass(CHECK); | 406 klassOop threadinfo_klass = Management::java_lang_management_ThreadInfo_klass(CHECK); |
412 klassOop element_klass = objArrayKlass::cast(infoArray_h->klass())->element_klass(); | 407 klassOop element_klass = objArrayKlass::cast(infoArray_h->klass())->element_klass(); |
413 if (element_klass != threadinfo_klass) { | 408 if (element_klass != threadinfo_klass) { |
414 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), | 409 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), |
415 "infoArray element type is not ThreadInfo class"); | 410 "infoArray element type is not ThreadInfo class"); |
416 } | 411 } |
417 | |
418 } | 412 } |
419 | 413 |
420 | 414 |
421 static MemoryManager* get_memory_manager_from_jobject(jobject obj, TRAPS) { | 415 static MemoryManager* get_memory_manager_from_jobject(jobject obj, TRAPS) { |
422 if (obj == NULL) { | 416 if (obj == NULL) { |
768 LowMemoryDetector::detect_low_memory(pool); | 762 LowMemoryDetector::detect_low_memory(pool); |
769 } | 763 } |
770 return prev; | 764 return prev; |
771 JVM_END | 765 JVM_END |
772 | 766 |
767 // Gets an array containing the amount of memory allocated on the Java | |
768 // heap for a set of threads (in bytes). Each element of the array is | |
769 // the amount of memory allocated for the thread ID specified in the | |
770 // corresponding entry in the given array of thread IDs; or -1 if the | |
771 // thread does not exist or has terminated. | |
772 JVM_ENTRY(void, jmm_GetThreadAllocatedMemory(JNIEnv *env, jlongArray ids, | |
773 jlongArray sizeArray)) | |
774 // Check if threads is null | |
775 if (ids == NULL || sizeArray == NULL) { | |
776 THROW(vmSymbols::java_lang_NullPointerException()); | |
777 } | |
778 | |
779 ResourceMark rm(THREAD); | |
780 typeArrayOop ta = typeArrayOop(JNIHandles::resolve_non_null(ids)); | |
781 typeArrayHandle ids_ah(THREAD, ta); | |
782 | |
783 typeArrayOop sa = typeArrayOop(JNIHandles::resolve_non_null(sizeArray)); | |
784 typeArrayHandle sizeArray_h(THREAD, sa); | |
785 | |
786 // validate the thread id array | |
787 validate_thread_id_array(ids_ah, CHECK); | |
788 | |
789 // sizeArray must be of the same length as the given array of thread IDs | |
790 int num_threads = ids_ah->length(); | |
791 if (num_threads != sizeArray_h->length()) { | |
792 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), | |
793 "The length of the given long array does not match the length of " | |
794 "the given array of thread IDs"); | |
795 } | |
796 | |
797 MutexLockerEx ml(Threads_lock); | |
798 for (int i = 0; i < num_threads; i++) { | |
799 JavaThread* java_thread = find_java_thread_from_id(ids_ah->long_at(i)); | |
800 if (java_thread != NULL) { | |
801 sizeArray_h->long_at_put(i, java_thread->cooked_allocated_bytes()); | |
802 } | |
803 } | |
804 JVM_END | |
805 | |
773 // Returns a java/lang/management/MemoryUsage object representing | 806 // Returns a java/lang/management/MemoryUsage object representing |
774 // the memory usage for the heap or non-heap memory. | 807 // the memory usage for the heap or non-heap memory. |
775 JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap)) | 808 JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap)) |
776 ResourceMark rm(THREAD); | 809 ResourceMark rm(THREAD); |
777 | 810 |
832 return ClassLoadingService::get_verbose(); | 865 return ClassLoadingService::get_verbose(); |
833 case JMM_THREAD_CONTENTION_MONITORING: | 866 case JMM_THREAD_CONTENTION_MONITORING: |
834 return ThreadService::is_thread_monitoring_contention(); | 867 return ThreadService::is_thread_monitoring_contention(); |
835 case JMM_THREAD_CPU_TIME: | 868 case JMM_THREAD_CPU_TIME: |
836 return ThreadService::is_thread_cpu_time_enabled(); | 869 return ThreadService::is_thread_cpu_time_enabled(); |
870 case JMM_THREAD_ALLOCATED_MEMORY: | |
871 return ThreadService::is_thread_allocated_memory_enabled(); | |
837 default: | 872 default: |
838 assert(0, "Unrecognized attribute"); | 873 assert(0, "Unrecognized attribute"); |
839 return false; | 874 return false; |
840 } | 875 } |
841 JVM_END | 876 JVM_END |
849 return ClassLoadingService::set_verbose(flag != 0); | 884 return ClassLoadingService::set_verbose(flag != 0); |
850 case JMM_THREAD_CONTENTION_MONITORING: | 885 case JMM_THREAD_CONTENTION_MONITORING: |
851 return ThreadService::set_thread_monitoring_contention(flag != 0); | 886 return ThreadService::set_thread_monitoring_contention(flag != 0); |
852 case JMM_THREAD_CPU_TIME: | 887 case JMM_THREAD_CPU_TIME: |
853 return ThreadService::set_thread_cpu_time_enabled(flag != 0); | 888 return ThreadService::set_thread_cpu_time_enabled(flag != 0); |
889 case JMM_THREAD_ALLOCATED_MEMORY: | |
890 return ThreadService::set_thread_allocated_memory_enabled(flag != 0); | |
854 default: | 891 default: |
855 assert(0, "Unrecognized attribute"); | 892 assert(0, "Unrecognized attribute"); |
856 return false; | 893 return false; |
857 } | 894 } |
858 JVM_END | 895 JVM_END |
1094 // maxDepth - the maximum depth of stack traces to be dumped: | 1131 // maxDepth - the maximum depth of stack traces to be dumped: |
1095 // maxDepth == -1 requests to dump entire stack trace. | 1132 // maxDepth == -1 requests to dump entire stack trace. |
1096 // maxDepth == 0 requests no stack trace. | 1133 // maxDepth == 0 requests no stack trace. |
1097 // infoArray - array of ThreadInfo objects | 1134 // infoArray - array of ThreadInfo objects |
1098 // | 1135 // |
1136 // QQQ - Why does this method return a value instead of void? | |
1099 JVM_ENTRY(jint, jmm_GetThreadInfo(JNIEnv *env, jlongArray ids, jint maxDepth, jobjectArray infoArray)) | 1137 JVM_ENTRY(jint, jmm_GetThreadInfo(JNIEnv *env, jlongArray ids, jint maxDepth, jobjectArray infoArray)) |
1100 // Check if threads is null | 1138 // Check if threads is null |
1101 if (ids == NULL || infoArray == NULL) { | 1139 if (ids == NULL || infoArray == NULL) { |
1102 THROW_(vmSymbols::java_lang_NullPointerException(), -1); | 1140 THROW_(vmSymbols::java_lang_NullPointerException(), -1); |
1103 } | 1141 } |
1157 dump_result.add_thread_snapshot(ts); | 1195 dump_result.add_thread_snapshot(ts); |
1158 } | 1196 } |
1159 } | 1197 } |
1160 } else { | 1198 } else { |
1161 // obtain thread dump with the specific list of threads with stack trace | 1199 // obtain thread dump with the specific list of threads with stack trace |
1162 | |
1163 do_thread_dump(&dump_result, | 1200 do_thread_dump(&dump_result, |
1164 ids_ah, | 1201 ids_ah, |
1165 num_threads, | 1202 num_threads, |
1166 maxDepth, | 1203 maxDepth, |
1167 false, /* no locked monitor */ | 1204 false, /* no locked monitor */ |
1249 if (ts->threadObj() == NULL) { | 1286 if (ts->threadObj() == NULL) { |
1250 // if the thread does not exist or now it is terminated, set threadinfo to NULL | 1287 // if the thread does not exist or now it is terminated, set threadinfo to NULL |
1251 result_h->obj_at_put(index, NULL); | 1288 result_h->obj_at_put(index, NULL); |
1252 continue; | 1289 continue; |
1253 } | 1290 } |
1254 | |
1255 | |
1256 | 1291 |
1257 ThreadStackTrace* stacktrace = ts->get_stack_trace(); | 1292 ThreadStackTrace* stacktrace = ts->get_stack_trace(); |
1258 assert(stacktrace != NULL, "Must have a stack trace dumped"); | 1293 assert(stacktrace != NULL, "Must have a stack trace dumped"); |
1259 | 1294 |
1260 // Create Object[] filled with locked monitors | 1295 // Create Object[] filled with locked monitors |
1496 if (java_thread != NULL) { | 1531 if (java_thread != NULL) { |
1497 return os::thread_cpu_time((Thread*) java_thread, user_sys_cpu_time != 0); | 1532 return os::thread_cpu_time((Thread*) java_thread, user_sys_cpu_time != 0); |
1498 } | 1533 } |
1499 } | 1534 } |
1500 return -1; | 1535 return -1; |
1536 JVM_END | |
1537 | |
1538 // Gets an array containing the CPU times consumed by a set of threads | |
1539 // (in nanoseconds). Each element of the array is the CPU time for the | |
1540 // thread ID specified in the corresponding entry in the given array | |
1541 // of thread IDs; or -1 if the thread does not exist or has terminated. | |
1542 // If user_sys_cpu_time = true, the sum of user level and system CPU time | |
1543 // for the given thread is returned; otherwise, only user level CPU time | |
1544 // is returned. | |
1545 JVM_ENTRY(void, jmm_GetThreadCpuTimesWithKind(JNIEnv *env, jlongArray ids, | |
1546 jlongArray timeArray, | |
1547 jboolean user_sys_cpu_time)) | |
1548 // Check if threads is null | |
1549 if (ids == NULL || timeArray == NULL) { | |
1550 THROW(vmSymbols::java_lang_NullPointerException()); | |
1551 } | |
1552 | |
1553 ResourceMark rm(THREAD); | |
1554 typeArrayOop ta = typeArrayOop(JNIHandles::resolve_non_null(ids)); | |
1555 typeArrayHandle ids_ah(THREAD, ta); | |
1556 | |
1557 typeArrayOop tia = typeArrayOop(JNIHandles::resolve_non_null(timeArray)); | |
1558 typeArrayHandle timeArray_h(THREAD, tia); | |
1559 | |
1560 // validate the thread id array | |
1561 validate_thread_id_array(ids_ah, CHECK); | |
1562 | |
1563 // timeArray must be of the same length as the given array of thread IDs | |
1564 int num_threads = ids_ah->length(); | |
1565 if (num_threads != timeArray_h->length()) { | |
1566 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), | |
1567 "The length of the given long array does not match the length of " | |
1568 "the given array of thread IDs"); | |
1569 } | |
1570 | |
1571 MutexLockerEx ml(Threads_lock); | |
1572 for (int i = 0; i < num_threads; i++) { | |
1573 JavaThread* java_thread = find_java_thread_from_id(ids_ah->long_at(i)); | |
1574 if (java_thread != NULL) { | |
1575 timeArray_h->long_at_put(i, os::thread_cpu_time((Thread*)java_thread, | |
1576 user_sys_cpu_time != 0)); | |
1577 } | |
1578 } | |
1501 JVM_END | 1579 JVM_END |
1502 | 1580 |
1503 // Returns a String array of all VM global flag names | 1581 // Returns a String array of all VM global flag names |
1504 JVM_ENTRY(jobjectArray, jmm_GetVMGlobalNames(JNIEnv *env)) | 1582 JVM_ENTRY(jobjectArray, jmm_GetVMGlobalNames(JNIEnv *env)) |
1505 // last flag entry is always NULL, so subtract 1 | 1583 // last flag entry is always NULL, so subtract 1 |
2018 jmm_GetInputArgumentArray, | 2096 jmm_GetInputArgumentArray, |
2019 jmm_GetMemoryPools, | 2097 jmm_GetMemoryPools, |
2020 jmm_GetMemoryManagers, | 2098 jmm_GetMemoryManagers, |
2021 jmm_GetMemoryPoolUsage, | 2099 jmm_GetMemoryPoolUsage, |
2022 jmm_GetPeakMemoryPoolUsage, | 2100 jmm_GetPeakMemoryPoolUsage, |
2023 NULL, | 2101 jmm_GetThreadAllocatedMemory, |
2024 jmm_GetMemoryUsage, | 2102 jmm_GetMemoryUsage, |
2025 jmm_GetLongAttribute, | 2103 jmm_GetLongAttribute, |
2026 jmm_GetBoolAttribute, | 2104 jmm_GetBoolAttribute, |
2027 jmm_SetBoolAttribute, | 2105 jmm_SetBoolAttribute, |
2028 jmm_GetLongAttributes, | 2106 jmm_GetLongAttributes, |
2036 jmm_SetPoolThreshold, | 2114 jmm_SetPoolThreshold, |
2037 jmm_GetPoolCollectionUsage, | 2115 jmm_GetPoolCollectionUsage, |
2038 jmm_GetGCExtAttributeInfo, | 2116 jmm_GetGCExtAttributeInfo, |
2039 jmm_GetLastGCStat, | 2117 jmm_GetLastGCStat, |
2040 jmm_GetThreadCpuTimeWithKind, | 2118 jmm_GetThreadCpuTimeWithKind, |
2041 NULL, | 2119 jmm_GetThreadCpuTimesWithKind, |
2042 jmm_DumpHeap0, | 2120 jmm_DumpHeap0, |
2043 jmm_FindDeadlockedThreads, | 2121 jmm_FindDeadlockedThreads, |
2044 jmm_SetVMGlobal, | 2122 jmm_SetVMGlobal, |
2045 NULL, | 2123 NULL, |
2046 jmm_DumpThreads | 2124 jmm_DumpThreads |