43
43
#define ENOUGH_MEASURE 10000
44
44
#define TEST_TRIES 10
45
45
46
- static t_context_t * t ;
46
+ /* Number of percentiles to calculate */
47
+ #define NUM_PERCENTILES (100)
48
+ #define DUDECT_TESTS (NUM_PERCENTILES + 1)
49
+
50
+ static t_context_t * ctxs [DUDECT_TESTS ];
47
51
48
52
/* threshold values for Welch's t-test */
49
53
enum {
@@ -56,6 +60,37 @@ static void __attribute__((noreturn)) die(void)
56
60
exit (111 );
57
61
}
58
62
63
+ static int64_t percentile (const int64_t * a_sorted , double which , size_t size )
64
+ {
65
+ assert (which >= 0 && which <= 1.0 );
66
+ size_t pos = (size_t ) (which * size );
67
+ return a_sorted [pos ];
68
+ }
69
+
70
+ /* leverages the fact that comparison expressions return 1 or 0. */
71
+ static int cmp (const void * aa , const void * bb )
72
+ {
73
+ int64_t a = * (const int64_t * ) aa , b = * (const int64_t * ) bb ;
74
+ return (a > b ) - (a < b );
75
+ }
76
+
77
+ /* This function is used to set different thresholds for cropping measurements.
78
+ * To filter out slow measurements, we keep only the fastest ones by a
79
+ * complementary exponential decay scale as thresholds for cropping
80
+ * measurements: threshold(x) = 1 - 0.5^(10 * x / N_MEASURES), where x is the
81
+ * counter of the measurement.
82
+ */
83
+ static void prepare_percentiles (int64_t * exec_times , int64_t * percentiles )
84
+ {
85
+ qsort (exec_times , N_MEASURES , sizeof (int64_t ), cmp );
86
+
87
+ for (size_t i = 0 ; i < NUM_PERCENTILES ; i ++ ) {
88
+ percentiles [i ] = percentile (
89
+ exec_times , 1 - (pow (0.5 , 10 * (double ) (i + 1 ) / NUM_PERCENTILES )),
90
+ N_MEASURES );
91
+ }
92
+ }
93
+
59
94
static void differentiate (int64_t * exec_times ,
60
95
const int64_t * before_ticks ,
61
96
const int64_t * after_ticks )
@@ -64,7 +99,9 @@ static void differentiate(int64_t *exec_times,
64
99
exec_times [i ] = after_ticks [i ] - before_ticks [i ];
65
100
}
66
101
67
- static void update_statistics (const int64_t * exec_times , uint8_t * classes )
102
+ static void update_statistics (const int64_t * exec_times ,
103
+ uint8_t * classes ,
104
+ int64_t * percentiles )
68
105
{
69
106
for (size_t i = 0 ; i < N_MEASURES ; i ++ ) {
70
107
int64_t difference = exec_times [i ];
@@ -73,15 +110,36 @@ static void update_statistics(const int64_t *exec_times, uint8_t *classes)
73
110
continue ;
74
111
75
112
/* do a t-test on the execution time */
76
- t_push (t , difference , classes [i ]);
113
+ t_push (ctxs [0 ], difference , classes [i ]);
114
+
115
+ /* t-test on cropped execution times, for several cropping thresholds.
116
+ */
117
+ for (size_t j = 0 ; j < NUM_PERCENTILES ; j ++ ) {
118
+ if (difference < percentiles [j ]) {
119
+ t_push (ctxs [j + 1 ], difference , classes [i ]);
120
+ }
121
+ }
77
122
}
78
123
}
79
124
125
+ static t_context_t * max_test ()
126
+ {
127
+ size_t max_idx = 0 ;
128
+ double max_t = 0.0f ;
129
+ for (size_t i = 0 ; i < NUM_PERCENTILES + 1 ; i ++ ) {
130
+ double t = fabs (t_compute (ctxs [i ]));
131
+ if (t > max_t ) {
132
+ max_t = t ;
133
+ max_idx = i ;
134
+ }
135
+ }
136
+ return ctxs [max_idx ];
137
+ }
138
+
80
139
static bool report (void )
81
140
{
82
- double max_t = fabs ( t_compute ( t ) );
141
+ t_context_t * t = max_test ( );
83
142
double number_traces_max_t = t -> n [0 ] + t -> n [1 ];
84
- double max_tau = max_t / sqrt (number_traces_max_t );
85
143
86
144
printf ("\033[A\033[2K" );
87
145
printf ("measure: %7.2lf M, " , (number_traces_max_t / 1e6 ));
@@ -91,6 +149,9 @@ static bool report(void)
91
149
return false;
92
150
}
93
151
152
+ double max_t = fabs (t_compute (t ));
153
+ double max_tau = max_t / sqrt (number_traces_max_t );
154
+
94
155
/* max_t: the t statistic value
95
156
* max_tau: a t value normalized by sqrt(number of measurements).
96
157
* this way we can compare max_tau taken with different
@@ -123,6 +184,7 @@ static bool doit(int mode)
123
184
int64_t * exec_times = calloc (N_MEASURES , sizeof (int64_t ));
124
185
uint8_t * classes = calloc (N_MEASURES , sizeof (uint8_t ));
125
186
uint8_t * input_data = calloc (N_MEASURES * CHUNK_SIZE , sizeof (uint8_t ));
187
+ int64_t * percentiles = calloc (NUM_PERCENTILES , sizeof (int64_t ));
126
188
127
189
if (!before_ticks || !after_ticks || !exec_times || !classes ||
128
190
!input_data ) {
@@ -133,28 +195,32 @@ static bool doit(int mode)
133
195
134
196
bool ret = measure (before_ticks , after_ticks , input_data , mode );
135
197
differentiate (exec_times , before_ticks , after_ticks );
136
- update_statistics (exec_times , classes );
198
+ prepare_percentiles (exec_times , percentiles );
199
+ update_statistics (exec_times , classes , percentiles );
137
200
ret &= report ();
138
201
139
202
free (before_ticks );
140
203
free (after_ticks );
141
204
free (exec_times );
142
205
free (classes );
143
206
free (input_data );
207
+ free (percentiles );
144
208
145
209
return ret ;
146
210
}
147
211
148
212
static void init_once (void )
149
213
{
150
214
init_dut ();
151
- t_init (t );
215
+ for (size_t i = 0 ; i < DUDECT_TESTS ; i ++ ) {
216
+ ctxs [i ] = malloc (sizeof (t_context_t ));
217
+ t_init (ctxs [i ]);
218
+ }
152
219
}
153
220
154
221
static bool test_const (char * text , int mode )
155
222
{
156
223
bool result = false;
157
- t = malloc (sizeof (t_context_t ));
158
224
159
225
for (int cnt = 0 ; cnt < TEST_TRIES ; ++ cnt ) {
160
226
printf ("Testing %s...(%d/%d)\n\n" , text , cnt , TEST_TRIES );
@@ -166,7 +232,11 @@ static bool test_const(char *text, int mode)
166
232
if (result )
167
233
break ;
168
234
}
169
- free (t );
235
+
236
+ for (size_t i = 0 ; i < DUDECT_TESTS ; i ++ ) {
237
+ free (ctxs [i ]);
238
+ }
239
+
170
240
return result ;
171
241
}
172
242
0 commit comments