Skip to content

Commit f53314e

Browse files
authored
Merge pull request #283 from BennyWang1007/dudect_fix
Improve dudect test with cropped time analysis
2 parents 9563d40 + 83077d6 commit f53314e

File tree

1 file changed

+79
-9
lines changed

1 file changed

+79
-9
lines changed

dudect/fixture.c

+79-9
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@
4343
#define ENOUGH_MEASURE 10000
4444
#define TEST_TRIES 10
4545

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];
4751

4852
/* threshold values for Welch's t-test */
4953
enum {
@@ -56,6 +60,37 @@ static void __attribute__((noreturn)) die(void)
5660
exit(111);
5761
}
5862

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+
5994
static void differentiate(int64_t *exec_times,
6095
const int64_t *before_ticks,
6196
const int64_t *after_ticks)
@@ -64,7 +99,9 @@ static void differentiate(int64_t *exec_times,
6499
exec_times[i] = after_ticks[i] - before_ticks[i];
65100
}
66101

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)
68105
{
69106
for (size_t i = 0; i < N_MEASURES; i++) {
70107
int64_t difference = exec_times[i];
@@ -73,15 +110,36 @@ static void update_statistics(const int64_t *exec_times, uint8_t *classes)
73110
continue;
74111

75112
/* 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+
}
77122
}
78123
}
79124

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+
80139
static bool report(void)
81140
{
82-
double max_t = fabs(t_compute(t));
141+
t_context_t *t = max_test();
83142
double number_traces_max_t = t->n[0] + t->n[1];
84-
double max_tau = max_t / sqrt(number_traces_max_t);
85143

86144
printf("\033[A\033[2K");
87145
printf("measure: %7.2lf M, ", (number_traces_max_t / 1e6));
@@ -91,6 +149,9 @@ static bool report(void)
91149
return false;
92150
}
93151

152+
double max_t = fabs(t_compute(t));
153+
double max_tau = max_t / sqrt(number_traces_max_t);
154+
94155
/* max_t: the t statistic value
95156
* max_tau: a t value normalized by sqrt(number of measurements).
96157
* this way we can compare max_tau taken with different
@@ -123,6 +184,7 @@ static bool doit(int mode)
123184
int64_t *exec_times = calloc(N_MEASURES, sizeof(int64_t));
124185
uint8_t *classes = calloc(N_MEASURES, sizeof(uint8_t));
125186
uint8_t *input_data = calloc(N_MEASURES * CHUNK_SIZE, sizeof(uint8_t));
187+
int64_t *percentiles = calloc(NUM_PERCENTILES, sizeof(int64_t));
126188

127189
if (!before_ticks || !after_ticks || !exec_times || !classes ||
128190
!input_data) {
@@ -133,28 +195,32 @@ static bool doit(int mode)
133195

134196
bool ret = measure(before_ticks, after_ticks, input_data, mode);
135197
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);
137200
ret &= report();
138201

139202
free(before_ticks);
140203
free(after_ticks);
141204
free(exec_times);
142205
free(classes);
143206
free(input_data);
207+
free(percentiles);
144208

145209
return ret;
146210
}
147211

148212
static void init_once(void)
149213
{
150214
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+
}
152219
}
153220

154221
static bool test_const(char *text, int mode)
155222
{
156223
bool result = false;
157-
t = malloc(sizeof(t_context_t));
158224

159225
for (int cnt = 0; cnt < TEST_TRIES; ++cnt) {
160226
printf("Testing %s...(%d/%d)\n\n", text, cnt, TEST_TRIES);
@@ -166,7 +232,11 @@ static bool test_const(char *text, int mode)
166232
if (result)
167233
break;
168234
}
169-
free(t);
235+
236+
for (size_t i = 0; i < DUDECT_TESTS; i++) {
237+
free(ctxs[i]);
238+
}
239+
170240
return result;
171241
}
172242

0 commit comments

Comments
 (0)