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