speed_stats.cc (3105B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #include "tools/speed_stats.h" 7 8 #include <algorithm> 9 #include <cmath> 10 #include <cstddef> 11 #include <cstdio> 12 #include <string> 13 14 namespace jpegxl { 15 namespace tools { 16 17 void SpeedStats::NotifyElapsed(double elapsed_seconds) { 18 if (elapsed_seconds > 0.0) { 19 elapsed_.push_back(elapsed_seconds); 20 } 21 } 22 23 bool SpeedStats::GetSummary(SpeedStats::Summary* s) { 24 if (elapsed_.empty()) return false; 25 26 s->min = *std::min_element(elapsed_.begin(), elapsed_.end()); 27 s->max = *std::max_element(elapsed_.begin(), elapsed_.end()); 28 29 // Single rep 30 if (elapsed_.size() == 1) { 31 s->central_tendency = elapsed_[0]; 32 s->variability = 0.0; 33 s->type = ""; 34 return true; 35 } 36 37 // Two: skip first (noisier) 38 if (elapsed_.size() == 2) { 39 s->central_tendency = elapsed_[1]; 40 s->variability = 0.0; 41 s->type = " second:"; 42 return true; 43 } 44 45 // Prefer geomean unless numerically unreliable (too many reps) 46 if (pow(elapsed_[0], elapsed_.size()) < 1E100) { 47 double product = 1.0; 48 for (size_t i = 1; i < elapsed_.size(); ++i) { 49 product *= elapsed_[i]; 50 } 51 52 s->central_tendency = pow(product, 1.0 / (elapsed_.size() - 1)); 53 s->variability = 0.0; 54 s->type = " geomean:"; 55 if (std::isnormal(s->central_tendency)) return true; 56 } 57 58 // Else: median 59 std::sort(elapsed_.begin(), elapsed_.end()); 60 s->central_tendency = elapsed_[elapsed_.size() / 2]; 61 double stdev = 0; 62 for (size_t i = 0; i < elapsed_.size(); i++) { 63 double diff = elapsed_[i] - s->central_tendency; 64 stdev += diff * diff; 65 } 66 s->variability = sqrt(stdev); 67 s->type = " median:"; 68 return true; 69 } 70 71 namespace { 72 73 std::string SummaryStat(double value, const char* unit, 74 const SpeedStats::Summary& s) { 75 if (value == 0.) return ""; 76 77 char stat_str[100] = {'\0'}; 78 const double value_tendency = value / s.central_tendency; 79 // Note flipped order: higher elapsed = lower mpps. 80 const double value_min = value / s.max; 81 const double value_max = value / s.min; 82 83 char variability[20] = {'\0'}; 84 if (s.variability != 0.0) { 85 const double stdev = value / s.variability; 86 snprintf(variability, sizeof(variability), " (stdev %.3f)", stdev); 87 } 88 89 snprintf(stat_str, sizeof(stat_str), "%s %.3f %s/s [%.2f, %.2f]%s", s.type, 90 value_tendency, unit, value_min, value_max, variability); 91 return stat_str; 92 } 93 94 } // namespace 95 96 bool SpeedStats::Print(size_t worker_threads) { 97 Summary s; 98 if (!GetSummary(&s)) { 99 return false; 100 } 101 std::string mps_stats = SummaryStat(xsize_ * ysize_ * 1e-6, "MP", s); 102 std::string mbs_stats = SummaryStat(file_size_ * 1e-6, "MB", s); 103 104 fprintf(stderr, "%d x %d, %s, %s, %d reps, %d threads.\n", 105 static_cast<int>(xsize_), static_cast<int>(ysize_), mps_stats.c_str(), 106 mbs_stats.c_str(), static_cast<int>(elapsed_.size()), 107 static_cast<int>(worker_threads)); 108 return true; 109 } 110 111 } // namespace tools 112 } // namespace jpegxl