perf-chart.scm 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. (use-modules (charting) (charting csv) (ice-9 match) (ice-9 pretty-print))
  2. (define (keyed-sorter key less?)
  3. (lambda (a b) (less? (key a) (key b))))
  4. (define (group-by ls less? truncate zero add)
  5. (let lp ((ls (sort ls (keyed-sorter truncate less?)))
  6. (cur #f)
  7. (sum (zero)))
  8. (define (finish tail)
  9. (if cur
  10. (acons cur sum tail)
  11. tail))
  12. (match ls
  13. (() (finish '()))
  14. ((x . ls)
  15. (let ((x_ (truncate x)))
  16. (if (equal? x_ cur)
  17. (lp ls cur (add x sum))
  18. (finish (lp ls x_ (add x (zero))))))))))
  19. (define (median ls)
  20. (let* ((ordered (list->vector (sort ls <)))
  21. (len (vector-length ordered)))
  22. (if (even? len)
  23. (/ (+ (vector-ref ordered (/ len 2))
  24. (vector-ref ordered (1- (/ len 2))))
  25. 2)
  26. (vector-ref ordered (/ (1- len) 2)))))
  27. (define (sort-by-first-non-baseline tests)
  28. (let ((medians
  29. (match tests
  30. ((baseline
  31. (non-baseline (test . times) ...)
  32. . _)
  33. (map cons test (map median times))))))
  34. (define (extract-median test)
  35. (match test
  36. ((name . times)
  37. (or (assoc-ref medians name) 0.0))))
  38. (match tests
  39. (((baseline . tests) . rest)
  40. (cons (cons baseline (sort tests (keyed-sorter extract-median <)))
  41. rest)))))
  42. (match (program-arguments)
  43. ((_ title output input)
  44. (let* ((rows (call-with-input-file input csv-port->row-list))
  45. (by-version
  46. (group-by rows
  47. string<?
  48. (match-lambda
  49. (#(version test time) version))
  50. (lambda () '())
  51. (lambda (row data)
  52. (match row
  53. (#(version test time)
  54. (acons test (string->number time) data))))))
  55. (by-version-and-test
  56. (map (lambda (test)
  57. (match test
  58. ((version . data)
  59. (cons version
  60. (group-by data
  61. string<?
  62. (match-lambda
  63. ((test . time) test))
  64. (lambda () '())
  65. (lambda (data times)
  66. (match data
  67. ((test . time)
  68. (cons time times)))))))))
  69. by-version))
  70. (normalized
  71. (let ((norms (match by-version-and-test
  72. (((version . tests) . _)
  73. (map (match-lambda
  74. ((test . times)
  75. (cons test (median times))))
  76. tests)))))
  77. (map (lambda (test)
  78. (match test
  79. ((version . data)
  80. (cons version
  81. (map (match-lambda
  82. ((test . times)
  83. (let ((norm (or (assoc-ref norms test) 1.0)))
  84. (cons test
  85. (map (lambda (time) (/ time norm))
  86. times)))))
  87. data)))))
  88. by-version-and-test)))
  89. (sorted (sort-by-first-non-baseline normalized)))
  90. (make-performance-chart
  91. title
  92. sorted
  93. #:log-y-base 2
  94. #:y-axis-label
  95. (match sorted
  96. (((version . _) . _)
  97. (format #f "run time normalized to ~a; shorter is better" version)))
  98. #:baseline 1.0
  99. #:box-width 5
  100. #:box-spacing 0
  101. #:test-spacing 10
  102. #:vertical-xtick-labels? #t
  103. #:vertical-box-labels? #t
  104. #:box-label-height 8.5
  105. #:box-value-formatter
  106. (lambda (value)
  107. (let ((str (format #f "~,3f" value)))
  108. (if (equal? str "1.000")
  109. ""
  110. str)))
  111. #:write-to-png output))))