Skip to content

Commit 81bc5a3

Browse files
committed
Added asynchronous testing
1 parent 80a84b6 commit 81bc5a3

1 file changed

Lines changed: 80 additions & 52 deletions

File tree

tests/jitter/jitter.cpp

Lines changed: 80 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <iostream>
55
#include <set>
66
#include <cstring>
7+
#include <unistd.h>
78

89
#include "CpuUtils.h"
910
#include "MicroStats.h"
@@ -13,13 +14,17 @@
1314
using Histogram = MicroStats<8>;
1415
const uint64_t ROUGHLY_ONE_SECOND_IN_TICKS = 3000000000;
1516

16-
struct Options {
17-
std::size_t wait_ticks = ROUGHLY_ONE_SECOND_IN_TICKS;
17+
struct Stats {
18+
std::size_t wait_ticks = 3 * ROUGHLY_ONE_SECOND_IN_TICKS;
1819
std::size_t core;
1920
int policy;
2021
int prio;
22+
pthread_t tid;
2123
bool print;
24+
bool async;
2225
Histogram hist;
26+
uint64_t pause;
27+
uint64_t events;
2328
};
2429

2530
double calcFrequencyGHz(uint64_t ticks) {
@@ -55,7 +60,7 @@ uint64_t calcQuantum(uint64_t ticks) {
5560
uint64_t quantum = calcQuantum(ROUGHLY_ONE_SECOND_IN_TICKS);
5661
double freqGHz = calcFrequencyGHz(ROUGHLY_ONE_SECOND_IN_TICKS);
5762

58-
void collectJitterSamples(Options& opt) {
63+
void collectJitterSamples(Stats& opt) {
5964
uint64_t threshold = 10 * quantum;
6065
uint64_t last = tic();
6166
busyWait(opt.wait_ticks, [&last, &opt, threshold](uint64_t now) {
@@ -66,21 +71,23 @@ void collectJitterSamples(Options& opt) {
6671
if (opt.print) {
6772
unsigned cpu = sched_getcpu();
6873
printf(
69-
"Testing core %-2ld cpu:%-2d Isol:%-2s Events:%-4ld "
74+
"Testing core %-2ld cpu:%-2d Isol:%-2s Events:%-6ld "
7075
"Pct1/50/99: %-7ld %-7ld %-7ld\n",
7176
opt.core, cpu, yn(isIsolated(opt.core)), opt.hist.count(),
7277
long(opt.hist.percentile(1)), long(opt.hist.percentile(50)),
73-
long(opt.hist.percentile(99)));
78+
long(opt.hist.percentile(99.9)));
7479
}
80+
opt.pause = opt.hist.percentile(99.9);
81+
opt.events = opt.hist.count();
7582
}
7683

7784
static void* runtest(void* args) {
78-
Options& opt = *((Options*)args);
85+
Stats& opt = *((Stats*)args);
7986
collectJitterSamples(opt);
8087
return nullptr;
8188
}
8289

83-
void runJitterTestInCore(Options& opt) {
90+
void runJitterTestInCore(Stats& opt) {
8491
// Sets affinity to given core, and scheduling policy + priority.
8592
pthread_attr_t attr;
8693
pthread_attr_init(&attr);
@@ -108,86 +115,107 @@ void runJitterTestInCore(Options& opt) {
108115
}
109116

110117
// Launches thread
111-
pthread_t tid;
112-
res = pthread_create(&tid, &attr, runtest, &opt);
118+
res = pthread_create(&opt.tid, &attr, runtest, &opt);
113119
if (res != 0) {
114120
perror("pthread_create");
115121
}
116122

117-
// Waits for it to finish
118-
void* result;
119-
pthread_join(tid, &result);
123+
if (opt.async) {
124+
// This is just so the results are printed in order
125+
usleep(10000);
126+
} else {
127+
// Wait for thread to finish
128+
void* retval;
129+
pthread_join(opt.tid, &retval);
130+
}
120131
}
121132

122-
int main() {
123-
lockAllMemory();
133+
void runAllTests(bool async) {
124134
auto numcores = getNumberOfCores();
125-
auto affinity = makeSet(getThreadAffinity());
126-
int policy;
127-
struct sched_param param;
128-
pthread_getschedparam(pthread_self(), &policy, &param);
135+
auto wait_ticks = (async ? 10 : 1) * ROUGHLY_ONE_SECOND_IN_TICKS;
129136

130-
printf("CPU Freq:%6.1f GHz Policy:%s Priority:%d Cores:%ld Avail:%ld ", freqGHz,
131-
getPolicyName(policy), param.sched_priority, numcores, affinity.size());
132-
for (auto core : affinity) {
133-
printf("%ld ", core);
134-
}
135-
printf("\n");
136-
if (numcores == affinity.size()) {
137-
printf(
138-
"*** There are no isolated cores to get reliable stats on. Results may be "
139-
"misleading.\n");
140-
}
141-
142-
struct Stats {
143-
uint64_t events;
144-
uint64_t pause;
145-
};
146137
std::vector<Stats> stats(numcores);
147-
int max_rr_prio = sched_get_priority_max(SCHED_FIFO);
148-
std::vector<uint64_t> isol_pause;
149138
for (int core = 0; core < numcores; ++core) {
150-
Options opt;
139+
Stats& opt(stats[core]);
151140
opt.core = core;
141+
opt.wait_ticks = wait_ticks;
152142
opt.policy = SCHED_FIFO;
153-
opt.prio = max_rr_prio;
143+
opt.prio = sched_get_priority_max(SCHED_FIFO);
154144
opt.print = true;
145+
opt.async = async;
155146
runJitterTestInCore(opt);
156-
uint64_t pause = opt.hist.percentile(99.9);
157-
stats[core].events = opt.hist.count();
158-
stats[core].pause = pause;
159-
if (isIsolated(core)) {
160-
isol_pause.push_back(pause);
161-
}
162147
}
163148

149+
// Wait for all threads to stop and collect stats
164150
uint64_t min_events = std::numeric_limits<uint64_t>::max();
165151
uint64_t min_pause = std::numeric_limits<uint64_t>::max();
152+
std::vector<uint64_t> isol_pause;
166153
for (Stats& s : stats) {
154+
if (async) {
155+
void* retval;
156+
pthread_join(s.tid, &retval);
157+
}
167158
min_events = std::min(min_events, s.events);
168159
min_pause = std::min(min_pause, s.pause);
160+
if (isIsolated(s.core)) {
161+
isol_pause.push_back(s.pause);
162+
}
169163
}
164+
170165
// Take stats from isolated cores if they exist
171166
if (!isol_pause.empty()) {
172167
int num_isol = isol_pause.size();
173168
std::sort(isol_pause.begin(), isol_pause.end());
174169
min_pause = isol_pause[num_isol / 2];
175170
}
176-
printf("\n============== Calculated Statistics ================\n");
177-
printf("MinEvents:%ld MinPause:%ld ticks \n", min_events, min_pause);
171+
printf("\n>>> MinEvents:%ld MinPause:%ld ticks \n\n", min_events, min_pause);
178172

179173
int min_sd_prio = sched_get_priority_min(SCHED_OTHER);
180-
double wait_secs = ROUGHLY_ONE_SECOND_IN_TICKS / (freqGHz * 1E9);
181174
for (int core = 0; core < numcores; ++core) {
182-
Options opt;
175+
Stats& opt(stats[core]);
183176
opt.core = core;
177+
opt.wait_ticks = wait_ticks;
184178
opt.policy = SCHED_OTHER;
185179
opt.prio = min_sd_prio;
186180
opt.print = false;
181+
opt.async = async;
187182
runJitterTestInCore(opt);
188-
double excess_events = (double(opt.hist.count()) - min_events) / wait_secs;
189-
double jitter = (double(opt.hist.percentile(99.9)) - min_pause) / (freqGHz * 1E3);
190-
printf("Core:%-2d ExcessEvents: %6.0f/sec Jitter: %6.1fus\n", core,
183+
}
184+
185+
for (Stats& s : stats) {
186+
if (async) {
187+
void* retval;
188+
pthread_join(s.tid, &retval);
189+
}
190+
double wait_secs = s.wait_ticks / (freqGHz * 1E9);
191+
double excess_events = (double(s.hist.count()) - min_events) / wait_secs;
192+
double jitter = (double(s.hist.percentile(99.9)) - min_pause) / (freqGHz * 1E3);
193+
printf("Core:%-2ld ExcessEvents: %6.0f/sec Jitter: %6.1fus\n", s.core,
191194
excess_events, jitter);
192195
}
193-
}
196+
}
197+
198+
int main() {
199+
lockAllMemory();
200+
auto numcores = getNumberOfCores();
201+
auto affinity = makeSet(getThreadAffinity());
202+
int policy;
203+
struct sched_param param;
204+
pthread_getschedparam(pthread_self(), &policy, &param);
205+
206+
printf("CPU Freq:%6.1f GHz Policy:%s Priority:%d Cores:%ld Avail:%ld ", freqGHz,
207+
getPolicyName(policy), param.sched_priority, numcores, affinity.size());
208+
for (auto core : affinity) {
209+
printf("%ld ", core);
210+
}
211+
printf("\n");
212+
if (numcores == affinity.size()) {
213+
printf(
214+
"*** There are no isolated cores to get reliable stats on. Results may be "
215+
"misleading.\n");
216+
}
217+
printf("\n\n*********** Running asynchronous tests \n\n");
218+
runAllTests(true);
219+
printf("\n\n*********** Running synchronous tests (better) \n\n");
220+
runAllTests(false);
221+
}

0 commit comments

Comments
 (0)