Skip to content

Commit 55e1dc5

Browse files
committed
Move tsc library into libs, where shim can also use it
1 parent 4054b51 commit 55e1dc5

9 files changed

Lines changed: 110 additions & 133 deletions

File tree

src/lib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
add_subdirectory(logger)
2+
add_subdirectory(tsc)
23
add_subdirectory(shim)

src/lib/shim/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ set(SHIM_FILES
4141
add_library(${SHIM_LIB} SHARED ${SHIM_FILES})
4242
set_target_properties(${SHIM_LIB} PROPERTIES LINK_FLAGS "-Wl,--no-as-needed")
4343
target_compile_options(${SHIM_LIB} PRIVATE -pthread -D_GNU_SOURCE)
44-
target_link_libraries(${SHIM_LIB} ${SHIM_HELPER_LIB} shadow-shmem logger
44+
target_link_libraries(${SHIM_LIB} ${SHIM_HELPER_LIB} shadow-shmem shadow-tsc logger
4545
${RT_LIBRARIES} ${GLIB_LIBRARIES} -pthread -ldl)
4646
install(TARGETS ${SHIM_LIB} DESTINATION lib)
4747

src/lib/tsc/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
include_directories(${GLIB_INCLUDES})
2+
3+
add_library(shadow-tsc STATIC tsc.c)
4+
target_compile_options(shadow-tsc PRIVATE -D_GNU_SOURCE -fPIC)
5+
target_link_libraries(shadow-tsc logger)
6+
7+
add_executable(tsc_test tsc_test.c)
8+
target_link_libraries(tsc_test ${GLIB_LIBRARIES} shadow-tsc)
9+
add_test(NAME tsc_test COMMAND tsc_test)
Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
#include "main/host/tsc.h"
1+
#include "lib/tsc/tsc.h"
22

33
#include <assert.h>
44
#include <cpuid.h>
55
#include <errno.h>
66
#include <inttypes.h>
7-
#include <string.h>
87
#include <stdio.h>
8+
#include <string.h>
99
#include <time.h>
1010
#include <unistd.h>
1111
#include <x86intrin.h>
@@ -16,7 +16,7 @@
1616
#define rdtscp __rdtscp
1717

1818
Tsc Tsc_measure() {
19-
unsigned int a=0,b=0,c=0,d=0;
19+
unsigned int a = 0, b = 0, c = 0, d = 0;
2020
// Use the cpuid instruction (wrapped by __get_cpuid) to determine the clock
2121
// frequency. See "cpuid" in "Intel® 64 and IA-32 Architectures Software
2222
// Developer’s Manual Volume 2A".
@@ -36,7 +36,7 @@ Tsc Tsc_measure() {
3636
panic("cpuid 0x15 unsupported; can't get tsc frequency");
3737
}
3838

39-
// cpuid 0x15 gives us
39+
// cpuid 0x15 gives us
4040
if (!__get_cpuid(0x15, &a, &b, &c, &d)) {
4141
panic("cpuid");
4242
}
@@ -56,7 +56,7 @@ Tsc Tsc_measure() {
5656
// core crystal clock in Hz."
5757
unsigned int core = c;
5858
if (core) {
59-
Tsc tsc = {(uint64_t)c*b/a};
59+
Tsc tsc = {(uint64_t)c * b / a};
6060
debug("Calculated %" PRIu64 " cyclesPerSecond via cpuid 15h", tsc.cyclesPerSecond);
6161
return tsc;
6262
}
@@ -69,7 +69,7 @@ Tsc Tsc_measure() {
6969
// gives a 2 row table for this case:
7070

7171
// 6th and 7th generation Intel® Core™ processors -> 24 MHz
72-
//
72+
//
7373
// Next Generation Intel® Atom™ processors based on Goldmont
7474
// Microarchitecture with CPUID signature 06_5CH -> 19.2 MHz.
7575
//
@@ -89,7 +89,7 @@ Tsc Tsc_measure() {
8989
return tsc;
9090
}
9191
#endif
92-
92+
9393
if (!__get_cpuid(0x80000000, &a, &b, &c, &d)) {
9494
panic("cpuid");
9595
}
@@ -100,7 +100,7 @@ Tsc Tsc_measure() {
100100
}
101101
union {
102102
uint32_t ints[3][4];
103-
char chars[12*4];
103+
char chars[12 * 4];
104104
} brand_string;
105105
for (int i = 0; i < 3; ++i) {
106106
if (!__get_cpuid(0x80000002 + i, &a, &b, &c, &d)) {
@@ -112,7 +112,7 @@ Tsc Tsc_measure() {
112112
brand_string.ints[i][3] = d;
113113
}
114114
// Guaranteed to be null terminated.
115-
assert(brand_string.chars[sizeof(brand_string)-1] == '\0');
115+
assert(brand_string.chars[sizeof(brand_string) - 1] == '\0');
116116

117117
trace("Got brand string %s", brand_string.chars);
118118

@@ -139,28 +139,25 @@ Tsc Tsc_measure() {
139139
panic("Unrecognized scale character %c", scale_c);
140140
}
141141

142-
Tsc tsc = {frequency*scale};
142+
Tsc tsc = {frequency * scale};
143143
debug("Calculated %" PRIu64 " cyclesPerSecond via brand string", tsc.cyclesPerSecond);
144144
return tsc;
145145
}
146146

147-
static void _Tsc_setRdtscCycles(const Tsc* tsc, struct user_regs_struct* regs,
148-
uint64_t nanos) {
147+
static void _Tsc_setRdtscCycles(const Tsc* tsc, struct user_regs_struct* regs, uint64_t nanos) {
149148
// Guaranteed not to overflow since the operands are both 64 bit.
150-
__uint128_t gigaCycles = (__uint128_t)tsc->cyclesPerSecond * nanos;
149+
__uint128_t gigaCycles = (__uint128_t)tsc->cyclesPerSecond * nanos;
151150
uint64_t cycles = gigaCycles / 1000000000;
152151
regs->rdx = (cycles >> 32) & 0xffffffff;
153152
regs->rax = cycles & 0xffffffff;
154153
}
155154

156-
void Tsc_emulateRdtsc(const Tsc* tsc, struct user_regs_struct* regs,
157-
uint64_t nanos) {
155+
void Tsc_emulateRdtsc(const Tsc* tsc, struct user_regs_struct* regs, uint64_t nanos) {
158156
_Tsc_setRdtscCycles(tsc, regs, nanos);
159157
regs->rip += 2;
160158
}
161159

162-
void Tsc_emulateRdtscp(const Tsc* tsc, struct user_regs_struct* regs,
163-
uint64_t nanos) {
160+
void Tsc_emulateRdtscp(const Tsc* tsc, struct user_regs_struct* regs, uint64_t nanos) {
164161
_Tsc_setRdtscCycles(tsc, regs, nanos);
165162
// rcx is set to IA32_TSC_AUX. According to the Intel developer manual
166163
// 17.17.2 "IA32_TSC_AUX Register and RDTSCP Support", "IA32_TSC_AUX
Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,14 @@ Tsc Tsc_measure();
2121

2222
// Updates `regs` to reflect the result of executing an rdtsc instruction at
2323
// time `nanos`.
24-
void Tsc_emulateRdtsc(const Tsc* tsc, struct user_regs_struct* regs,
25-
uint64_t nanos);
24+
void Tsc_emulateRdtsc(const Tsc* tsc, struct user_regs_struct* regs, uint64_t nanos);
2625

2726
// Updates `regs` to reflect the result of executing an rdtscp instruction at
2827
// time `nanos`.
29-
void Tsc_emulateRdtscp(const Tsc* tsc, struct user_regs_struct* regs,
30-
uint64_t nanos);
28+
void Tsc_emulateRdtscp(const Tsc* tsc, struct user_regs_struct* regs, uint64_t nanos);
3129

3230
// Whether `buf` begins with an rdtsc instruction.
33-
static inline bool isRdtsc(const uint8_t* buf) {
34-
return buf[0] == 0x0f && buf[1] == 0x31;
35-
}
31+
static inline bool isRdtsc(const uint8_t* buf) { return buf[0] == 0x0f && buf[1] == 0x31; }
3632

3733
// Whether `buf` begins with an rdtscp instruction.
3834
static inline bool isRdtscp(const uint8_t* buf) {

src/lib/tsc/tsc_test.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include "lib/tsc/tsc.h"
2+
3+
#include <glib.h>
4+
#include <inttypes.h>
5+
#include <locale.h>
6+
#include <stdint.h>
7+
#include <stdlib.h>
8+
9+
void measureGivesConsistentResults() {
10+
Tsc baseline = Tsc_measure();
11+
// FIXME: this is a pretty loose consistency bound, but tighter bounds
12+
// currently occasionally fail. The right thing to do is extract the
13+
// nominal rate via cpuid, and have a test validating that is within the
14+
// ballpark of the measured approach.
15+
for (int i = 0; i < 100; ++i) {
16+
Tsc test = Tsc_measure();
17+
int64_t milliPercentDiff =
18+
llabs((int64_t)test.cyclesPerSecond - (int64_t)baseline.cyclesPerSecond) * 100L *
19+
1000L / baseline.cyclesPerSecond;
20+
/* 1.000% */
21+
g_assert_cmpint(milliPercentDiff, <, 1000);
22+
}
23+
g_assert_true(TRUE);
24+
}
25+
26+
static uint64_t _getEmulatedCycles(void (*emulate_fn)(const Tsc* tsc, struct user_regs_struct* regs,
27+
uint64_t nanos),
28+
uint64_t cyclesPerSecond, int64_t nanos) {
29+
30+
Tsc tsc = {.cyclesPerSecond = cyclesPerSecond};
31+
struct user_regs_struct regs = {};
32+
emulate_fn(&tsc, &regs, nanos);
33+
return (regs.rdx << 32) | regs.rax;
34+
}
35+
36+
void emulateGivesExpectedCycles(void* unusedFixture, gconstpointer user_data) {
37+
void (*emulate_fn)(const Tsc* tsc, struct user_regs_struct* regs, uint64_t nanos) = user_data;
38+
const uint64_t cyclesPerSecondForOneGHz = 1000000000;
39+
40+
// Single ns granularity @ 1 GHz
41+
g_assert_cmpint(_getEmulatedCycles(emulate_fn, cyclesPerSecondForOneGHz, 1), ==, 1);
42+
43+
// 1000x clock rate
44+
g_assert_cmpint(_getEmulatedCycles(emulate_fn, 1000 * cyclesPerSecondForOneGHz, 1), ==, 1000);
45+
46+
// 1000x nanos
47+
g_assert_cmpint(_getEmulatedCycles(emulate_fn, cyclesPerSecondForOneGHz, 1000), ==, 1000);
48+
49+
// Correct (no overflow) for 1 year @ 10 GHz
50+
const uint64_t oneYearInSeconds = 1L // years
51+
* 365L // days
52+
* 24L // hours
53+
* 60L // minutes
54+
* 60L; // seconds
55+
uint64_t expectedCycles;
56+
gboolean ok =
57+
g_uint64_checked_mul(&expectedCycles, oneYearInSeconds, 10 * cyclesPerSecondForOneGHz);
58+
g_assert(ok);
59+
g_assert_cmpint(_getEmulatedCycles(
60+
emulate_fn, 10L * cyclesPerSecondForOneGHz, oneYearInSeconds * 1000000000L),
61+
==, expectedCycles);
62+
}
63+
64+
int main(int argc, char* argv[]) {
65+
g_test_init(&argc, &argv, NULL);
66+
g_test_set_nonfatal_assertions();
67+
68+
// Define the tests.
69+
70+
// FIXME: flaky
71+
// g_test_add_func("/tsc/measureGivesConsistentResults",
72+
// measureGivesConsistentResults);
73+
74+
g_test_add("/tsc/emulateRdtscGivesExpectedCycles", void, &Tsc_emulateRdtsc, NULL,
75+
emulateGivesExpectedCycles, NULL);
76+
g_test_add("/tsc/emulateRdtscpGivesExpectedCycles", void, &Tsc_emulateRdtscp, NULL,
77+
emulateGivesExpectedCycles, NULL);
78+
79+
return g_test_run();
80+
}

src/main/CMakeLists.txt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,6 @@ endif()
5252

5353
add_library(shadow-remora STATIC host/descriptor/tcp_retransmit_tally.cc)
5454

55-
add_library(shadow-tsc STATIC host/tsc.c)
56-
target_link_libraries(shadow-tsc ${GLIB_LIBRARIES} logger)
57-
58-
add_executable(tsc_test host/tsc_test.c)
59-
target_link_libraries(tsc_test ${GLIB_LIBRARIES} shadow-tsc)
60-
add_test(NAME tsc_test COMMAND tsc_test)
61-
6255
set(SHD_SHMEM_SRC
6356
shmem/buddy.c
6457
shmem/shmem_allocator.c
@@ -203,6 +196,7 @@ set(RUSTFLAGS "${RUSTFLAGS} -lstdc++")
203196
set(RUSTFLAGS "${RUSTFLAGS} -L${CMAKE_CURRENT_BINARY_DIR}")
204197
set(RUSTFLAGS "${RUSTFLAGS} -L${CMAKE_BINARY_DIR}/src/lib/logger")
205198
set(RUSTFLAGS "${RUSTFLAGS} -L${CMAKE_BINARY_DIR}/src/lib/shim")
199+
set(RUSTFLAGS "${RUSTFLAGS} -L${CMAKE_BINARY_DIR}/src/lib/tsc")
206200
set(CARGO_ENV_VARS "${CARGO_ENV_VARS} RUSTFLAGS=\"${RUSTFLAGS}\"")
207201

208202
set(RUST_FEATURES "")

src/main/host/thread_ptrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717

1818
#include "lib/logger/logger.h"
1919
#include "lib/shim/ipc.h"
20+
#include "lib/tsc/tsc.h"
2021
#include "main/bindings/c/bindings.h"
2122
#include "main/core/support/config_handlers.h"
2223
#include "main/core/worker.h"
2324
#include "main/host/shimipc.h"
2425
#include "main/host/syscall_numbers.h"
2526
#include "main/host/thread_protected.h"
26-
#include "main/host/tsc.h"
2727
#include "main/utility/fork_proxy.h"
2828

2929
#define THREADPTRACE_TYPE_ID 3024

src/main/host/tsc_test.c

Lines changed: 0 additions & 100 deletions
This file was deleted.

0 commit comments

Comments
 (0)