Commit 115b3df1 authored by Ian Lynagh's avatar Ian Lynagh
Browse files

Merge branch 'master' of mac:ghc/git/val32/.

parents 0f51b3eb d6905920
......@@ -141,9 +141,10 @@
#define EVENT_SPARK_FIZZLE 40 /* () */
#define EVENT_SPARK_GC 41 /* () */
#define EVENT_INTERN_STRING 42 /* (string, id) {not used by ghc} */
#define EVENT_WALL_CLOCK_TIME 43 /* (capset, unix_epoch_seconds, nanoseconds) */
/* Range 43 - 59 is available for new GHC and common events */
/* Range 44 - 59 is available for new GHC and common events */
/* Range 60 - 80 is used by eden for parallel tracing
* see http://www.mathematik.uni-marburg.de/~eden/
......@@ -156,7 +157,7 @@
* ranges higher than this are reserved but not currently emitted by ghc.
* This must match the size of the EventDesc[] array in EventLog.c
*/
#define NUM_GHC_EVENT_TAGS 42
#define NUM_GHC_EVENT_TAGS 44
#if 0 /* DEPRECATED EVENTS: */
/* we don't actually need to record the thread, it's implicit */
......
......@@ -266,6 +266,7 @@ initCapability( Capability *cap, nat i )
cap->pinned_object_block = NULL;
traceCapsetAssignCap(CAPSET_OSPROCESS_DEFAULT, i);
traceCapsetAssignCap(CAPSET_CLOCKDOMAIN_DEFAULT, i);
#if defined(THREADED_RTS)
traceSparkCounters(cap);
#endif
......@@ -282,9 +283,10 @@ initCapability( Capability *cap, nat i )
void
initCapabilities( void )
{
/* Declare a single capability set representing the process.
Each capability will get added to this capset. */
/* Declare a couple capability sets representing the process and
clock domain. Each capability will get added to these capsets. */
traceCapsetCreate(CAPSET_OSPROCESS_DEFAULT, CapsetTypeOsProcess);
traceCapsetCreate(CAPSET_CLOCKDOMAIN_DEFAULT, CapsetTypeClockdomain);
#if defined(THREADED_RTS)
nat i;
......@@ -867,6 +869,7 @@ shutdownCapability (Capability *cap,
#endif /* THREADED_RTS */
traceCapsetRemoveCap(CAPSET_OSPROCESS_DEFAULT, cap->no);
traceCapsetRemoveCap(CAPSET_CLOCKDOMAIN_DEFAULT, cap->no);
}
void
......@@ -878,6 +881,7 @@ shutdownCapabilities(Task *task, rtsBool safe)
shutdownCapability(&capabilities[i], task, safe);
}
traceCapsetDelete(CAPSET_OSPROCESS_DEFAULT);
traceCapsetDelete(CAPSET_CLOCKDOMAIN_DEFAULT);
#if defined(THREADED_RTS)
ASSERT(checkSparkCountInvariant());
......
......@@ -22,6 +22,11 @@ Ticks getThreadCPUTime (void);
Ticks getProcessElapsedTime (void);
void getProcessTimes (Ticks *user, Ticks *elapsed);
/* Get the current date and time.
Uses seconds since the Unix epoch, plus nanoseconds
*/
void getUnixEpochTime (StgWord64 *sec, StgWord32 *nsec);
// Not strictly timing, but related
nat getPageFaults (void);
......
......@@ -154,6 +154,7 @@ hs_init(int *argc, char **argv[])
initScheduler();
/* Trace some basic information about the process */
traceWallClockTime();
traceOSProcessInfo();
/* initialize the storage manager */
......
......@@ -293,9 +293,9 @@ void traceGcEvent_ (Capability *cap, EventTypeNum tag)
}
}
void traceCapsetModify_ (EventTypeNum tag,
CapsetID capset,
StgWord32 other)
void traceCapsetEvent_ (EventTypeNum tag,
CapsetID capset,
StgWord info)
{
#ifdef DEBUG
if (RtsFlags.TraceFlags.tracing == TRACE_STDERR) {
......@@ -304,18 +304,18 @@ void traceCapsetModify_ (EventTypeNum tag,
tracePreface();
switch (tag) {
case EVENT_CAPSET_CREATE: // (capset, capset_type)
debugBelch("created capset %lu of type %d\n", (lnat)capset, (int)other);
debugBelch("created capset %lu of type %d\n", (lnat)capset, (int)info);
break;
case EVENT_CAPSET_DELETE: // (capset)
debugBelch("deleted capset %lu\n", (lnat)capset);
break;
case EVENT_CAPSET_ASSIGN_CAP: // (capset, capno)
debugBelch("assigned cap %lu to capset %lu\n",
(lnat)other, (lnat)capset);
(lnat)info, (lnat)capset);
break;
case EVENT_CAPSET_REMOVE_CAP: // (capset, capno)
debugBelch("removed cap %lu from capset %lu\n",
(lnat)other, (lnat)capset);
(lnat)info, (lnat)capset);
break;
}
RELEASE_LOCK(&trace_utx);
......@@ -323,25 +323,31 @@ void traceCapsetModify_ (EventTypeNum tag,
#endif
{
if (eventlog_enabled) {
postCapsetModifyEvent(tag, capset, other);
postCapsetEvent(tag, capset, info);
}
}
}
void traceWallClockTime_(void) {
if (eventlog_enabled) {
postWallClockTime(CAPSET_CLOCKDOMAIN_DEFAULT);
}
}
void traceOSProcessInfo_(void) {
if (eventlog_enabled) {
postCapsetModifyEvent(EVENT_OSPROCESS_PID,
CAPSET_OSPROCESS_DEFAULT,
getpid());
postCapsetEvent(EVENT_OSPROCESS_PID,
CAPSET_OSPROCESS_DEFAULT,
getpid());
#if !defined(cygwin32_HOST_OS) && !defined (mingw32_HOST_OS)
/* Windows has no strong concept of process heirarchy, so no getppid().
* In any case, this trace event is mainly useful for tracing programs
* that use 'forkProcess' which Windows doesn't support anyway.
*/
postCapsetModifyEvent(EVENT_OSPROCESS_PPID,
CAPSET_OSPROCESS_DEFAULT,
getppid());
postCapsetEvent(EVENT_OSPROCESS_PPID,
CAPSET_OSPROCESS_DEFAULT,
getppid());
#endif
{
char buf[256];
......
......@@ -37,6 +37,7 @@ enum CapsetType { CapsetTypeCustom = CAPSET_TYPE_CUSTOM,
CapsetTypeOsProcess = CAPSET_TYPE_OSPROCESS,
CapsetTypeClockdomain = CAPSET_TYPE_CLOCKDOMAIN };
#define CAPSET_OSPROCESS_DEFAULT 0
#define CAPSET_CLOCKDOMAIN_DEFAULT 1
// -----------------------------------------------------------------------------
// Message classes
......@@ -195,9 +196,11 @@ void traceEventStartup_ (int n_caps);
* the capset info events so for simplicity, rather than working out if
* they're necessary we always emit them. They should be very low volume.
*/
void traceCapsetModify_ (EventTypeNum tag,
CapsetID capset,
StgWord32 other);
void traceCapsetEvent_ (EventTypeNum tag,
CapsetID capset,
StgWord info);
void traceWallClockTime_(void);
void traceOSProcessInfo_ (void);
......@@ -218,7 +221,8 @@ void traceSparkCounters_ (Capability *cap,
#define debugTraceCap(class, cap, str, ...) /* nothing */
#define traceThreadStatus(class, tso) /* nothing */
INLINE_HEADER void traceEventStartup_ (int n_caps STG_UNUSED) {};
#define traceCapsetModify_(tag, capset, other) /* nothing */
#define traceCapsetEvent_(tag, capset, info) /* nothing */
#define traceWallClockTime_() /* nothing */
#define traceOSProcessInfo_() /* nothing */
#define traceSparkCounters_(cap, counters, remaining) /* nothing */
......@@ -468,30 +472,36 @@ INLINE_HEADER void traceEventStartup(void)
INLINE_HEADER void traceCapsetCreate(CapsetID capset STG_UNUSED,
CapsetType capset_type STG_UNUSED)
{
traceCapsetModify_(EVENT_CAPSET_CREATE, capset, capset_type);
traceCapsetEvent_(EVENT_CAPSET_CREATE, capset, capset_type);
dtraceCapsetCreate(capset, capset_type);
}
INLINE_HEADER void traceCapsetDelete(CapsetID capset STG_UNUSED)
{
traceCapsetModify_(EVENT_CAPSET_DELETE, capset, 0);
traceCapsetEvent_(EVENT_CAPSET_DELETE, capset, 0);
dtraceCapsetDelete(capset);
}
INLINE_HEADER void traceCapsetAssignCap(CapsetID capset STG_UNUSED,
nat capno STG_UNUSED)
{
traceCapsetModify_(EVENT_CAPSET_ASSIGN_CAP, capset, capno);
traceCapsetEvent_(EVENT_CAPSET_ASSIGN_CAP, capset, capno);
dtraceCapsetAssignCap(capset, capno);
}
INLINE_HEADER void traceCapsetRemoveCap(CapsetID capset STG_UNUSED,
nat capno STG_UNUSED)
{
traceCapsetModify_(EVENT_CAPSET_REMOVE_CAP, capset, capno);
traceCapsetEvent_(EVENT_CAPSET_REMOVE_CAP, capset, capno);
dtraceCapsetRemoveCap(capset, capno);
}
INLINE_HEADER void traceWallClockTime(void)
{
traceWallClockTime_();
/* Note: no DTrace equivalent because it is available to DTrace directly */
}
INLINE_HEADER void traceOSProcessInfo(void)
{
traceOSProcessInfo_();
......
......@@ -83,6 +83,7 @@ char *EventDesc[] = {
[EVENT_PROGRAM_ENV] = "Program environment variables",
[EVENT_OSPROCESS_PID] = "Process ID",
[EVENT_OSPROCESS_PPID] = "Parent process ID",
[EVENT_WALL_CLOCK_TIME] = "Wall clock time",
[EVENT_SPARK_COUNTERS] = "Spark counters",
[EVENT_SPARK_CREATE] = "Spark create",
[EVENT_SPARK_DUD] = "Spark dud",
......@@ -299,6 +300,11 @@ initEventLogging(void)
sizeof(EventCapsetID) + sizeof(StgWord32);
break;
case EVENT_WALL_CLOCK_TIME: // (capset, unix_epoch_seconds, nanoseconds)
eventTypes[t].size =
sizeof(EventCapsetID) + sizeof(StgWord64) + sizeof(StgWord32);
break;
case EVENT_SPARK_STEAL: // (cap, victim_cap)
eventTypes[t].size =
sizeof(EventCapNo);
......@@ -559,9 +565,9 @@ postSparkCountersEvent (Capability *cap,
postWord64(eb,remaining);
}
void postCapsetModifyEvent (EventTypeNum tag,
EventCapsetID capset,
StgWord32 other)
void postCapsetEvent (EventTypeNum tag,
EventCapsetID capset,
StgWord info)
{
ACQUIRE_LOCK(&eventBufMutex);
......@@ -576,7 +582,7 @@ void postCapsetModifyEvent (EventTypeNum tag,
switch (tag) {
case EVENT_CAPSET_CREATE: // (capset, capset_type)
{
postCapsetType(&eventBuf, other /* capset_type */);
postCapsetType(&eventBuf, info /* capset_type */);
break;
}
......@@ -588,17 +594,17 @@ void postCapsetModifyEvent (EventTypeNum tag,
case EVENT_CAPSET_ASSIGN_CAP: // (capset, capno)
case EVENT_CAPSET_REMOVE_CAP: // (capset, capno)
{
postCapNo(&eventBuf, other /* capno */);
postCapNo(&eventBuf, info /* capno */);
break;
}
case EVENT_OSPROCESS_PID: // (capset, pid)
case EVENT_OSPROCESS_PPID: // (capset, parent_pid)
{
postWord32(&eventBuf, other);
postWord32(&eventBuf, info);
break;
}
default:
barf("postCapsetModifyEvent: unknown event tag %d", tag);
barf("postCapsetEvent: unknown event tag %d", tag);
}
RELEASE_LOCK(&eventBufMutex);
......@@ -668,6 +674,52 @@ void postCapsetVecEvent (EventTypeNum tag,
RELEASE_LOCK(&eventBufMutex);
}
void postWallClockTime (EventCapsetID capset)
{
StgWord64 ts;
StgWord64 sec;
StgWord32 nsec;
ACQUIRE_LOCK(&eventBufMutex);
/* The EVENT_WALL_CLOCK_TIME event is intended to allow programs
reading the eventlog to match up the event timestamps with wall
clock time. The normal event timestamps measure time since the
start of the program. To align eventlogs from concurrent
processes we need to be able to match up the timestamps. One way
to do this is if we know how the timestamps and wall clock time
match up (and of course if both processes have sufficiently
synchronised clocks).
So we want to make sure that the timestamp that we generate for
this event matches up very closely with the wall clock time.
Unfortunately we currently have to use two different APIs to get
the elapsed time vs the wall clock time. So to minimise the
difference we just call them very close together.
*/
getUnixEpochTime(&sec, &nsec); /* Get the wall clock time */
ts = time_ns(); /* Get the eventlog timestamp */
if (!hasRoomForEvent(&eventBuf, EVENT_WALL_CLOCK_TIME)) {
// Flush event buffer to make room for new event.
printAndClearEventBuf(&eventBuf);
}
/* Normally we'd call postEventHeader(), but that generates its own
timestamp, so we go one level lower so we can write out the
timestamp we already generated above. */
postEventTypeNum(&eventBuf, EVENT_WALL_CLOCK_TIME);
postWord64(&eventBuf, ts);
/* EVENT_WALL_CLOCK_TIME (capset, unix_epoch_seconds, nanoseconds) */
postCapsetID(&eventBuf, capset);
postWord64(&eventBuf, sec);
postWord32(&eventBuf, nsec);
RELEASE_LOCK(&eventBufMutex);
}
void
postEvent (Capability *cap, EventTypeNum tag)
{
......
......@@ -48,11 +48,11 @@ void postCapMsg(Capability *cap, char *msg, va_list ap);
void postEventStartup(EventCapNo n_caps);
/*
* Post a capability set modification event
* Post an event that is associated with a capability set
*/
void postCapsetModifyEvent (EventTypeNum tag,
EventCapsetID capset,
StgWord32 other);
void postCapsetEvent (EventTypeNum tag,
EventCapsetID capset,
StgWord info);
/*
* Post a capability set event with a string payload
......@@ -69,6 +69,8 @@ void postCapsetVecEvent (EventTypeNum tag,
int argc,
char *msg[]);
void postWallClockTime (EventCapsetID capset);
/*
* Post a `par` spark event
*/
......
......@@ -181,6 +181,22 @@ Ticks getThreadCPUTime(void)
return getProcessCPUTime();
}
void getUnixEpochTime(StgWord64 *sec, StgWord32 *nsec)
{
#if defined(HAVE_GETTIMEOFDAY)
struct timeval tv;
gettimeofday(&tv, (struct timezone *) NULL);
*sec = tv.tv_sec;
*nsec = tv.tv_usec * 1000;
#else
/* Sigh, fall back to second resolution. */
time_t t;
time(&t);
*sec = t;
*nsec = 0;
#endif
}
nat
getPageFaults(void)
{
......
......@@ -27,26 +27,6 @@ fileTimeToTicks(FILETIME ft)
return t;
}
static int is_win9x = -1;
static INLINE_ME rtsBool
isWin9x(void)
{
if (is_win9x < 0) {
/* figure out whether we're on a Win9x box or not. */
OSVERSIONINFO oi;
BOOL b;
/* Need to init the size field first.*/
oi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
b = GetVersionEx(&oi);
is_win9x = ( (b && (oi.dwPlatformId & VER_PLATFORM_WIN32_WINDOWS)) ? 1 : 0);
}
return is_win9x;
}
void
getProcessTimes(Ticks *user, Ticks *elapsed)
{
......@@ -59,8 +39,6 @@ getProcessCPUTime(void)
{
FILETIME creationTime, exitTime, userTime, kernelTime = {0,0};
if (isWin9x()) return getProcessElapsedTime();
if (!GetProcessTimes(GetCurrentProcess(), &creationTime,
&exitTime, &kernelTime, &userTime)) {
return 0;
......@@ -106,8 +84,6 @@ getThreadCPUTime(void)
{
FILETIME creationTime, exitTime, userTime, kernelTime = {0,0};
if (isWin9x()) return getProcessCPUTime();
if (!GetThreadTimes(GetCurrentThread(), &creationTime,
&exitTime, &kernelTime, &userTime)) {
return 0;
......@@ -116,6 +92,46 @@ getThreadCPUTime(void)
return fileTimeToTicks(userTime);
}
void
getUnixEpochTime(StgWord64 *sec, StgWord32 *nsec)
{
/* Windows has a bunch of time APIs but none that directly give
us unix epoch time, so we have to do a little dance. */
SYSTEMTIME systime;
FILETIME filetime;
ULARGE_INTEGER unixtime;
/* Windows SYSTEMTIME is a big struct with fields for
year, month, day, hour, minute, second, millisecond. */
GetSystemTime(&systime);
/* Windows FILETIME timestamps use an epoch-based time,
using a 64bit unsigned word. The time is measured in
units of 100 nanoseconds since an epoch of 1601. */
SystemTimeToFileTime(&systime, &filetime);
/* FILETIME isn't directly a 64bit word, but a struct with
a pair of 32bit words, so we have to convert via a
ULARGE_INTEGER struct which is a handy union type */
unixtime.LowPart = filetime.dwLowDateTime;
unixtime.HighPart = filetime.dwHighDateTime;
/* We have to do an epoch conversion, since FILETIME uses 1601
while we want unix epoch of 1970. In case you were wondering,
there were 11,644,473,600 seconds between 1601 and 1970, then
multiply by 10^7 for units of 100 nanoseconds. */
unixtime.QuadPart = unixtime.QuadPart - 116444736000000000ull;
/* For the seconds part we use integer division by 10^7 */
*sec = unixtime.QuadPart / 10000000ull;
/* The remainder from integer division by 10^7 gives us
the sub-second component in units of 100 nanoseconds.
So for nanoseconds we just multiply by 100.
Note that nanoseconds always fits in a 32bit word */
*nsec = ((unsigned long)(unixtime.QuadPart % 10000000ull)) * 100ul;
}
nat
getPageFaults(void)
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment