Skip to content

Commit

Permalink
Get the process start time
Browse files Browse the repository at this point in the history
Get the process start time on linux, windows, osx, aix and
z/os.

Issue: #7201
Signed-off-by: Amarpreet Singh <[email protected]>
  • Loading branch information
singh264 committed Jan 4, 2024
1 parent 3a47874 commit d5b70ec
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 0 deletions.
61 changes: 61 additions & 0 deletions fvtest/porttest/si.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,30 @@
#include <sched.h>
#include <fstream>
#include <regex>
#include <sys/wait.h>
#include <unistd.h>
#endif /* defined(LINUX) */
#if defined(OMR_OS_WINDOWS)
#include <direct.h>
#include <windows.h>
#endif /* defined(OMR_OS_WINDOWS) */
#if !defined(OMR_OS_WINDOWS)
#include <grp.h>
#include <errno.h>
#if defined(J9ZOS390)
#include <limits.h>
#include <sys/wait.h>
#include <unistd.h>
#else
#define __STDC_LIMIT_MACROS
#include <stdint.h> /* For INT64_MAX. */
#endif /* defined(J9ZOS390) */
#include <sys/resource.h> /* For RLIM_INFINITY */
#endif /* !defined(OMR_OS_WINDOWS) */
#if defined(OSX) || defined(AIXPPC)
#include <sys/wait.h>
#include <unistd.h>
#endif /* defined(LINUX) */

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

/**
* Test GetProcessorStartTimeOfNonExistingProcessTest.
*/
TEST(PortSysinfoTest, GetProcessorStartTimeOfNonExistingProcessTest)
{
OMRPORT_ACCESS_FROM_OMRPORT(portTestEnv->getPortLibrary());
uintptr_t pid = UINTPTR_MAX;
uint64_t expectedProcessStartTimeInNanoseconds = 0;
uint64_t actualProcessStartTimeInNanoseconds = omrsysinfo_get_process_start_time(pid);
ASSERT_EQ(expectedProcessStartTimeInNanoseconds, actualProcessStartTimeInNanoseconds);
}

/**
* Test GetProcessorStartTimeOfExistingProcessTest.
*/
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;
#if defined(LINUX) || defined(OSX) || defined(AIXPPC) || defined(J9ZOS390)
int status = 0;
sleep(3);
pid = fork();
ASSERT_NE(pid, -1);
if (0 == pid) {
sleep(10);
exit(0);
}
processStartTimeInNanoseconds = omrsysinfo_get_process_start_time(pid);
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);
processStartTimeInNanoseconds = omrsysinfo_get_process_start_time(pid);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
#endif /* defined(LINUX) || defined(OSX) || defined(AIXPPC) || defined(J9ZOS390) */
ASSERT_GT(processStartTimeInNanoseconds, testStartTimeInNanoseconds);
ASSERT_LT(processStartTimeInNanoseconds, omrtime_current_time_nanos(&success));
}
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"*/
uint64_t (*sysinfo_get_process_start_time)(struct OMRPortLibrary *portLibrary, uintptr_t pid);
/** 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) privateOmrPortLibrary->sysinfo_get_process_start_time(privateOmrPortLibrary, param1)
#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
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
12 changes: 12 additions & 0 deletions port/common/omrsysinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -1178,3 +1178,15 @@ 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.
* @return 0 if the process does not exist, process start time in ns precision epoch time if the process exists.
*/
uint64_t
omrsysinfo_get_process_start_time(struct OMRPortLibrary *portLibrary, uintptr_t pid)
{
return 0;
}
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 uint64_t
omrsysinfo_get_process_start_time(struct OMRPortLibrary *portLibrary, uintptr_t pid);

/* J9SourceJ9Signal*/
extern J9_CFUNC int32_t
Expand Down
100 changes: 100 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 "omrintrospect.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 @@ -641,6 +643,25 @@ static int32_t retrieveOSXMemoryStats(struct OMRPortLibrary *portLibrary, struct
static int32_t retrieveAIXMemoryStats(struct OMRPortLibrary *portLibrary, struct J9MemoryInfo *memInfo);
#endif

#if defined(LINUX) || defined(OSX) || defined(AIXPPC) || defined(J9ZOS390)
#define NANOSECONDS_PER_SECOND 1000000000ULL
#endif /* defined(LINUX) || defined(OSX) || defined(AIXPPC) || defined(J9ZOS390) */

#if defined(LINUX)
#define PROC_DIR_BUFFER_SIZE 256
#define STAT_FAILURE -1
#endif /* defined(LINUX) */

#if defined(OSX)
#define NUM_SYSCTL_ARGS 4
#define SYSCTL_FAILURE -1
#define NANOSECONDS_PER_MICROSECOND 1000ULL
#endif /* defined(OSX) */

#if defined(J9ZOS390)
#define I32MAXVAL 0x7FFFFFFF
#endif /* defined(J9ZOS390) */

/**
* @internal
* Determines the proper portable error code to return given a native error code
Expand Down Expand Up @@ -7354,3 +7375,82 @@ get_Dispatch_IstreamCount(void) {
return (uintptr_t)numberOfIStreams;
}
#endif /* defined(OMRZTPF) */

/**
* Get the process start time in ns precision epoch time.
* @param[in] portLibrary The port library.
* @param[in] pid The process id.
* @return 0 if the process does not exist, process start time in ns precision epoch time if the process exists.
*/
uint64_t
omrsysinfo_get_process_start_time(struct OMRPortLibrary *portLibrary, uintptr_t pid)
{
uint64_t processStartTimeInNanoseconds = 0;
if (omrsysinfo_process_exists(portLibrary, pid)) {
#if defined(LINUX)
char procDir[PROC_DIR_BUFFER_SIZE] = {0};
struct stat st;
snprintf(procDir, sizeof(procDir), "/proc/%" PRIuPTR, pid);
if (stat(procDir, &st) == STAT_FAILURE) {
perror("stat");
goto done;
}
processStartTimeInNanoseconds = (uint64_t)st.st_mtime * NANOSECONDS_PER_SECOND + st.st_mtim.tv_nsec;
#elif defined(OSX) /* defined(LINUX) */
int mib[NUM_SYSCTL_ARGS] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
size_t len = sizeof(struct kinfo_proc);
struct kinfo_proc procInfo;
if (sysctl(mib, NUM_SYSCTL_ARGS, &procInfo, &len, NULL, 0) == SYSCTL_FAILURE) {
perror("sysctl");
goto done;
}
if (0 == len) {
perror("pid does not exist");
goto done;
}
processStartTimeInNanoseconds =
((uint64_t)procInfo.kp_proc.p_starttime.tv_sec * NANOSECONDS_PER_SECOND) +
((uint64_t)procInfo.kp_proc.p_starttime.tv_usec * 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) {
perror("getprocs");
goto done;
} else if (0 == ret) {
perror("pid does not exist");
goto done;
}
processStartTimeInNanoseconds = (uint64_t)(procInfos[0].pi_start) * NANOSECONDS_PER_SECOND;
#elif defined(J9ZOS390) /* defined(AIXPPC) */
struct pgtha pgtha;
struct j9pg_thread_data threadData;
struct pgthc *pgthc = NULL;
unsigned int dataOffset = 0;
int inputSize = sizeof(struct pgtha);
struct pgtha *input = &pgtha;
int outputSize = sizeof(struct j9pg_thread_data);
unsigned char *output = (unsigned char *)&threadData;
int ret = 0;
int retCode = 0;
int reasonCode = 0;
memset(input, 0, sizeof(pgtha));
memset(output, 0, sizeof(threadData));
pgtha.pid = (pid_t)pid;
pgtha.accesspid = PGTHA_ACCESS_CURRENT;
pgtha.flag1 = PGTHA_FLAG_PROCESS_DATA;
getthent_os(&inputSize, &input, &outputSize, (void **)&output, &ret, &retCode, &reasonCode);
if (-1 == ret) {
fprintf(stderr, "getthent_os\n");
goto done;
}
dataOffset = *((unsigned int *)threadData.pgthb.offc);
dataOffset = (dataOffset & I32MAXVAL) >> 8;
pgthc = (struct pgthc *)(((char *)&threadData) + dataOffset);
processStartTimeInNanoseconds = (uint64_t)pgthc->starttime * NANOSECONDS_PER_SECOND;
#endif /* defined(LINUX) */
}
done:
return processStartTimeInNanoseconds;
}
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 WINDOWS_TICK 10000000ULL
#define SEC_TO_UNIX_EPOCH 11644473600ULL
#define 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;
}

/**
* Get the process start time of a process in ns precision epoch time.
* @param[in] portLibrary The port library.
* @param[in] pid The process id.
* @return 0 if the process does not exist, process start time in ns precision epoch time if the process exists.
*/
uint64_t
omrsysinfo_get_process_start_time(struct OMRPortLibrary *portLibrary, uintptr_t pid)
{
uint64_t processStartTimeInNanoseconds = 0;
if (omrsysinfo_process_exists(portLibrary, pid)) {
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pid);
FILETIME createTime, exitTime, kernelTime, userTime;
double seconds = 0;
if (NULL == process) {
fprintf(stderr, "error opening process\n");
goto done;
}
if (!GetProcessTimes(process, &createTime, &exitTime, &kernelTime, &userTime)) {
fprintf(stderr, "error getting process times\n");
goto cleanup;
}
seconds = (double)(*(LONGLONG*)&(createTime)) / WINDOWS_TICK;
processStartTimeInNanoseconds = (uint64_t)((seconds - SEC_TO_UNIX_EPOCH) * NS100_PER_SEC);
processStartTimeInNanoseconds *= 100;
cleanup:
CloseHandle(process);
}
done:
return processStartTimeInNanoseconds;
}
11 changes: 11 additions & 0 deletions port/zos390/omrintrospect.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@
#include "omrutil.h"

#pragma linkage(getthent, OS_UPSTACK)
#pragma linkage(getthent_os, OS)
#if defined(OMR_ENV_DATA64)
#pragma map(getthent, "BPX4GTH")
#pragma map(getthent_os, "BPX4GTH")
#else
#pragma map(getthent, "BPX1GTH")
#pragma map(getthent_os, "BPX1GTH")
#endif

#pragma linkage(pthread_quiesce, OS_UPSTACK)
Expand Down Expand Up @@ -779,6 +782,14 @@ struct tcb {
#define QUIESCE_SRB 9 /* Quiesce threads type = SRBs @DGA */
/* Skip 10 and 11 due to collision with BPXZCONS Freeze/Unfreeze Fast */

void getthent_os(int *inputSize, struct pgtha **input, int *outputSize, void **output, int *ret, int *retCode, int *reasonCode);

struct j9pg_thread_data {
struct pgthb pgthb;
struct pgthj pgthj;
char padding[256];
};

#pragma pack(reset)

#endif

0 comments on commit d5b70ec

Please sign in to comment.