44#include < iostream>
55#include < set>
66#include < cstring>
7+ #include < unistd.h>
78
89#include " CpuUtils.h"
910#include " MicroStats.h"
1314using Histogram = MicroStats<8 >;
1415const 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
2530double calcFrequencyGHz (uint64_t ticks) {
@@ -55,7 +60,7 @@ uint64_t calcQuantum(uint64_t ticks) {
5560uint64_t quantum = calcQuantum(ROUGHLY_ONE_SECOND_IN_TICKS );
5661double 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
7784static 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, ¶m);
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, ¶m);
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