| 52 | const TimingMeasurement TIMESTAMP_PRECISION = 1000000; |
| 53 | |
| 54 | struct PerformanceData { |
| 55 | /** Duration value indicating the value is not valid should be considered a gap in measurements */ |
| 56 | static const TimingMeasurement INVALID_DURATION = UINT64_MAX; |
| 57 | |
| 58 | /** Time spent processing each cycle of the performance element, circular buffer */ |
| 59 | std::array<TimingMeasurement, NUM_FRAMERATE_POINTS> durations{}; |
| 60 | /** Start time of each cycle of the performance element, circular buffer */ |
| 61 | std::array<TimingMeasurement, NUM_FRAMERATE_POINTS> timestamps{}; |
| 62 | /** Expected number of cycles per second when the system is running without slowdowns */ |
| 63 | double expected_rate = 0; |
| 64 | /** Next index to write to in \c durations and \c timestamps */ |
| 65 | int next_index = 0; |
| 66 | /** Last index written to in \c durations and \c timestamps */ |
| 67 | int prev_index = 0; |
| 68 | /** Number of data points recorded, clamped to \c NUM_FRAMERATE_POINTS */ |
| 69 | int num_valid = 0; |
| 70 | |
| 71 | /** Current accumulated duration */ |
| 72 | TimingMeasurement acc_duration{}; |
| 73 | /** Start time for current accumulation cycle */ |
| 74 | TimingMeasurement acc_timestamp{}; |
| 75 | |
| 76 | /** |
| 77 | * Initialize a data element with an expected collection rate |
| 78 | * @param expected_rate |
| 79 | * Expected number of cycles per second of the performance element. Use 1 if unknown or not relevant. |
| 80 | * The rate is used for highlighting slow-running elements in the GUI. |
| 81 | */ |
| 82 | explicit PerformanceData(double expected_rate) : expected_rate(expected_rate) { } |
| 83 | |
| 84 | /** Collect a complete measurement, given start and ending times for a processing block */ |
| 85 | void Add(TimingMeasurement start_time, TimingMeasurement end_time) |
| 86 | { |
| 87 | this->durations[this->next_index] = end_time - start_time; |
| 88 | this->timestamps[this->next_index] = start_time; |
| 89 | this->prev_index = this->next_index; |
| 90 | this->next_index += 1; |
| 91 | if (this->next_index >= NUM_FRAMERATE_POINTS) this->next_index = 0; |
| 92 | this->num_valid = std::min(NUM_FRAMERATE_POINTS, this->num_valid + 1); |
| 93 | } |
| 94 | |
| 95 | /** Begin an accumulation of multiple measurements into a single value, from a given start time */ |
| 96 | void BeginAccumulate(TimingMeasurement start_time) |
| 97 | { |
| 98 | this->timestamps[this->next_index] = this->acc_timestamp; |
| 99 | this->durations[this->next_index] = this->acc_duration; |
| 100 | this->prev_index = this->next_index; |
| 101 | this->next_index += 1; |
| 102 | if (this->next_index >= NUM_FRAMERATE_POINTS) this->next_index = 0; |
| 103 | this->num_valid = std::min(NUM_FRAMERATE_POINTS, this->num_valid + 1); |
| 104 | |
| 105 | this->acc_duration = 0; |
| 106 | this->acc_timestamp = start_time; |
| 107 | } |
| 108 | |
| 109 | /** Accumulate a period onto the current measurement */ |
| 110 | void AddAccumulate(TimingMeasurement duration) |
| 111 | { |