-
Notifications
You must be signed in to change notification settings - Fork 0
/
nondeterminism.h
136 lines (107 loc) · 4.18 KB
/
nondeterminism.h
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
#ifndef CORRBENCH_NONDETERMINISM_H
#define CORRBENCH_NONDETERMINISM_H
#define USE_TEMP_COMPARE_BUF
#define SIGNAL_FILE_NAME_ERROR "error_not_present"
// Settings for execution
//#define USE_DISTURBED_THREAD_ORDER
// define default vlaues if define via compiler option in missing
#ifndef NUM_THREADS
#define NUM_THREADS 2
#endif
#ifndef BUFFER_LENGTH_INT
#define BUFFER_LENGTH_INT 10
//#define BUFFER_LENGTH_INT 10000
#endif
#define BUFFER_LENGTH_BYTE (BUFFER_LENGTH_INT * sizeof(int))
// circumvent a tsan bug when using memset
// if definded memory is touced in a for loop
#define CIRCUMVENT_TSAN_BUG
#ifdef USE_DISTURBED_THREAD_ORDER
#define DISTURB_THREAD_ORDER us_sleep(omp_get_thread_num());
#else
#define DISTURB_THREAD_ORDER
#endif
#include <mpi.h>
#include <omp.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#ifdef USE_TEMP_COMPARE_BUF
#include <stdlib.h>
#endif
// macros to check for a correct ordering of the MPI calls
#define DEF_ORDER_CAPTURING_VARIABLES \
int flag = 0, before_a = 0, after_a = 0, before_b = 0, after_b = 0, overlap_count = 0;
#define CHECK_OVERLAP_BEGIN \
int before; \
_Pragma("omp atomic capture") before = flag++; \
if (before != 0) \
_Pragma("omp atomic") overlap_count++;
// its not that important to count the exact number of overlapping operations, as one overlap is already faulty in our
// cases
// overlap will be checked on entry
#define CHECK_OVERLAP_END _Pragma("omp atomic ")-- flag;
// can only be used, when each operation is only executed once
#define ENTER_CALL_A _Pragma("omp atomic capture") before_a = flag++;
#define EXIT_CALL_A _Pragma("omp atomic capture") after_a = flag++;
#define ENTER_CALL_B _Pragma("omp atomic capture") before_b = flag++;
#define EXIT_CALL_B _Pragma("omp atomic capture") after_b = flag++;
#define CHECK_FOR_EXPECTED_ORDER (before_a == 0 && after_a == 1 && before_b == 2 && after_b == 3)
// Tell Corrbench if the error has manifested itself
// or if there was no error e.g. "wrong" thread ordering prevented a data race
static inline void has_error_manifested(bool manifested) {
// else do nothing: we assume that an error was present unless signaled otherwise
if (!manifested) {
// just create the signal file
int rank;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
size_t needed = snprintf(NULL, 0, "%s%d", SIGNAL_FILE_NAME_ERROR, rank) + 1; // +1 for trailing \0
char *fname = malloc(needed);
snprintf(fname, needed, "%s%d", SIGNAL_FILE_NAME_ERROR, rank);
FILE *file_ptr = fopen(fname, "w");
fclose(file_ptr);
free(fname);
printf("ERROR_NOT_PRESENT\n");
}
}
// init unique message buffer and checks if the content is the expected content without the need for data transfer
// this way we can find "wrong" message matching
// sender and receiver need to use the same pattern_id
const unsigned char pattern_list[8] = {0x0F, 0xF0, 0xAA, 0x55, 0x99, 0xCC, 0x00, 0xFF};
static inline void fill_message_buffer(void *buf, size_t length, int pattern) {
#ifdef CIRCUMVENT_TSAN_BUG
char *buf_ptr = (char *)buf; // make it clear that we iterate through the single bytes
for (size_t i = 0; i < length; ++i) {
buf_ptr[i] = pattern_list[pattern];
}
#else
memset(buf, pattern_list[pattern], length);
#endif
}
// check if message buffer is correct
static inline bool has_buffer_expected_content(void *buf, size_t length, int pattern) {
#ifdef USE_TEMP_COMPARE_BUF
void *tmp_buf = malloc(length);
memset(tmp_buf, pattern_list[pattern], length);
int memcmp_result = memcmp(tmp_buf, buf, length);
free(tmp_buf);
return memcmp_result == 0;
#else
char *buf_ptr = (char *)buf; // make it clear that we iterate through the single bytes
for (size_t i = 0; i < length; ++i) {
if (buf_ptr[i] != pattern_list[pattern])
return false;
}
return true;
#endif
}
static inline void us_sleep(long int microseconds) {
const long int scale2sec = (long int)1e6;
const long int scale2nsec = 1000;
const long int tv_sec = microseconds / scale2sec;
const long int tv_nano = (microseconds % scale2sec) * scale2nsec;
struct timespec ts = {tv_sec, tv_nano};
nanosleep(&ts, NULL);
}
#endif