| // 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 |