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 */
4953enum {
@@ -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+
5994static 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+
80139static 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
148212static 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
154221static 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