summaryrefslogtreecommitdiffstats
path: root/contrib/restricted/wavm/Lib/Platform/POSIX/ClockPOSIX.cpp
blob: 301f9d819715fc3d28df1d78da07bef203ee48b2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <stdio.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <time.h>
#include "WAVM/Inline/Assert.h"
#include "WAVM/Inline/Errors.h"
#include "WAVM/Inline/I128.h"
#include "WAVM/Inline/Time.h"
#include "WAVM/Platform/Clock.h"

using namespace WAVM;
using namespace WAVM::Platform;

static I128 timespecToNS(timespec t) { return I128(U64(t.tv_sec)) * 1000000000 + U64(t.tv_nsec); }

static I128 getClockAsI128(clockid_t clockId)
{
	timespec clockTime;
	WAVM_ERROR_UNLESS(!clock_gettime(clockId, &clockTime));
	return timespecToNS(clockTime);
}

static I128 getClockResAsI128(clockid_t clockId)
{
	timespec clockResolution;
	WAVM_ERROR_UNLESS(!clock_getres(clockId, &clockResolution));
	return timespecToNS(clockResolution);
}

#if defined(__APPLE__)

#include <mach/mach_time.h>

static mach_timebase_info_data_t getTimebaseInfoData()
{
	mach_timebase_info_data_t timebaseInfoData;
	WAVM_ERROR_UNLESS(mach_timebase_info(&timebaseInfoData) == KERN_SUCCESS);
	return timebaseInfoData;
}

static mach_timebase_info_data_t getCachedTimebaseInfoData()
{
	static mach_timebase_info_data_t cachedTimebaseInfoData = getTimebaseInfoData();
	return cachedTimebaseInfoData;
}

static I128 getMachAbsoluteClock()
{
	mach_timebase_info_data_t cachedTimebaseInfoData = getCachedTimebaseInfoData();
	const I128 ticks = mach_absolute_time();
	const I128 ns = ticks * cachedTimebaseInfoData.numer / cachedTimebaseInfoData.denom;

	return ns;
}
static I128 getMachAbsoluteClockResolution()
{
	mach_timebase_info_data_t cachedTimebaseInfoData = getCachedTimebaseInfoData();
	I128 ticksPerNanosecond = I128(cachedTimebaseInfoData.numer) / cachedTimebaseInfoData.denom;
	if(ticksPerNanosecond == 0) { ticksPerNanosecond = 1; }
	return ticksPerNanosecond;
}
#endif

Time Platform::getClockTime(Clock clock)
{
	switch(clock)
	{
	case Clock::realtime: return Time{getClockAsI128(CLOCK_REALTIME)};
	case Clock::monotonic: {
#if defined(__APPLE__)
		return Time{getMachAbsoluteClock()};
#elif defined(CLOCK_MONOTONIC)
		return Time{getClockAsI128(CLOCK_MONOTONIC)};
#else
#error CLOCK_MONOTONIC not supported on this platform.
#endif
	}
	case Clock::processCPUTime: {
#ifdef CLOCK_PROCESS_CPUTIME_ID
		return Time{getClockAsI128(CLOCK_PROCESS_CPUTIME_ID)};
#else
		struct rusage ru;
		WAVM_ERROR_UNLESS(!getrusage(RUSAGE_SELF, &ru));
		return Time{timevalToNS(ru.ru_stime) + timevalToNS(ru.ru_utime)};
#endif
	}
	default: WAVM_UNREACHABLE();
	}
}

Time Platform::getClockResolution(Clock clock)
{
	switch(clock)
	{
	case Clock::realtime: return Time{getClockResAsI128(CLOCK_REALTIME)};
	case Clock::monotonic: {
#if defined(__APPLE__)
		return Time{getMachAbsoluteClockResolution()};
#elif defined(CLOCK_MONOTONIC)
		return Time{getClockResAsI128(CLOCK_MONOTONIC)};
#else
#error CLOCK_MONOTONIC not supported on this platform.
#endif
	}
	case Clock::processCPUTime: {
#ifdef CLOCK_PROCESS_CPUTIME_ID
		return Time{getClockResAsI128(CLOCK_PROCESS_CPUTIME_ID)};
#else
		return Time{1000};
#endif
	}
	default: WAVM_UNREACHABLE();
	}
}