@@ -12,6 +12,7 @@ use serde::Serialize;
12
12
13
13
use std:: collections:: HashMap ;
14
14
use std:: error:: Error ;
15
+ use std:: hash:: Hash ;
15
16
use std:: sync:: Arc ;
16
17
17
18
type BoxedError = Box < dyn Error + Send + Sync > ;
@@ -222,7 +223,7 @@ pub async fn compare(
222
223
}
223
224
224
225
/// Compare two bounds on a given stat
225
- pub async fn compare_given_commits (
226
+ async fn compare_given_commits (
226
227
start : Bound ,
227
228
end : Bound ,
228
229
stat : String ,
@@ -236,6 +237,21 @@ pub async fn compare_given_commits(
236
237
Some ( b) => b,
237
238
None => return Ok ( None ) ,
238
239
} ;
240
+ let mut prevs = Vec :: with_capacity ( 10 ) ;
241
+ let mut commit = a. clone ( ) ;
242
+ while prevs. len ( ) < 100 {
243
+ match prev_commit ( & commit, master_commits) {
244
+ Some ( c) => {
245
+ let new = ArtifactId :: Commit ( database:: Commit {
246
+ sha : c. sha . clone ( ) ,
247
+ date : database:: Date ( c. time ) ,
248
+ } ) ;
249
+ commit = new. clone ( ) ;
250
+ prevs. push ( new) ;
251
+ }
252
+ None => break ,
253
+ }
254
+ }
239
255
let aids = Arc :: new ( vec ! [ a. clone( ) , b. clone( ) ] ) ;
240
256
241
257
// get all crates, cache, and profile combinations for the given stat
@@ -247,10 +263,51 @@ pub async fn compare_given_commits(
247
263
248
264
// `responses` contains series iterators. The first element in the iterator is the data
249
265
// for `a` and the second is the data for `b`
250
- let mut responses = ctxt. query :: < Option < f64 > > ( query, aids) . await ?;
266
+ let mut responses = ctxt. query :: < Option < f64 > > ( query. clone ( ) , aids) . await ?;
267
+ let mut rps = ctxt
268
+ . query :: < Option < f64 > > ( query, Arc :: new ( prevs. clone ( ) ) )
269
+ . await ?;
251
270
252
271
let conn = ctxt. conn ( ) . await ;
253
272
273
+ let mut others = Vec :: new ( ) ;
274
+ for aid in prevs {
275
+ others. push ( ArtifactData :: consume_one ( & * conn, aid, & mut rps, master_commits) . await )
276
+ }
277
+ // println!("{:#?}", others.iter().map(|o| &o.data).collect::<Vec<_>>());
278
+ let mut h: HashMap < String , Vec < f64 > > = HashMap :: new ( ) ;
279
+ for o in others {
280
+ let data = & o. data ;
281
+ for ( k, v) in data {
282
+ for ( c, val) in v {
283
+ h. entry ( format ! ( "{}-{}" , k, c) ) . or_default ( ) . push ( * val) ;
284
+ }
285
+ }
286
+ }
287
+ for ( bench, results) in h {
288
+ println ! ( "Bechmark: {}" , bench) ;
289
+ let results_len = results. len ( ) ;
290
+ let results_mean = results. iter ( ) . sum :: < f64 > ( ) / results. len ( ) as f64 ;
291
+ let mut deltas = results
292
+ . windows ( 2 )
293
+ . map ( |window| ( window[ 0 ] - window[ 1 ] ) . abs ( ) )
294
+ . collect :: < Vec < _ > > ( ) ;
295
+ deltas. sort_by ( |d1, d2| d1. partial_cmp ( d2) . unwrap_or ( std:: cmp:: Ordering :: Equal ) ) ;
296
+ let non_significant = deltas
297
+ . iter ( )
298
+ . zip ( results)
299
+ . take_while ( |( & d, r) | d / r < 0.05 )
300
+ . collect :: < Vec < _ > > ( ) ;
301
+ println ! (
302
+ "Significant changes: {}" ,
303
+ results_len - non_significant. len( )
304
+ ) ;
305
+ let mean =
306
+ non_significant. iter ( ) . map ( |( & d, _) | d) . sum :: < f64 > ( ) / ( non_significant. len ( ) as f64 ) ;
307
+ let coefficient_of_variance = ( mean / results_mean) * 100.0 ;
308
+ println ! ( "\t Coefficient of variance: {:.3}%" , coefficient_of_variance) ;
309
+ }
310
+
254
311
Ok ( Some ( Comparison {
255
312
a : ArtifactData :: consume_one ( & * conn, a. clone ( ) , & mut responses, master_commits) . await ,
256
313
b : ArtifactData :: consume_one ( & * conn, b. clone ( ) , & mut responses, master_commits) . await ,
@@ -376,13 +433,7 @@ pub struct Comparison {
376
433
impl Comparison {
377
434
/// Gets the previous commit before `a`
378
435
pub fn prev ( & self , master_commits : & [ collector:: MasterCommit ] ) -> Option < String > {
379
- match & self . a . artifact {
380
- ArtifactId :: Commit ( a) => master_commits
381
- . iter ( )
382
- . find ( |c| c. sha == a. sha )
383
- . map ( |c| c. parent_sha . clone ( ) ) ,
384
- ArtifactId :: Artifact ( _) => None ,
385
- }
436
+ prev_commit ( & self . a . artifact , master_commits) . map ( |c| c. parent_sha . clone ( ) )
386
437
}
387
438
388
439
/// Determines if `a` and `b` are contiguous
@@ -405,13 +456,7 @@ impl Comparison {
405
456
406
457
/// Gets the sha of the next commit after `b`
407
458
pub fn next ( & self , master_commits : & [ collector:: MasterCommit ] ) -> Option < String > {
408
- match & self . b . artifact {
409
- ArtifactId :: Commit ( b) => master_commits
410
- . iter ( )
411
- . find ( |c| c. parent_sha == b. sha )
412
- . map ( |c| c. sha . clone ( ) ) ,
413
- ArtifactId :: Artifact ( _) => None ,
414
- }
459
+ next_commit ( & self . a . artifact , master_commits) . map ( |c| c. parent_sha . clone ( ) )
415
460
}
416
461
417
462
fn get_benchmarks < ' a > ( & ' a self ) -> Vec < BenchmarkComparison < ' a > > {
@@ -437,6 +482,31 @@ impl Comparison {
437
482
}
438
483
}
439
484
485
+ /// Gets the previous commit
486
+ pub fn prev_commit < ' a > (
487
+ artifact : & ArtifactId ,
488
+ master_commits : & ' a [ collector:: MasterCommit ] ,
489
+ ) -> Option < & ' a collector:: MasterCommit > {
490
+ match & artifact {
491
+ ArtifactId :: Commit ( a) => {
492
+ let current = master_commits. iter ( ) . find ( |c| c. sha == a. sha ) ?;
493
+ master_commits. iter ( ) . find ( |c| c. sha == current. parent_sha )
494
+ }
495
+ ArtifactId :: Artifact ( _) => None ,
496
+ }
497
+ }
498
+
499
+ /// Gets the next commit
500
+ pub fn next_commit < ' a > (
501
+ artifact : & ArtifactId ,
502
+ master_commits : & ' a [ collector:: MasterCommit ] ,
503
+ ) -> Option < & ' a collector:: MasterCommit > {
504
+ match artifact {
505
+ ArtifactId :: Commit ( b) => master_commits. iter ( ) . find ( |c| c. parent_sha == b. sha ) ,
506
+ ArtifactId :: Artifact ( _) => None ,
507
+ }
508
+ }
509
+
440
510
// A single comparison based on benchmark and cache state
441
511
#[ derive( Debug ) ]
442
512
pub struct BenchmarkComparison < ' a > {
0 commit comments