blob: 08ff0bdb9b05b1d2e1302f1187cc8ee0f395b64e [file] [log] [blame]
// Copyright 2017 The Fuchsia 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 "garnet/lib/measure/results.h"
#include <sstream>
#include "src/lib/fxl/logging.h"
namespace tracing {
namespace measure {
namespace {
std::string GetLabel(const measure::DurationSpec& spec) {
std::ostringstream os;
os << spec.event.name.c_str() << " (" << spec.event.category.c_str() << ")";
return os.str();
}
std::string GetLabel(const measure::ArgumentValueSpec& spec) {
std::ostringstream os;
os << spec.event.name.c_str() << " (" << spec.event.category.c_str() << "), ";
os << spec.argument_name.c_str();
return os.str();
}
std::string GetLabel(const measure::TimeBetweenSpec& spec) {
std::ostringstream os;
os << spec.first_event.name.c_str() << " (" << spec.first_event.category.c_str() << ") to ";
os << spec.second_event.name.c_str() << " (" << spec.second_event.category.c_str() << ")";
return os.str();
}
std::string GetUnit(const measure::ArgumentValueSpec& spec) { return spec.argument_unit; }
std::string GetUnit(const measure::DurationSpec& spec) { return "ms"; }
std::string GetUnit(const measure::TimeBetweenSpec& spec) { return "ms"; }
template <typename Spec, typename T>
Result ComputeSingle(Spec spec, const std::vector<T>& recorded_values) {
Result result;
if (spec.common.output_test_name.empty()) {
result.label = GetLabel(spec);
} else {
result.label = spec.common.output_test_name;
}
result.unit = GetUnit(spec);
result.split_first = spec.common.split_first;
if ((spec.common.expected_sample_count > 0) &&
(spec.common.expected_sample_count != recorded_values.size())) {
FX_LOGS(ERROR) << "Number of recorded samples for an event " << result.label
<< " does not match the expected number (expected "
<< spec.common.expected_sample_count << ", got " << recorded_values.size()
<< ").";
return result;
}
std::copy(recorded_values.begin(), recorded_values.end(), std::back_inserter(result.values));
return result;
}
template <typename T>
const T& get_or_default(const std::unordered_map<uint64_t, T>& dictionary, uint64_t id,
const T& default_value) {
return dictionary.count(id) ? dictionary.at(id) : default_value;
}
std::vector<double> ticks_to_ms(const std::vector<uint64_t> ticks, uint64_t ticks_per_second) {
std::vector<double> milliseconds(ticks.size());
double ms_per_tick = 1'000.0 / ticks_per_second;
std::transform(ticks.begin(), ticks.end(), milliseconds.begin(),
[&ms_per_tick](uint64_t tick) { return tick * ms_per_tick; });
return milliseconds;
}
} // namespace
std::vector<Result> ComputeResults(
const Measurements& measurements,
const std::unordered_map<uint64_t, std::vector<uint64_t>>& recorded_values,
uint64_t ticks_per_second) {
std::vector<Result> results;
const std::vector<uint64_t> no_recorded_values;
std::string empty_string;
for (auto& measure_spec : measurements.duration) {
auto duration_values =
ticks_to_ms(get_or_default(recorded_values, measure_spec.common.id, no_recorded_values),
ticks_per_second);
results.push_back(ComputeSingle(measure_spec, duration_values));
}
for (auto& measure_spec : measurements.argument_value) {
auto argument_values =
get_or_default(recorded_values, measure_spec.common.id, no_recorded_values);
results.push_back(ComputeSingle(measure_spec, argument_values));
}
for (auto& measure_spec : measurements.time_between) {
auto time_between_values =
ticks_to_ms(get_or_default(recorded_values, measure_spec.common.id, no_recorded_values),
ticks_per_second);
results.push_back(ComputeSingle(measure_spec, time_between_values));
}
return results;
}
} // namespace measure
} // namespace tracing