Skip to content

Commit 843f7f9

Browse files
Add support for thread cpu time in Management
1 parent e6a0104 commit 843f7f9

File tree

4 files changed

+130
-8
lines changed

4 files changed

+130
-8
lines changed

espresso/src/com.oracle.truffle.espresso.mokapot/include/jmm_common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ enum {
5454
JMM_VERSION_4 = 0x20040000, // JDK 21
5555
};
5656

57-
typedef struct {
57+
typedef struct jmmOptionalSupport {
5858
unsigned int isLowMemoryDetectionSupported : 1;
5959
unsigned int isCompilationTimeMonitoringSupported : 1;
6060
unsigned int isThreadContentionMonitoringSupported : 1;

espresso/src/com.oracle.truffle.espresso.mokapot/src/structs.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#include "jvm.h"
2525
#include "jvmti.h"
26+
#include "jmm_common.h"
2627
#include "structs.h"
2728

2829
#include <jni.h>
@@ -218,13 +219,17 @@
218219
V(_jvmtiAddrLocationMap) \
219220
V(_jvmtiEventCallbacks)
220221

222+
#define JMM_STRUCT_LIST(V) \
223+
V(jmmOptionalSupport)
224+
221225
#define MEMBER_INFO_STRUCT_LIST(V) \
222226
V(member_info)
223227

224228
#define STRUCT_LIST_LIST(V) \
225229
JNI_STRUCT_LIST(V) \
226230
JVM_STRUCT_LIST(V) \
227231
JVMTI_STRUCT_LIST(V) \
232+
JMM_STRUCT_LIST(V) \
228233
MEMBER_INFO_STRUCT_LIST(V)
229234

230235
#define STRUCT_MEMBER_LIST_LIST(V) \
@@ -233,7 +238,8 @@
233238
JVMTI_STRUCT_MEMBER_LIST(V) \
234239
MEMBER_INFO_STRUCT_MEMBER_LIST(V)
235240

236-
#define STRUCT_BITFIELD_MEMBER_LIST_LIST(V)
241+
#define STRUCT_BITFIELD_MEMBER_LIST_LIST(V) \
242+
JMM_STRUCT_BITFIELD_MEMBER_LIST(V)
237243

238244
void add_member_info(member_info** info, char* id, size_t offset) {
239245
member_info* current = malloc(sizeof(struct member_info));

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/Management.java

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.lang.management.MemoryPoolMXBean;
3232
import java.lang.management.MemoryType;
3333
import java.lang.management.MemoryUsage;
34+
import java.lang.management.ThreadMXBean;
3435
import java.nio.ByteBuffer;
3536
import java.util.Iterator;
3637
import java.util.List;
@@ -78,6 +79,7 @@
7879
import com.oracle.truffle.espresso.threads.EspressoThreadRegistry;
7980
import com.oracle.truffle.espresso.threads.State;
8081
import com.oracle.truffle.espresso.threads.ThreadAccess;
82+
import com.oracle.truffle.espresso.vm.structs.JmmOptionalSupport;
8183

8284
@GenerateNativeEnv(target = ManagementImpl.class, prependEnv = true)
8385
public final class Management extends NativeEnv {
@@ -163,6 +165,7 @@ public final class Management extends NativeEnv {
163165
private int managementVersion;
164166

165167
private MemoryMXBean memoryMXBean;
168+
private ThreadMXBean threadMXBean;
166169

167170
private final @Pointer TruffleObject initializeManagementContext;
168171
private final @Pointer TruffleObject disposeManagementContext;
@@ -190,6 +193,14 @@ private MemoryMXBean getHostMemoryMXBean() {
190193
return memoryMXBean;
191194
}
192195

196+
@TruffleBoundary
197+
private ThreadMXBean getHostThreadMXBean() {
198+
if (threadMXBean == null) {
199+
threadMXBean = ManagementFactory.getThreadMXBean();
200+
}
201+
return threadMXBean;
202+
}
203+
193204
/**
194205
* Procedure to support a new management version in Espresso:
195206
* <ul>
@@ -266,12 +277,16 @@ public int GetVersion() {
266277

267278
@ManagementImpl
268279
public int GetOptionalSupport(@Pointer TruffleObject /* jmmOptionalSupport **/ supportPtr) {
269-
if (!getUncached().isNull(supportPtr)) {
270-
ByteBuffer supportBuf = NativeUtils.directByteBuffer(supportPtr, 8);
271-
supportBuf.putInt(0); // nothing optional is supported
272-
return 0;
273-
}
274-
return -1;
280+
if (getUncached().isNull(supportPtr)) {
281+
return -1;
282+
}
283+
ByteBuffer supportBuf = NativeUtils.directByteBuffer(supportPtr, 8);
284+
supportBuf.putInt(0); // clear
285+
JmmOptionalSupport.JmmOptionalSupportWrapper optionalSupport = getVM().getStructs().jmmOptionalSupport.wrap(getHandles(), supportPtr);
286+
ThreadMXBean hostBean = getHostThreadMXBean();
287+
optionalSupport.isOtherThreadCpuTimeSupported(hostBean.isThreadCpuTimeSupported() ? 1 : 0);
288+
optionalSupport.isCurrentThreadCpuTimeSupported(hostBean.isCurrentThreadCpuTimeSupported() ? 1 : 0);
289+
return 0;
275290
}
276291

277292
private static void validateThreadIdArray(EspressoLanguage language, Meta meta, @JavaType(long[].class) StaticObject threadIds, SubstitutionProfiler profiler) {
@@ -286,6 +301,18 @@ private static void validateThreadIdArray(EspressoLanguage language, Meta meta,
286301
}
287302
}
288303

304+
private static int validateThreadIdArray(EspressoLanguage language, Meta meta, @JavaType(long[].class) StaticObject threadIds) {
305+
assert threadIds.isArray();
306+
int numThreads = threadIds.length(language);
307+
for (int i = 0; i < numThreads; ++i) {
308+
long tid = threadIds.<long[]> unwrap(language)[i];
309+
if (tid <= 0) {
310+
throw meta.throwIllegalArgumentExceptionBoundary("Invalid thread ID entry");
311+
}
312+
}
313+
return numThreads;
314+
}
315+
289316
private static void validateThreadInfoArray(Meta meta, @JavaType(internalName = "[Ljava/lang/management/ThreadInfo;") StaticObject infoArray, SubstitutionProfiler profiler) {
290317
// check if the element of infoArray is of type ThreadInfo class
291318
Klass infoArrayKlass = infoArray.getKlass();
@@ -909,5 +936,56 @@ public boolean ResetStatistic(@SuppressWarnings("unused") long obj, /* jmmStatis
909936
return false;
910937
}
911938

939+
@ManagementImpl
940+
public long GetThreadCpuTimeWithKind(long threadId, boolean withSysTime,
941+
@Inject Meta meta) {
942+
if (threadId < 0) {
943+
throw meta.throwIllegalArgumentExceptionBoundary("Invalid thread ID");
944+
}
945+
ThreadMXBean hostBean = getHostThreadMXBean();
946+
if (threadId == 0) {
947+
if (!hostBean.isCurrentThreadCpuTimeSupported()) {
948+
return -1;
949+
}
950+
long id = EspressoThreadRegistry.getThreadId(Thread.currentThread());
951+
return withSysTime ? hostBean.getThreadCpuTime(id) : hostBean.getThreadUserTime(id);
952+
}
953+
StaticObject[] activeThreads = getContext().getActiveThreads();
954+
StaticObject thread = findThreadById(activeThreads, threadId);
955+
if (getThreadAccess().isVirtualThread(thread)) {
956+
return -1;
957+
}
958+
Thread host = getThreadAccess().getHost(thread);
959+
long hostId = EspressoThreadRegistry.getThreadId(host);
960+
return withSysTime ? hostBean.getThreadCpuTime(hostId) : hostBean.getThreadUserTime(hostId);
961+
}
962+
963+
@ManagementImpl
964+
public void GetThreadCpuTimesWithKind(@JavaType(long[].class) StaticObject threadIds, @JavaType(long[].class) StaticObject times, boolean withSysTime,
965+
@Inject EspressoLanguage language, @Inject Meta meta) {
966+
if (StaticObject.isNull(threadIds) || StaticObject.isNull(times)) {
967+
throw meta.throwNullPointerExceptionBoundary();
968+
}
969+
int length = validateThreadIdArray(language, meta, threadIds);
970+
if (length != times.length(language)) {
971+
throw meta.throwIllegalArgumentExceptionBoundary("The length of the given long array does not match the length of the given array of thread IDs");
972+
}
973+
974+
StaticObject[] activeThreads = getContext().getActiveThreads();
975+
InterpreterToVM interpreterToVM = getInterpreterToVM();
976+
ThreadMXBean hostBean = getHostThreadMXBean();
977+
for (int i = 0; i < length; i++) {
978+
long guestId = interpreterToVM.getArrayLong(language, i, threadIds);
979+
StaticObject thread = findThreadById(activeThreads, guestId);
980+
if (getThreadAccess().isVirtualThread(thread)) {
981+
continue;
982+
}
983+
Thread host = getThreadAccess().getHost(thread);
984+
long hostId = EspressoThreadRegistry.getThreadId(host);
985+
long time = withSysTime ? hostBean.getThreadCpuTime(hostId) : hostBean.getThreadUserTime(hostId);
986+
interpreterToVM.setArrayLong(language, time, i, times);
987+
}
988+
}
989+
912990
// Checkstyle: resume method name check
913991
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/vm/structs/StructWrapper.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
*/
2323
package com.oracle.truffle.espresso.vm.structs;
2424

25+
import static com.oracle.truffle.espresso.ffi.NativeType.BITFIELD_INT;
2526
import static com.oracle.truffle.espresso.ffi.NativeType.BOOLEAN;
2627
import static com.oracle.truffle.espresso.ffi.NativeType.INT;
2728
import static com.oracle.truffle.espresso.ffi.NativeType.LONG;
@@ -719,6 +720,43 @@
719720
POINTER,
720721
POINTER,
721722
}),
723+
/*-
724+
* typedef struct jmmOptionalSupport {
725+
* unsigned int isLowMemoryDetectionSupported : 1;
726+
* unsigned int isCompilationTimeMonitoringSupported : 1;
727+
* unsigned int isThreadContentionMonitoringSupported : 1;
728+
* unsigned int isCurrentThreadCpuTimeSupported : 1;
729+
* unsigned int isOtherThreadCpuTimeSupported : 1;
730+
* unsigned int isObjectMonitorUsageSupported : 1;
731+
* unsigned int isSynchronizerUsageSupported : 1;
732+
* unsigned int isThreadAllocatedMemorySupported : 1;
733+
* unsigned int isRemoteDiagnosticCommandsSupported : 1;
734+
* unsigned int : 22;
735+
* } jmmOptionalSupport;
736+
*/
737+
@KnownStruct(structName = "jmmOptionalSupport", //
738+
memberNames = {
739+
"isLowMemoryDetectionSupported",
740+
"isCompilationTimeMonitoringSupported",
741+
"isThreadContentionMonitoringSupported",
742+
"isCurrentThreadCpuTimeSupported",
743+
"isOtherThreadCpuTimeSupported",
744+
"isObjectMonitorUsageSupported",
745+
"isSynchronizerUsageSupported",
746+
"isThreadAllocatedMemorySupported",
747+
"isRemoteDiagnosticCommandsSupported",
748+
}, //
749+
types = {
750+
BITFIELD_INT,
751+
BITFIELD_INT,
752+
BITFIELD_INT,
753+
BITFIELD_INT,
754+
BITFIELD_INT,
755+
BITFIELD_INT,
756+
BITFIELD_INT,
757+
BITFIELD_INT,
758+
BITFIELD_INT,
759+
}),
722760
})
723761
public abstract class StructWrapper {
724762
private final JNIHandles handles;

0 commit comments

Comments
 (0)