blob: a8be98b4089f306522c7b5f1d5fc1e29b9faabd1 [file] [log] [blame]
// Copyright 2020 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 "src/logger/event_vector_index.h"
#include "src/lib/statusor/status_macros.h"
#include "src/lib/statusor/statusor.h"
namespace cobalt::logger {
namespace {
// Returns a sorted list of the event codes which are explicitly enumerated in
// |metric_dim|.
std::vector<uint32_t> GetSortedEnumeratedEventCodes(
const MetricDefinition::MetricDimension &metric_dim) {
std::vector<uint32_t> event_codes;
for (const auto &[key, value] : metric_dim.event_codes()) {
event_codes.push_back(key);
}
std::sort(event_codes.begin(), event_codes.end());
return event_codes;
}
} // namespace
uint64_t GetNumEventCodes(const MetricDefinition::MetricDimension &metric_dim) {
if (metric_dim.max_event_code() != 0u) {
return metric_dim.max_event_code() + 1;
}
return metric_dim.event_codes_size();
}
uint64_t GetNumEventVectors(
const google::protobuf::RepeatedPtrField<MetricDefinition::MetricDimension>
&metric_dimensions) {
uint64_t num_event_vectors = 1;
for (const auto &metric_dim : metric_dimensions) {
num_event_vectors *= GetNumEventCodes(metric_dim);
}
return num_event_vectors;
}
lib::statusor::StatusOr<uint64_t> EventCodeToIndexForDimension(
uint32_t event_code, const MetricDefinition::MetricDimension &metric_dim) {
// If |metric_dim| has a max_event_code, just cast |event_code| to a uint64.
if (metric_dim.max_event_code() != 0u) {
if (event_code > metric_dim.max_event_code()) {
return util::Status(util::INVALID_ARGUMENT, "event_code is larger than max_event_code.");
}
return event_code;
}
// Otherwise, find the index of |event_code| in the sorted list of enumerated
// event codes.
std::vector<uint32_t> event_codes = GetSortedEnumeratedEventCodes(metric_dim);
for (uint64_t i = 0; i < event_codes.size(); ++i) {
if (event_codes[i] == event_code) {
return i;
}
}
return util::Status(util::INVALID_ARGUMENT, "event_code not found in MetricDimension.");
}
lib::statusor::StatusOr<uint32_t> EventCodeFromIndexForDimension(
uint64_t index, const MetricDefinition::MetricDimension &metric_dim) {
// If |metric_dim| has a max_event_code, just cast |index| to a uint32.
if (metric_dim.max_event_code() != 0) {
if (index > metric_dim.max_event_code()) {
return util::Status(util::INVALID_ARGUMENT, "event_code not found in MetricDimension.");
}
return static_cast<uint32_t>(index);
}
// Otherwise, |index| is an index into the sorted list of enumerated event
// codes.
if (index >= static_cast<uint64_t>(metric_dim.event_codes_size())) {
return util::Status(util::INVALID_ARGUMENT, "event_code not found in MetricDimension.");
}
std::vector<uint32_t> event_codes = GetSortedEnumeratedEventCodes(metric_dim);
return event_codes[index];
}
lib::statusor::StatusOr<uint64_t> EventVectorToIndex(std::vector<uint32_t> event_vector,
const MetricDefinition &metric_def) {
if (int(event_vector.size()) != metric_def.metric_dimensions_size()) {
return util::Status(util::INVALID_ARGUMENT,
"event_vector size differs from number of metric dimensions");
}
uint64_t multiplier = 1;
uint64_t result = 0;
for (size_t i = 0; i < event_vector.size(); ++i) {
CB_ASSIGN_OR_RETURN(uint32_t index, EventCodeToIndexForDimension(
event_vector[i], metric_def.metric_dimensions(i)));
result += index * multiplier;
multiplier *= GetNumEventCodes(metric_def.metric_dimensions(i));
}
return result;
}
lib::statusor::StatusOr<std::vector<uint32_t>> EventVectorFromIndex(
uint64_t index, const google::protobuf::RepeatedPtrField<MetricDefinition::MetricDimension>
&metric_dimensions) {
std::vector<uint32_t> result;
uint64_t divisor = 1;
for (const auto &dim : metric_dimensions) {
divisor *= GetNumEventCodes(dim);
}
for (int64_t i = static_cast<int64_t>(metric_dimensions.size()) - 1; i >= 0; --i) {
divisor /= GetNumEventCodes(metric_dimensions[i]);
CB_ASSIGN_OR_RETURN(uint32_t decoded_event_code,
EventCodeFromIndexForDimension(index / divisor, metric_dimensions[i]));
result.insert(result.begin(), decoded_event_code);
index = index % divisor;
}
if (index > 0) {
return util::Status(util::INVALID_ARGUMENT,
"index is too large to correspond to an event vector");
}
return result;
}
} // namespace cobalt::logger