1 // ©2013-2014 Cameron Desrochers
2 
3 #include "systemtime.h"
4 #include <climits>
5 
6 #if defined(_MSC_VER) && _MSC_VER < 1700
7 #include <intrin.h>
8 #define CompilerMemBar() _ReadWriteBarrier()
9 #else
10 #include <atomic>
11 #define CompilerMemBar() std::atomic_signal_fence(std::memory_order_seq_cst)
12 #endif
13 
14 #if defined(ST_WINDOWS)
15 
16 #include <windows.h>
17 
18 namespace moodycamel
19 {
20 
sleep(int milliseconds)21 void sleep(int milliseconds)
22 {
23 	::Sleep(milliseconds);
24 }
25 
getSystemTime()26 SystemTime getSystemTime()
27 {
28 	LARGE_INTEGER t;
29 	CompilerMemBar();
30 	if (!QueryPerformanceCounter(&t)) {
31 		return static_cast<SystemTime>(-1);
32 	}
33 	CompilerMemBar();
34 
35 	return static_cast<SystemTime>(t.QuadPart);
36 }
37 
getTimeDelta(SystemTime start)38 double getTimeDelta(SystemTime start)
39 {
40 	LARGE_INTEGER t;
41 	CompilerMemBar();
42 	if (start == static_cast<SystemTime>(-1) || !QueryPerformanceCounter(&t)) {
43 		return -1;
44 	}
45 	CompilerMemBar();
46 
47 	auto now = static_cast<SystemTime>(t.QuadPart);
48 
49 	LARGE_INTEGER f;
50 	if (!QueryPerformanceFrequency(&f)) {
51 		return -1;
52 	}
53 
54 #if defined(__GNUC__)
55 #pragma GCC diagnostic push
56 #pragma GCC diagnostic ignored "-Wconversion"
57 #endif
58 	return static_cast<double>(static_cast<__int64>(now - start)) / f.QuadPart * 1000;
59 #if defined(__GNUC__)
60 #pragma GCC diagnostic pop
61 #endif
62 }
63 
64 }  // end namespace moodycamel
65 
66 #elif defined(ST_APPLE)
67 
68 #include <mach/mach.h>
69 #include <mach/mach_time.h>
70 #include <unistd.h>
71 #include <time.h>
72 
73 namespace moodycamel
74 {
75 
sleep(int milliseconds)76 void sleep(int milliseconds)
77 {
78 	::usleep(milliseconds * 1000);
79 }
80 
getSystemTime()81 SystemTime getSystemTime()
82 {
83 	CompilerMemBar();
84 	std::uint64_t result = mach_absolute_time();
85 	CompilerMemBar();
86 
87 	return result;
88 }
89 
getTimeDelta(SystemTime start)90 double getTimeDelta(SystemTime start)
91 {
92 	CompilerMemBar();
93 	std::uint64_t end = mach_absolute_time();
94 	CompilerMemBar();
95 
96 	mach_timebase_info_data_t tb = { 0 };
97 	mach_timebase_info(&tb);
98 	double toNano = static_cast<double>(tb.numer) / tb.denom;
99 
100 	return static_cast<double>(end - start) * toNano * 0.000001;
101 }
102 
103 }  // end namespace moodycamel
104 
105 #elif defined(ST_NIX)
106 
107 #include <unistd.h>
108 
109 namespace moodycamel
110 {
111 
sleep(int milliseconds)112 void sleep(int milliseconds)
113 {
114 	::usleep(milliseconds * 1000);
115 }
116 
getSystemTime()117 SystemTime getSystemTime()
118 {
119 	timespec t;
120 	CompilerMemBar();
121 	if (clock_gettime(CLOCK_MONOTONIC_RAW, &t) != 0) {
122 		t.tv_sec = (time_t)-1;
123 		t.tv_nsec = -1;
124 	}
125 	CompilerMemBar();
126 
127 	return t;
128 }
129 
getTimeDelta(SystemTime start)130 double getTimeDelta(SystemTime start)
131 {
132 	timespec t;
133 	CompilerMemBar();
134 	if ((start.tv_sec == (time_t)-1 && start.tv_nsec == -1) || clock_gettime(CLOCK_MONOTONIC_RAW, &t) != 0) {
135 		return -1;
136 	}
137 	CompilerMemBar();
138 
139 	return static_cast<double>(static_cast<long>(t.tv_sec) - static_cast<long>(start.tv_sec)) * 1000 + double(t.tv_nsec - start.tv_nsec) / 1000000;
140 }
141 
142 }  // end namespace moodycamel
143 
144 #endif
145