source: doc/theses/thierry_delisle_PhD/code/readyQ_proto/bts.cpp@ affb51b

ADT ast-experimental
Last change on this file since affb51b was f9f3775, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Moved phd code for the readQ prototype to it's own folder

  • Property mode set to 100644
File size: 6.8 KB
Line 
1#include <array>
2#include <iomanip>
3#include <iostream>
4#include <locale>
5#include <string>
6#include <thread>
7#include <vector>
8
9#include <getopt.h>
10#include <unistd.h>
11#include <sys/sysinfo.h>
12
13#include "utils.hpp"
14
15// ================================================================================================
16// UTILS
17// ================================================================================================
18
19struct local_stat_t {
20 size_t cnt = 0;
21};
22
23struct global_stat_t {
24 std::atomic_size_t cnt = { 0 };
25};
26
27void atomic_max(std::atomic_size_t & target, size_t value) {
28 for(;;) {
29 size_t expect = target.load(std::memory_order_relaxed);
30 if(value <= expect) return;
31 bool success = target.compare_exchange_strong(expect, value);
32 if(success) return;
33 }
34}
35
36void atomic_min(std::atomic_size_t & target, size_t value) {
37 for(;;) {
38 size_t expect = target.load(std::memory_order_relaxed);
39 if(value >= expect) return;
40 bool success = target.compare_exchange_strong(expect, value);
41 if(success) return;
42 }
43}
44
45void tally_stats(global_stat_t & global, local_stat_t & local) {
46 global.cnt += local.cnt;
47}
48
49void waitfor(double & duration, barrier_t & barrier, std::atomic_bool & done) {
50 std::cout << "Starting" << std::endl;
51 auto before = Clock::now();
52 barrier.wait(0);
53
54 while(true) {
55 usleep(100000);
56 auto now = Clock::now();
57 duration_t durr = now - before;
58 if( durr.count() > duration ) {
59 done = true;
60 break;
61 }
62 std::cout << "\r" << std::setprecision(4) << durr.count();
63 std::cout.flush();
64 }
65
66 barrier.wait(0);
67 auto after = Clock::now();
68 duration_t durr = after - before;
69 duration = durr.count();
70 std::cout << "\rClosing down" << std::endl;
71}
72
73void waitfor(double & duration, barrier_t & barrier, const std::atomic_size_t & count) {
74 std::cout << "Starting" << std::endl;
75 auto before = Clock::now();
76 barrier.wait(0);
77
78 while(true) {
79 usleep(100000);
80 size_t c = count.load();
81 if( c == 0 ) {
82 break;
83 }
84 std::cout << "\r" << c;
85 std::cout.flush();
86 }
87
88 barrier.wait(0);
89 auto after = Clock::now();
90 duration_t durr = after - before;
91 duration = durr.count();
92 std::cout << "\rClosing down" << std::endl;
93}
94
95void print_stats(double duration, unsigned nthread, global_stat_t & global) {
96 std::cout << "Done" << std::endl;
97
98 size_t ops = global.cnt;
99 size_t ops_sec = size_t(double(ops) / duration);
100 size_t ops_thread = ops_sec / nthread;
101 auto dur_nano = duration_cast<std::nano>(1.0);
102
103 std::cout << "Duration : " << duration << "s\n";
104 std::cout << "ns/Op : " << ( dur_nano / ops_thread )<< "\n";
105 std::cout << "Ops/sec/thread: " << ops_thread << "\n";
106 std::cout << "Ops/sec : " << ops_sec << "\n";
107 std::cout << "Total ops : " << ops << "\n";
108}
109
110static inline bool bts(std::atomic_size_t & target, size_t bit ) {
111 /*
112 int result = 0;
113 asm volatile(
114 "LOCK btsq %[bit], %[target]\n\t"
115 :"=@ccc" (result)
116 : [target] "m" (target), [bit] "r" (bit)
117 );
118 return result != 0;
119 /*/
120 size_t mask = 1ul << bit;
121 size_t ret = target.fetch_or(mask, std::memory_order_relaxed);
122 return (ret & mask) != 0;
123 //*/
124}
125
126static inline bool btr(std::atomic_size_t & target, size_t bit ) {
127 /*
128 int result = 0;
129 asm volatile(
130 "LOCK btrq %[bit], %[target]\n\t"
131 :"=@ccc" (result)
132 : [target] "m" (target), [bit] "r" (bit)
133 );
134 return result != 0;
135 /*/
136 size_t mask = 1ul << bit;
137 size_t ret = target.fetch_and(~mask, std::memory_order_relaxed);
138 return (ret & mask) != 0;
139 //*/
140}
141
142// ================================================================================================
143// EXPERIMENTS
144// ================================================================================================
145
146// ================================================================================================
147__attribute__((noinline)) void runPingPong_body(
148 std::atomic<bool>& done,
149 local_stat_t & local,
150 std::atomic_size_t & target,
151 size_t id
152) {
153 while(__builtin_expect(!done.load(std::memory_order_relaxed), true)) {
154
155 bool ret;
156 ret = bts(target, id);
157 assert(!ret);
158
159 // -----
160
161 ret = btr(target, id);
162 assert(ret);
163 local.cnt++;
164 }
165}
166
167void run(unsigned nthread, double duration) {
168 // Barrier for synchronization
169 barrier_t barrier(nthread + 1);
170
171 // Data to check everything is OK
172 global_stat_t global;
173
174 // Flag to signal termination
175 std::atomic_bool done = { false };
176
177 std::cout << "Initializing ";
178 // List being tested
179 std::atomic_size_t word = { 0 };
180 {
181 std::thread * threads[nthread];
182 unsigned i = 1;
183 for(auto & t : threads) {
184 t = new std::thread([&done, &word, &barrier, &global](unsigned tid) {
185 local_stat_t local;
186
187 // affinity(tid);
188
189 barrier.wait(tid);
190
191 // EXPERIMENT START
192
193 runPingPong_body(done, local, word, tid - 1);
194
195 // EXPERIMENT END
196
197 barrier.wait(tid);
198
199 tally_stats(global, local);
200 }, i++);
201 }
202
203 waitfor(duration, barrier, done);
204
205 for(auto t : threads) {
206 t->join();
207 delete t;
208 }
209 }
210
211 print_stats(duration, nthread, global);
212}
213
214// ================================================================================================
215
216int main(int argc, char * argv[]) {
217
218 double duration = 5.0;
219 unsigned nthreads = 2;
220
221 std::cout.imbue(std::locale(""));
222
223 for(;;) {
224 static struct option options[] = {
225 {"duration", required_argument, 0, 'd'},
226 {"nthreads", required_argument, 0, 't'},
227 {0, 0, 0, 0}
228 };
229
230 int idx = 0;
231 int opt = getopt_long(argc, argv, "d:t:", options, &idx);
232
233 std::string arg = optarg ? optarg : "";
234 size_t len = 0;
235 switch(opt) {
236 case -1:
237 if(optind != argc) {
238 std::cerr << "Too many arguments " << argc << " " << idx << std::endl;
239 goto usage;
240 }
241 goto run;
242 // Numeric Arguments
243 case 'd':
244 try {
245 duration = std::stod(optarg, &len);
246 if(len != arg.size()) { throw std::invalid_argument(""); }
247 } catch(std::invalid_argument &) {
248 std::cerr << "Duration must be a valid double, was " << arg << std::endl;
249 goto usage;
250 }
251 break;
252 case 't':
253 try {
254 nthreads = std::stoul(optarg, &len);
255 if(len != arg.size() || nthreads > (8 * sizeof(size_t))) { throw std::invalid_argument(""); }
256 } catch(std::invalid_argument &) {
257 std::cerr << "Number of threads must be a positive integer less than or equal to " << sizeof(size_t) * 8 << ", was " << arg << std::endl;
258 goto usage;
259 }
260 break;
261 // Other cases
262 default: /* ? */
263 std::cerr << opt << std::endl;
264 usage:
265 std::cerr << "Usage: " << argv[0] << ": [options]" << std::endl;
266 std::cerr << std::endl;
267 std::cerr << " -d, --duration=DURATION Duration of the experiment, in seconds" << std::endl;
268 std::cerr << " -t, --nthreads=NTHREADS Number of kernel threads" << std::endl;
269 std::exit(1);
270 }
271 }
272 run:
273
274 check_cache_line_size();
275
276 std::cout << "Running " << nthreads << " threads for " << duration << " seconds" << std::endl;
277 run(nthreads, duration);
278 return 0;
279}
Note: See TracBrowser for help on using the repository browser.