blob: 717b02e162b7f806112d2f3c24eeb6bbc79ef317 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "apps/benchmark/measurements.h"
#include <algorithm>
namespace benchmark {
namespace {
static bool Match(const Event& event, const EventSpec& spec) {
return event.name == spec.name && event.categories == spec.categories;
}
} // namespace
EventSpec::EventSpec() {}
EventSpec::EventSpec(std::string name, std::string categories)
: name(name), categories(categories) {}
EventSpec::~EventSpec() {}
Measurement::Measurement() {}
Measurement::Measurement(MeasurementType type, EventSpec target_event)
: type(type), target_event(target_event) {}
Measurement::Measurement(MeasurementType type,
EventSpec target_event,
EventSpec second_event)
: type(type), target_event(target_event), second_event(second_event) {}
Measurement::~Measurement() {}
Measurements::Measurements(std::vector<Event> events,
base::TimeTicks time_origin)
: events_(events), time_origin_(time_origin) {}
Measurements::~Measurements() {}
double Measurements::Measure(const Measurement& measurement) const {
switch (measurement.type) {
case MeasurementType::TIME_UNTIL:
return TimeUntil(measurement.target_event);
case MeasurementType::TIME_BETWEEN:
return TimeBetween(measurement.target_event, measurement.second_event);
case MeasurementType::AVG_DURATION:
return AvgDuration(measurement.target_event);
case MeasurementType::PERCENTILE_DURATION:
return Percentile(measurement.target_event, measurement.param);
default:
NOTREACHED();
return double();
}
}
bool Measurements::EarliestOccurence(const EventSpec& event_spec,
base::TimeTicks* earliest) const {
base::TimeTicks result;
bool found = false;
for (const Event& event : events_) {
if (!Match(event, event_spec))
continue;
if (found) {
result = std::min(result, event.timestamp);
} else {
result = event.timestamp;
found = true;
}
}
if (!found)
return false;
*earliest = result;
return true;
}
double Measurements::TimeUntil(const EventSpec& event_spec) const {
base::TimeTicks earliest;
if (!EarliestOccurence(event_spec, &earliest))
return -1.0;
return (earliest - time_origin_).InMillisecondsF();
}
double Measurements::TimeBetween(const EventSpec& first_event_spec,
const EventSpec& second_event_spec) const {
base::TimeTicks earliest_first_event;
if (!EarliestOccurence(first_event_spec, &earliest_first_event))
return -1.0;
base::TimeTicks earliest_second_event;
if (!EarliestOccurence(second_event_spec, &earliest_second_event))
return -1.0;
if (earliest_second_event < earliest_first_event)
return -1.0;
return (earliest_second_event - earliest_first_event).InMillisecondsF();
}
double Measurements::AvgDuration(const EventSpec& event_spec) const {
double sum = 0.0;
int count = 0;
for (const Event& event : events_) {
if (event.type != EventType::COMPLETE)
continue;
if (!Match(event, event_spec))
continue;
sum += event.duration.InMillisecondsF();
count += 1;
}
if (!count)
return -1.0;
return sum / count;
}
double Measurements::Percentile(const EventSpec& event_spec,
double percentile) const {
DCHECK_GE(percentile, 0.0);
DCHECK_LE(percentile, 1.0);
std::vector<double> durations;
for (const Event& event : events_) {
if (event.type != EventType::COMPLETE)
continue;
if (!Match(event, event_spec))
continue;
durations.push_back(event.duration.InMillisecondsF());
}
if (durations.size() == 0) {
return -1.0;
}
// Nearest-rank method from:
// https://en.wikipedia.org/wiki/Percentile
double size = static_cast<double>(durations.size());
size_t rank = static_cast<size_t>(ceil(size * percentile));
size_t index = std::max(size_t{1}, rank) - 1;
std::nth_element(durations.begin(), durations.begin() + index,
durations.end());
return durations[index];
}
} // namespace benchmark