Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get the process start time #7214

Merged
merged 1 commit into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions fvtest/porttest/si.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@
#endif /* defined(J9ZOS390) */
#include <sys/resource.h> /* For RLIM_INFINITY */
#endif /* !defined(OMR_OS_WINDOWS) */
#if defined(OMR_OS_WINDOWS)
#include <windows.h>
#else /* defined(OMR_OS_WINDOWS) */
#include <sys/wait.h>
#include <unistd.h>
singh264 marked this conversation as resolved.
Show resolved Hide resolved
#endif /* defined(OMR_OS_WINDOWS) */

#if defined(J9ZOS390) && !defined(OMR_EBCDIC)
#include "atoe.h"
Expand Down Expand Up @@ -3119,3 +3125,75 @@ TEST(PortSysinfoTest, GetProcessorDescription)
ASSERT_TRUE(feature == TRUE || feature == FALSE);
}
}

/* The method omrsysinfo_get_process_start_time is not implemented on z/TPF. */
#if !defined(OMRZTPF)
/**
* Test: GetProcessorStartTimeOfNonExistingProcessTest.
* Description: Verify that getting the process start time for a non-existing process (UINTPTR_MAX) results in 0 nanoseconds.
* Passing Condition: The expected process start time is 0 nanoseconds, and the actual process start time matches this value.
*/
TEST(PortSysinfoTest, GetProcessorStartTimeOfNonExistingProcessTest)
singh264 marked this conversation as resolved.
Show resolved Hide resolved
{
OMRPORT_ACCESS_FROM_OMRPORT(portTestEnv->getPortLibrary());
/*
* If a pid of UINTPTR_MAX exists in the future then the test will need to be modified.
* UINTPTR_MAX represents the maximum unsigned integer value, which can be a 32-bit or a 64-bit depending on the system.
* On unix systems, a pid is represented by pid_t, which can be a 32-bit or a 64-bit signed integer.
* On windows systems, a pid is represented by DWORD, which is a 32-bit unsigned integer, and
* the maximum value of DWORD is not a valid pid as it is reserved for use by the ASFW_ANY parameter.
*/
uintptr_t pid = UINTPTR_MAX;
singh264 marked this conversation as resolved.
Show resolved Hide resolved
uint64_t expectedProcessStartTimeInNanoseconds = 0;
uint64_t actualProcessStartTimeInNanoseconds = 0;
int32_t rc = omrsysinfo_get_process_start_time(pid, &actualProcessStartTimeInNanoseconds);
ASSERT_LT(rc, 0);
ASSERT_EQ(expectedProcessStartTimeInNanoseconds, actualProcessStartTimeInNanoseconds);
}

/**
* Test: GetProcessorStartTimeOfExistingProcessTest.
* Description: Verify that getting the process start time for an existing process results in a valid timestamp.
* Passing Condition: The process start time is greater than the test start time and less than the current time at the end of the test.
*/
TEST(PortSysinfoTest, GetProcessorStartTimeOfExistingProcessTest)
{
OMRPORT_ACCESS_FROM_OMRPORT(portTestEnv->getPortLibrary());
uintptr_t pid = UINTPTR_MAX;
uintptr_t success = 0;
uint64_t testStartTimeInNanoseconds = omrtime_current_time_nanos(&success);
uint64_t processStartTimeInNanoseconds = 0;
int32_t rc = 0;
#if defined(LINUX) || defined(OSX) || defined(AIXPPC) || defined(J9ZOS390)
int status = 0;
sleep(3);
pid = fork();
ASSERT_NE(pid, -1);
/* The if block will only be invoked by the child process. */
if (0 == pid) {
sleep(10);
/* A call to exit allows the child process to stop and avoids a timeout on x86-64 macOS. */
exit(0);
}
rc = omrsysinfo_get_process_start_time(pid, &processStartTimeInNanoseconds);
waitpid(pid, &status, 0);
#elif defined(OMR_OS_WINDOWS) /* defined(LINUX) || defined(OSX) || defined(AIXPPC) || defined(J9ZOS390) */
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL ret = FALSE;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
ret = CreateProcess(NULL, "cmd.exe /c timeout /t 10", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
ASSERT_EQ(ret, TRUE);
pid = (uintptr_t)GetProcessId(pi.hProcess);
rc = omrsysinfo_get_process_start_time(pid, &processStartTimeInNanoseconds);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
#endif /* defined(LINUX) || defined(OSX) || defined(AIXPPC) || defined(J9ZOS390) */
ASSERT_EQ(rc, 0);
ASSERT_GT(processStartTimeInNanoseconds, testStartTimeInNanoseconds);
ASSERT_LT(processStartTimeInNanoseconds, omrtime_current_time_nanos(&success));
singh264 marked this conversation as resolved.
Show resolved Hide resolved
}
#endif /* !defined(OMRZTPF) */
3 changes: 3 additions & 0 deletions include_core/omrport.h
Original file line number Diff line number Diff line change
Expand Up @@ -2459,6 +2459,8 @@ typedef struct OMRPortLibrary {
int32_t (*sysinfo_cgroup_subsystem_iterator_next)(struct OMRPortLibrary *portLibrary, struct OMRCgroupMetricIteratorState *state, struct OMRCgroupMetricElement *metricElement);
/** see @ref omrsysinfo.c::omrsysinfo_cgroup_subsystem_iterator_destroy "omrsysinfo_cgroup_subsystem_iterator_destroy"*/
void (*sysinfo_cgroup_subsystem_iterator_destroy)(struct OMRPortLibrary *portLibrary, struct OMRCgroupMetricIteratorState *state);
/** see @ref omrsysinfo.c::omrsysinfo_get_process_start_time "omrsysinfo_get_process_start_time"*/
int32_t (*sysinfo_get_process_start_time)(struct OMRPortLibrary *portLibrary, uintptr_t pid, uint64_t *processStartTimeInNanoseconds);
/** see @ref omrport.c::omrport_init_library "omrport_init_library"*/
int32_t (*port_init_library)(struct OMRPortLibrary *portLibrary, uintptr_t size) ;
/** see @ref omrport.c::omrport_startup_library "omrport_startup_library"*/
Expand Down Expand Up @@ -3102,6 +3104,7 @@ extern J9_CFUNC int32_t omrport_getVersion(struct OMRPortLibrary *portLibrary);
#define omrsysinfo_cgroup_subsystem_iterator_metricKey(param1, param2) privateOmrPortLibrary->sysinfo_cgroup_subsystem_iterator_metricKey(privateOmrPortLibrary, param1, param2)
#define omrsysinfo_cgroup_subsystem_iterator_next(param1, param2) privateOmrPortLibrary->sysinfo_cgroup_subsystem_iterator_next(privateOmrPortLibrary, param1, param2)
#define omrsysinfo_cgroup_subsystem_iterator_destroy(param1) privateOmrPortLibrary->sysinfo_cgroup_subsystem_iterator_destroy(privateOmrPortLibrary, param1)
#define omrsysinfo_get_process_start_time(param1, param2) privateOmrPortLibrary->sysinfo_get_process_start_time(privateOmrPortLibrary, param1, param2)
#define omrintrospect_startup() privateOmrPortLibrary->introspect_startup(privateOmrPortLibrary)
#define omrintrospect_shutdown() privateOmrPortLibrary->introspect_shutdown(privateOmrPortLibrary)
#define omrintrospect_set_suspend_signal_offset(param1) privateOmrPortLibrary->introspect_set_suspend_signal_offset(privateOmrPortLibrary, param1)
Expand Down
2 changes: 2 additions & 0 deletions include_core/omrporterror.h
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,8 @@
#define OMRPORT_ERROR_SYSINFO_CGROUP_NULL_PARAM (OMRPORT_ERROR_SYSINFO_BASE-30)
#define OMRPORT_ERROR_SYSINFO_ERROR_SWAPPINESS_OPEN_FAILED (OMRPORT_ERROR_SYSINFO_BASE-31)
#define OMRPORT_ERROR_SYSINFO_ERROR_READING_SWAPPINESS (OMRPORT_ERROR_SYSINFO_BASE-32)
#define OMRPORT_ERROR_SYSINFO_NONEXISTING_PROCESS (OMRPORT_ERROR_SYSINFO_BASE-33)
#define OMRPORT_ERROR_SYSINFO_ERROR_GETTING_PROCESS_START_TIME (OMRPORT_ERROR_SYSINFO_BASE-34)

/**
* @name Port library initialization return codes
Expand Down
1 change: 1 addition & 0 deletions port/common/omrport.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ static OMRPortLibrary MainPortLibraryTable = {
omrsysinfo_cgroup_subsystem_iterator_metricKey, /* sysinfo_cgroup_subsystem_iterator_metricKey */
omrsysinfo_cgroup_subsystem_iterator_next, /* sysinfo_cgroup_subsystem_iterator_next */
omrsysinfo_cgroup_subsystem_iterator_destroy, /* sysinfo_cgroup_subsystem_iterator_destroy */
omrsysinfo_get_process_start_time, /* sysinfo_get_process_start_time */
omrport_init_library, /* port_init_library */
omrport_startup_library, /* port_startup_library */
omrport_create_library, /* port_create_library */
Expand Down
3 changes: 3 additions & 0 deletions port/common/omrport.tdf
Original file line number Diff line number Diff line change
Expand Up @@ -1630,3 +1630,6 @@ TraceEvent=Trc_PRT_sl_open_shared_library_noload Group=sl Overhead=1 Level=3 NoE
TraceException=Trc_PRT_retrieveLinuxMemoryStats_failedOpeningSwappinessFs Group=sysinfo Overhead=1 Level=1 NoEnv Template="retrieveLinuxMemoryStats: Failed to open /proc/sys/vm/swappiness. Error code = %d."
TraceException=Trc_PRT_retrieveLinuxMemoryStats_failedReadingSwappiness Group=sysinfo Overhead=1 Level=1 NoEnv Template="retrieveLinuxMemoryStats: Failed to read /proc/sys/vm/swappiness. Error code = %d."
TraceException=Trc_PRT_retrieveLinuxMemoryStats_unexpectedSwappinessFormat Group=sysinfo Overhead=1 Level=1 NoEnv Template="retrieveLinuxMemoryStats: Expected %d items to read, but read %d items."

TraceEntry=Trc_PRT_sysinfo_get_process_start_time_enter Group=sysinfo Overhead=1 Level=1 NoEnv Template="Enter omrsysinfo_get_process_start_time, pid=%llu."
TraceExit=Trc_PRT_sysinfo_get_process_start_time_exit Group=sysinfo Overhead=1 Level=1 NoEnv Template="Exit omrsysinfo_get_process_start_time, pid=%llu, processStartTimeInNanoseconds=%llu, rc=%d."
singh264 marked this conversation as resolved.
Show resolved Hide resolved
13 changes: 13 additions & 0 deletions port/common/omrsysinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -1178,3 +1178,16 @@ omrsysinfo_cgroup_subsystem_iterator_destroy(struct OMRPortLibrary *portLibrary,
{
return;
}

/**
* Get the process start time in ns precision epoch time.
* @param[in] portLibrary The port library
* @param[in] pid The process ID
* @param[in/out] processStartTimeInNanoseconds The pointer to uint64_t that stores the process start time in ns precision epoch time
* @return 0 on success, error code on failure
*/
int32_t
omrsysinfo_get_process_start_time(struct OMRPortLibrary *portLibrary, uintptr_t pid, uint64_t *processStartTimeInNanoseconds)
{
return OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM;
}
2 changes: 2 additions & 0 deletions port/omrportpriv.h
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,8 @@ extern J9_CFUNC int32_t
omrsysinfo_cgroup_subsystem_iterator_next(struct OMRPortLibrary *portLibrary, struct OMRCgroupMetricIteratorState *state, struct OMRCgroupMetricElement *metricElement);
extern J9_CFUNC void
omrsysinfo_cgroup_subsystem_iterator_destroy(struct OMRPortLibrary *portLibrary, struct OMRCgroupMetricIteratorState *state);
extern J9_CFUNC int32_t
omrsysinfo_get_process_start_time(struct OMRPortLibrary *portLibrary, uintptr_t pid, uint64_t *processStartTimeInNanoseconds);

/* J9SourceJ9Signal*/
extern J9_CFUNC int32_t
Expand Down
104 changes: 104 additions & 0 deletions port/unix/omrsysinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@


#if defined(J9ZOS390)
#include "omrgetthent.h"
#include "omrsimap.h"
#endif /* defined(J9ZOS390) */

Expand All @@ -95,6 +96,7 @@

#if defined(AIXPPC)
#include <fcntl.h>
#include <procinfo.h>
#include <sys/procfs.h>
#include <sys/systemcfg.h>
#endif /* defined(AIXPPC) */
Expand Down Expand Up @@ -195,6 +197,14 @@ uintptr_t Get_Number_Of_CPUs();
#define JIFFIES 100
#define USECS_PER_SEC 1000000
#define TICKS_TO_USEC ((uint64_t)(USECS_PER_SEC/JIFFIES))
#define OMRPORT_SYSINFO_PROC_DIR_BUFFER_SIZE 256
#define OMRPORT_SYSINFO_NUM_SYSCTL_ARGS 4
#define OMRPORT_SYSINFO_NANOSECONDS_PER_MICROSECOND 1000ULL
#if defined(_LP64)
#define GETTHENT BPX4GTH
#else /* defined(_LP64) */
#define GETTHENT BPX1GTH
#endif /* defined(_LP64) */

static uintptr_t copyEnvToBuffer(struct OMRPortLibrary *portLibrary, void *args);
static uintptr_t copyEnvToBufferSignalHandler(struct OMRPortLibrary *portLib, uint32_t gpType, void *gpInfo, void *unUsed);
Expand Down Expand Up @@ -598,6 +608,19 @@ static intptr_t searchSystemPath(struct OMRPortLibrary *portLibrary, char *filen
#if defined(J9ZOS390)
static void setOSFeature(struct OMROSDesc *desc, uint32_t feature);
static intptr_t getZOSDescription(struct OMRPortLibrary *portLibrary, struct OMROSDesc *desc);
#if defined(_LP64)
#pragma linkage(BPX4GTH,OS)
#else /* defined(_LP64) */
#pragma linkage(BPX1GTH,OS)
#endif /* defined(_LP64) */
void GETTHENT(
unsigned int *inputSize,
unsigned char **input,
unsigned int *outputSize,
unsigned char **output,
unsigned int *ret,
unsigned int *retCode,
unsigned int *reasonCode);
#endif /* defined(J9ZOS390) */

#if !defined(RS6000) && !defined(J9ZOS390) && !defined(OSX) && !defined(OMRZTPF)
Expand Down Expand Up @@ -7354,3 +7377,84 @@ get_Dispatch_IstreamCount(void) {
return (uintptr_t)numberOfIStreams;
}
#endif /* defined(OMRZTPF) */

int32_t
omrsysinfo_get_process_start_time(struct OMRPortLibrary *portLibrary, uintptr_t pid, uint64_t *processStartTimeInNanoseconds)
{
int32_t rc = 0;
uint64_t computedProcessStartTimeInNanoseconds = 0;
Trc_PRT_sysinfo_get_process_start_time_enter((unsigned long long)pid);
if (0 != omrsysinfo_process_exists(portLibrary, pid)) {
#if defined(LINUX)
char procDir[OMRPORT_SYSINFO_PROC_DIR_BUFFER_SIZE] = {0};
struct stat st;
snprintf(procDir, sizeof(procDir), "/proc/%" PRIuPTR, pid);
if (-1 == stat(procDir, &st)) {
rc = OMRPORT_ERROR_SYSINFO_ERROR_GETTING_PROCESS_START_TIME;
goto done;
}
computedProcessStartTimeInNanoseconds = (uint64_t)st.st_mtime * OMRPORT_TIME_DELTA_IN_NANOSECONDS + st.st_mtim.tv_nsec;
#elif defined(OSX) /* defined(LINUX) */
int mib[OMRPORT_SYSINFO_NUM_SYSCTL_ARGS] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
size_t len = sizeof(struct kinfo_proc);
struct kinfo_proc procInfo;
if (-1 == sysctl(mib, OMRPORT_SYSINFO_NUM_SYSCTL_ARGS, &procInfo, &len, NULL, 0)) {
rc = OMRPORT_ERROR_SYSINFO_ERROR_GETTING_PROCESS_START_TIME;
goto done;
}
if (0 == len) {
rc = OMRPORT_ERROR_SYSINFO_NONEXISTING_PROCESS;
goto done;
}
computedProcessStartTimeInNanoseconds =
((uint64_t)procInfo.kp_proc.p_starttime.tv_sec * OMRPORT_TIME_DELTA_IN_NANOSECONDS) +
((uint64_t)procInfo.kp_proc.p_starttime.tv_usec * OMRPORT_SYSINFO_NANOSECONDS_PER_MICROSECOND);
#elif defined(AIXPPC) /* defined(OSX) */
pid_t convertedPid = (pid_t)pid;
struct procsinfo procInfos[] = {0};
int ret = getprocs(procInfos, sizeof(procInfos[0]), NULL, 0, &convertedPid, sizeof(procInfos) / sizeof(procInfos[0]));
if (-1 == ret) {
rc = OMRPORT_ERROR_SYSINFO_ERROR_GETTING_PROCESS_START_TIME;
goto done;
} else if (0 == ret) {
rc = OMRPORT_ERROR_SYSINFO_NONEXISTING_PROCESS;
goto done;
}
computedProcessStartTimeInNanoseconds = (uint64_t)(procInfos[0].pi_start) * OMRPORT_TIME_DELTA_IN_NANOSECONDS;
#elif defined(J9ZOS390) /* defined(AIXPPC) */
pgtha pgtha;
ProcessData processData;
pgthc *currentProcessInfo = NULL;
uint32_t dataOffset = 0;
uint32_t inputSize = sizeof(pgtha);
unsigned char *input = (unsigned char *)&pgtha;
uint32_t outputSize = sizeof(ProcessData);
unsigned char *output = (unsigned char *)&processData;
uint32_t ret = 0;
uint32_t retCode = 0;
uint32_t reasonCode = 0;
memset(input, 0, sizeof(pgtha));
memset(output, 0, sizeof(processData));
pgtha.pid = pid;
pgtha.accesspid = PGTHA_ACCESS_CURRENT;
pgtha.flag1 = PGTHA_FLAG_PROCESS_DATA;
GETTHENT(&inputSize, &input, &outputSize, &output, &ret, &retCode, &reasonCode);
if (-1 == ret) {
rc = OMRPORT_ERROR_SYSINFO_ERROR_GETTING_PROCESS_START_TIME;
goto done;
}
dataOffset = *((unsigned int *)processData.pgthb.offc);
dataOffset = (dataOffset & I_32_MAX) >> 8;
currentProcessInfo = (pgthc *)(((char *)&processData) + dataOffset);
computedProcessStartTimeInNanoseconds = (uint64_t)currentProcessInfo->starttime * OMRPORT_TIME_DELTA_IN_NANOSECONDS;
#else /* defined(J9ZOS390) */
rc = OMRPORT_ERROR_NOT_SUPPORTED_ON_THIS_PLATFORM;
#endif /* defined(LINUX) */
singh264 marked this conversation as resolved.
Show resolved Hide resolved
singh264 marked this conversation as resolved.
Show resolved Hide resolved
} else {
rc = OMRPORT_ERROR_SYSINFO_NONEXISTING_PROCESS;
}
done:
*processStartTimeInNanoseconds = computedProcessStartTimeInNanoseconds;
Trc_PRT_sysinfo_get_process_start_time_exit((unsigned long long)pid, (unsigned long long)computedProcessStartTimeInNanoseconds, rc);
return rc;
}
35 changes: 35 additions & 0 deletions port/win32/omrsysinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
#include "ut_omrport.h"
#include "omrsysinfo_helpers.h"

#define OMRPORT_SYSINFO_WINDOWS_TICK 10000000ULL
#define OMRPORT_SYSINFO_SEC_TO_UNIX_EPOCH 11644473600ULL
#define OMRPORT_SYSINFO_NS100_PER_SEC 10000000ULL

static int32_t copyEnvToBuffer(struct OMRPortLibrary *portLibrary, void *args);

typedef struct CopyEnvToBufferArgs {
Expand Down Expand Up @@ -1990,3 +1994,34 @@ omrsysinfo_cgroup_subsystem_iterator_destroy(struct OMRPortLibrary *portLibrary,
return;
}

int32_t
omrsysinfo_get_process_start_time(struct OMRPortLibrary *portLibrary, uintptr_t pid, uint64_t *processStartTimeInNanoseconds)
{
int32_t rc = 0;
uint64_t computedProcessStartTimeInNanoseconds = 0;
Trc_PRT_sysinfo_get_process_start_time_enter((unsigned long long)pid);
if (0 != omrsysinfo_process_exists(portLibrary, pid)) {
double seconds = 0;
FILETIME createTime, exitTime, kernelTime, userTime;
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
if (NULL == process) {
rc = OMRPORT_ERROR_SYSINFO_NONEXISTING_PROCESS;
goto done;
}
if (!GetProcessTimes(process, &createTime, &exitTime, &kernelTime, &userTime)) {
rc = OMRPORT_ERROR_SYSINFO_ERROR_GETTING_PROCESS_START_TIME;
goto cleanup;
}
seconds = (double)(*(LONGLONG *)&(createTime)) / OMRPORT_SYSINFO_WINDOWS_TICK;
computedProcessStartTimeInNanoseconds = (uint64_t)((seconds - OMRPORT_SYSINFO_SEC_TO_UNIX_EPOCH) * OMRPORT_SYSINFO_NS100_PER_SEC);
computedProcessStartTimeInNanoseconds *= 100;
cleanup:
CloseHandle(process);
} else {
rc = OMRPORT_ERROR_SYSINFO_NONEXISTING_PROCESS;
}
done:
*processStartTimeInNanoseconds = computedProcessStartTimeInNanoseconds;
Trc_PRT_sysinfo_get_process_start_time_exit((unsigned long long)pid, (unsigned long long)computedProcessStartTimeInNanoseconds, rc);
return rc;
}
Loading
Loading