-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
425 lines (397 loc) · 14.3 KB
/
main.cpp
File metadata and controls
425 lines (397 loc) · 14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
/** @file key.hpp
* @author Daniel Zainzinger
* @author Noah Bruns
* @date 2.6.2020
*
* @brief Main file to test the datastructures
*/
#include "Coarse_Grained.hpp"
#include "Fine_Grained.hpp"
#include "Lazy.hpp"
#include "Lazy_mem.hpp"
#include "Lock_free.hpp"
#include "Lock_free_impr.hpp"
#include "Lock_free_impr_mem.hpp"
#include "Optimistic.hpp"
#include "Optimistic_mem.hpp"
#include "benchmark.hpp"
#include "stdio.h"
#include "termcolor.hpp"
#include <chrono>
#include <fstream>
#include <omp.h>
#include <sstream>
#include <vector>
using namespace termcolor;
#include <assert.h>
#include <set>
#include <unistd.h>
#define START_FILE 0
#define PRE_FILENAME "testcases/pre%zu.csv"
#define MAIN_FILENAME "testcases/main%zu.csv"
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
static uint32_t read_file(string name, vector<vector<int>> *cases);
static void runtest(vector<vector<int>> cases, SetList<int> *list, sub_benchMark_t *sub_benchMark, size_t thread_am);
static void check(vector<vector<int>> cases, SetList<int> *list, sub_benchMark_t *sub_benchMark, size_t thread_am);
/**
* @brief Entrypoint of the Programm
* @details calls perform for each datastructure few benchmarks and write the result in a csv file
* @param [const] PRE_FILENAME filename of the add testfile
* @param [const] MAIN_FILENAME filename of the mixed testfile
*/
int main(int argc, char *argv[]) {
////////////////////////////////////////Read options//////////////////////////////////////////////
int opt;
size_t thread_am = omp_get_num_procs(); // amount of threads
int tested_list = 0;
while ((opt = getopt(argc, argv, "n:t:")) != -1) {
switch (opt) {
case 'n':
thread_am = (size_t)atoi(optarg);
break;
case 't':
tested_list = atoi(optarg);
break;
default: /* '?' */
cout << "usage ./main [-n thread_amount]" << endl;
}
}
benchMark_t benchMark;
benchMark_t benchMark_arr[REPEAT_TESTS];
SetList<int> *list;
size_t testCnt = START_FILE;
while (true) { // Read all available main and pre files
vector<vector<int>> testcases[2];
uint32_t testSizePre = 0;
uint32_t testSizeMain = 0;
char pre_file[20];
char main_file[20];
sprintf(pre_file, PRE_FILENAME, testCnt);
sprintf(main_file, MAIN_FILENAME, testCnt);
testSizePre = read_file(pre_file, &testcases[0]);
testSizeMain = read_file(main_file, &testcases[1]);
if (testSizePre == 0 || testSizeMain == 0) { // stop, if there is no file to read
break;
}
int T_max = MIN(MAX(testSizePre, testSizeMain), thread_am);
cout << blue << main_file << endl;
if (tested_list == 0 || tested_list == 1) {
///////////////// CoarseList///////////////////////
cout << white << "CoarseList:" << endl;
for (size_t i = 0; i < REPEAT_TESTS; i++) {
list = new CoarseList<int>();
cout << "Pre: ";
benchMark_arr[i] = BENCHMARK_E;
runtest(testcases[0], list, &benchMark_arr[i].pre, thread_am);
cout << "Main: ";
runtest(testcases[1], list, &benchMark_arr[i].main, thread_am);
cout << "Check: ";
check(testcases[1], list, &benchMark_arr[i].check, thread_am);
delete list;
}
benchMark = BENCHMARK_E;
averBenchm(benchMark_arr, &benchMark);
if (write_csv("CoarseList", benchMark, testSizePre, testSizeMain) == 0) {
break;
}
}
////////////////////// FineList /////////////////////
if (tested_list == 0 || tested_list == 2) {
cout << white << "FineList:" << endl;
for (size_t i = 0; i < REPEAT_TESTS; i++) {
list = new FineList<int>();
cout << "Pre: ";
benchMark_arr[i] = BENCHMARK_E;
runtest(testcases[0], list, &benchMark_arr[i].pre, thread_am);
cout << "Main: ";
runtest(testcases[1], list, &benchMark_arr[i].main, thread_am);
cout << "Check: ";
check(testcases[1], list, &benchMark_arr[i].check, thread_am);
delete list;
}
benchMark = BENCHMARK_E;
averBenchm(benchMark_arr, &benchMark);
if (write_csv("FineList", benchMark, testSizePre, testSizeMain) == 0) {
break;
}
}
////////////////////// Optimistic /////////////////////
if (tested_list == 0 || tested_list == 3) {
cout << white << "Optimistic:" << endl;
for (size_t i = 0; i < REPEAT_TESTS; i++) {
list = new Optimistic<int>();
cout << "Pre: ";
benchMark_arr[i] = BENCHMARK_E;
runtest(testcases[0], list, &benchMark_arr[i].pre, thread_am);
cout << "Main: ";
runtest(testcases[1], list, &benchMark_arr[i].main, thread_am);
cout << "Check: ";
check(testcases[1], list, &benchMark_arr[i].check, thread_am);
delete list;
}
benchMark = BENCHMARK_E;
averBenchm(benchMark_arr, &benchMark);
if (write_csv("Optimistic", benchMark, testSizePre, testSizeMain) == 0) {
break;
}
}
////////////////////// Optimistic_mem /////////////////////
if (tested_list == 0 || tested_list == 4) {
cout << white << "Optimistic_mem:" << endl;
for (size_t i = 0; i < REPEAT_TESTS; i++) {
list = new Optimistic_mem<int>(T_max);
cout << "Pre: ";
benchMark_arr[i] = BENCHMARK_E;
runtest(testcases[0], list, &benchMark_arr[i].pre, thread_am);
cout << "Main: ";
runtest(testcases[1], list, &benchMark_arr[i].main, thread_am);
cout << "Check: ";
check(testcases[1], list, &benchMark_arr[i].check, thread_am);
delete list;
}
benchMark = BENCHMARK_E;
averBenchm(benchMark_arr, &benchMark);
if (write_csv("Optimistic_mem", benchMark, testSizePre, testSizeMain) == 0) {
break;
}
}
////////////////////// Lazy /////////////////////
if (tested_list == 0 || tested_list == 5) {
cout << white << "Lazy:" << endl;
for (size_t i = 0; i < REPEAT_TESTS; i++) {
list = new Lazy<int>();
cout << "Pre: ";
benchMark_arr[i] = BENCHMARK_E;
runtest(testcases[0], list, &benchMark_arr[i].pre, thread_am);
cout << "Main: ";
runtest(testcases[1], list, &benchMark_arr[i].main, thread_am);
cout << "Check: ";
check(testcases[1], list, &benchMark_arr[i].check, thread_am);
delete list;
}
benchMark = BENCHMARK_E;
averBenchm(benchMark_arr, &benchMark);
if (write_csv("Lazy", benchMark, testSizePre, testSizeMain) == 0) {
break;
}
}
////////////////////// Lazy_mem /////////////////////
if (tested_list == 0 || tested_list == 6) {
cout << white << "Lazy_mem:" << endl;
for (size_t i = 0; i < REPEAT_TESTS; i++) {
list = new Lazy_mem<int>(T_max);
cout << "Pre: ";
benchMark_arr[i] = BENCHMARK_E;
runtest(testcases[0], list, &benchMark_arr[i].pre, thread_am);
cout << "Main: ";
runtest(testcases[1], list, &benchMark_arr[i].main, thread_am);
cout << "Check: ";
check(testcases[1], list, &benchMark_arr[i].check, thread_am);
delete list;
}
benchMark = BENCHMARK_E;
averBenchm(benchMark_arr, &benchMark);
if (write_csv("Lazy_mem", benchMark, testSizePre, testSizeMain) == 0) {
break;
}
}
////////////////////// LockFree /////////////////////
if (tested_list == 0 || tested_list == 7) {
cout << white << "LockFree:" << endl;
for (size_t i = 0; i < REPEAT_TESTS; i++) {
list = new LockFree<int>();
cout << "Pre: ";
benchMark_arr[i] = BENCHMARK_E;
runtest(testcases[0], list, &benchMark_arr[i].pre, thread_am);
cout << "Main: ";
runtest(testcases[1], list, &benchMark_arr[i].main, thread_am);
cout << "Check: ";
check(testcases[1], list, &benchMark_arr[i].check, thread_am);
delete list;
}
benchMark = BENCHMARK_E;
averBenchm(benchMark_arr, &benchMark);
if (write_csv("LockFree", benchMark, testSizePre, testSizeMain) == 0) {
break;
}
}
////////////////////// LockFree_impr /////////////////////
if (tested_list == 0 || tested_list == 8) {
cout << white << "LockFree_impr:" << endl;
for (size_t i = 0; i < REPEAT_TESTS; i++) {
list = new LockFree_impr<int>();
cout << "Pre: ";
benchMark_arr[i] = BENCHMARK_E;
runtest(testcases[0], list, &benchMark_arr[i].pre, thread_am);
cout << "Main: ";
runtest(testcases[1], list, &benchMark_arr[i].main, thread_am);
cout << "Check: ";
check(testcases[1], list, &benchMark_arr[i].check, thread_am);
delete list;
}
benchMark = BENCHMARK_E;
averBenchm(benchMark_arr, &benchMark);
if (write_csv("LockFree_impr", benchMark, testSizePre, testSizeMain) == 0) {
break;
}
}
////////////////////// LockFree_impr_mem /////////////////////
if (tested_list == 0 || tested_list == 9) {
cout << white << "LockFree_impr_mem:" << endl;
for (size_t i = 0; i < REPEAT_TESTS; i++) {
list = new LockFree_impr_mem<int>(T_max);
cout << "Pre: ";
benchMark_arr[i] = BENCHMARK_E;
runtest(testcases[0], list, &benchMark_arr[i].pre, thread_am);
cout << "Main: ";
runtest(testcases[1], list, &benchMark_arr[i].main, thread_am);
cout << "Check: ";
check(testcases[1], list, &benchMark_arr[i].check, thread_am);
delete list;
}
benchMark = BENCHMARK_E;
averBenchm(benchMark_arr, &benchMark);
if (write_csv("LockFree_impr_mem", benchMark, testSizePre, testSizeMain) == 0) {
break;
}
}
testCnt++;
}
return 0;
}
/**
* @brief Function add values from cases to the datastructure and removes them, if there a below 0
* @details Function starts maximal available threads. It will add all positiv values from the vector "cases"
* and remove all negative. Also the timemessurement takes place in this function.
* @param[in] cases vector with all testcases
* @param[in] list datastructure for which the benchmark is performed
* @param[out] sub_benchMark a struct, which stores information for benchmarking
*/
static void runtest(vector<vector<int>> cases, SetList<int> *list, sub_benchMark_t *sub_benchMark, size_t thread_am) {
auto startTime = chrono::high_resolution_clock::now();
size_t Tmax = MIN(cases.size(), thread_am);
sub_benchMark_t sub_benchMark_arr[Tmax];
#pragma omp parallel shared(sub_benchMark_arr) num_threads(Tmax)
// limit the maximal threads, if testfile has less lines
{
sub_benchMark_t sub_benchMark_loc = SUB_BENCHMARK_E;
sub_benchMark_loc.cores = MIN((size_t)omp_get_num_procs(), thread_am); // used number of threads
size_t tid = omp_get_thread_num(); // curred thread id
assert(tid < Tmax); // thread id can be not higher than available Threads
#pragma omp for
for (auto it = cases.begin(); it < cases.end(); it++) {
for (const auto &j : *it) {
if (j < 0) {
list->remove(-j, &sub_benchMark_loc);
if (list->contains(j, &sub_benchMark_loc)) {
cout << red << "Error: " << reset << j << " in list" << endl;
}
} else if (j > 0) {
list->add(j, &sub_benchMark_loc);
if (!list->contains(j, &sub_benchMark_loc)) {
cout << red << "Error 1: " << reset << j << " not in list" << endl;
}
} else
throw new invalid_argument("0 not allowed");
}
}
sub_benchMark_arr[tid] = sub_benchMark_loc;
list->emptyQueue(true);
}
uint16_t cores = sub_benchMark_arr[0].cores; // amount of cores from core 0
auto finishTime = chrono::high_resolution_clock::now();
chrono::duration<double> elapsed = finishTime - startTime;
auto ms = chrono::duration_cast<chrono::milliseconds>(elapsed).count();
sub_benchMark->time = ms;
sub_benchMark->cores = cores;
for (size_t i = 0; i < cores; i++) {
sub_benchMark->goToStart += sub_benchMark_arr[i].goToStart;
sub_benchMark->lostTime += sub_benchMark_arr[i].lostTime;
}
cout << green << "Test succeeded" << reset << " in " << ms << "ms with " << cores << " cores and " << Tmax
<< " Threads" << endl;
}
/**
* @brief Function checks, iff all values in the dataset
* @details It checks with the maximal available threads, if all values from the cases vector
* with negative not in the list and positive values in the list.
* @param[in] cases vector with all testcases
* @param[in] list datastructure for which the benchmark is performed
* @param[out] sub_benchMark a struct, which stores information for benchmarking
*/
static void check(vector<vector<int>> cases, SetList<int> *list, sub_benchMark_t *sub_benchMark, size_t thread_am) {
auto startTime = chrono::high_resolution_clock::now();
// Compare to Valid
bool correct = true;
size_t Tmax = MIN(cases.size(), thread_am);
sub_benchMark_t sub_benchMark_arr[Tmax];
#pragma omp parallel num_threads(Tmax)
{
sub_benchMark_t sub_benchMark_loc = SUB_BENCHMARK_E;
/* get the total number of threads available in this parallel region */
sub_benchMark_loc.cores = omp_get_num_threads();
size_t tid = omp_get_thread_num();
#pragma omp for
for (auto it = cases.begin(); it < cases.end(); it++) {
for (const auto &j : *it) {
if (j < 0) {
if (list->contains(-j, &sub_benchMark_loc)) {
cout << red << "Error: " << reset << j << " in list" << endl;
}
} else if (j > 0) {
if (!list->contains(j, &sub_benchMark_loc)) {
cout << red << "Error 1: " << reset << j << " not in list" << endl;
}
} else
throw new invalid_argument("0 not allowed");
}
}
sub_benchMark_arr[tid] = sub_benchMark_loc;
}
auto finishTime = chrono::high_resolution_clock::now();
chrono::duration<double> elapsed = finishTime - startTime;
auto ms = chrono::duration_cast<chrono::milliseconds>(elapsed).count();
uint16_t cores = sub_benchMark_arr[0].cores; // amount of cores from core 0
sub_benchMark->time = ms;
sub_benchMark->cores = cores;
// sum up the "goToStart" from all threads
for (size_t i = 0; i < cores; i++) {
sub_benchMark->goToStart += sub_benchMark_arr[i].goToStart;
sub_benchMark->lostTime += sub_benchMark_arr[i].lostTime;
}
if (correct) {
cout << green << "Test succeeded" << reset << " in " << ms << "ms with " << cores << " cores and " << Tmax
<< " Threads" << endl;
}
cout << endl;
}
/**
* @brief Function read a csv file and put all values to the cases vector
* @param[in] name name of the file, which should be read (csv file with "," as a seperator)
* @param[out] cases vector with all testcases
* @return amount of values, that was read, 0 if it was not possible to read
*/
static uint32_t read_file(string name, vector<vector<int>> *cases) {
ifstream file(name);
string line;
uint32_t testSize = 0;
// Load Test cases
if (file.is_open()) {
while (getline(file, line)) {
vector<int> x;
string segment;
stringstream l(line);
while (getline(l, segment, ',')) {
auto t = stoi(segment);
x.push_back(t);
testSize++;
}
cases->push_back(x);
}
file.close();
return testSize;
} else {
return 0;
}
}