blob: ef16280ba0fc3f21c1dc3e8d1201a4777cfe172f [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "annotation_util.h"
#include <cstdlib>
#define LOG_TAG "TuningFork"
#include "Log.h"
namespace annotation_util {
typedef uint64_t AnnotationId;
// This is a protobuf 1-based index
int GetKeyIndex(uint8_t b) {
int type = b & 0x7;
if (type != 0) return kKeyError;
return b >> 3;
}
uint64_t GetBase128IntegerFromByteStream(const std::vector<uint8_t> &bytes, int &index) {
uint64_t m = 0;
uint64_t r = 0;
while (index < bytes.size() && m <= (64 - 7)) {
auto b = bytes[index];
r |= (((uint64_t) b) & 0x7f) << m;
if ((b & 0x80) != 0) m += 7;
else return r;
++index;
}
return kStreamError;
}
void WriteBase128IntToStream(uint64_t x, std::vector<uint8_t> &bytes) {
do {
uint8_t a = x & 0x7f;
int b = x & 0xffffffffffffff80;
if (b) {
bytes.push_back(a | 0x80);
x >>= 7;
} else {
bytes.push_back(a);
return;
}
} while(x);
}
AnnotationId DecodeAnnotationSerialization(const SerializedAnnotation &ser,
const std::vector<uint32_t>& radix_mult,
int loading_annotation_index,
bool* loading) {
AnnotationId result = 0;
if (loading != nullptr) {
*loading = false; // False if annotation not present
}
for (int i = 0; i < ser.size(); ++i) {
int key = GetKeyIndex(ser[i]);
if (key == kKeyError)
return kAnnotationError;
// Convert to 0-based index
--key;
if (key >= radix_mult.size())
return kAnnotationError;
++i;
if (i >= ser.size())
return kAnnotationError;
uint64_t value = GetBase128IntegerFromByteStream(ser, i);
if (value == kStreamError)
return kAnnotationError;
// Check the range of the value
if (value == 0 || value >= radix_mult[key])
return kAnnotationError;
// We don't allow enums with more that 255 values
if (value > 0xff)
return kAnnotationError;
if (loading != nullptr && loading_annotation_index == key) {
*loading = value > 1;
}
if (key > 0)
result += radix_mult[key - 1] * value;
else
result += value;
}
return result;
}
ErrorCode SerializeAnnotationId(uint64_t id, SerializedAnnotation& ser,
const std::vector<uint32_t>& radix_mult) {
uint64_t x = id;
size_t n = radix_mult.size();
std::vector<uint32_t> v(n);
for (int i = n-1; i>0; --i) {
auto r = ::lldiv(x, (uint64_t)radix_mult[i-1]);
v[i] = r.quot;
x = r.rem;
}
v[0] = x;
for (int i = 0; i < n; ++i) {
auto value = v[i];
if (value > 0) {
int key = (i + 1) << 3;
ser.push_back(key);
WriteBase128IntToStream(value, ser);
}
}
return NO_ERROR;
}
ErrorCode Value(uint64_t id, uint32_t index, const std::vector<uint32_t>& radix_mult, int& value) {
uint64_t x = id;
int ix = index;
for (int i = 0; i < radix_mult.size(); ++i) {
auto r = ::lldiv(x, (uint64_t)radix_mult[i]);
if (ix==0) {
value = r.rem;
return NO_ERROR;
}
--ix;
x = r.quot;
}
return BAD_INDEX;
}
void SetUpAnnotationRadixes( std::vector<uint32_t>& radix_mult,
const std::vector<uint32_t>& enum_sizes) {
ALOGV("Settings::annotation_enum_size");
for(int i=0; i< enum_sizes.size();++i) {
ALOGV("%d", enum_sizes[i]);
}
auto n = enum_sizes.size();
if (n == 0) {
// With no annotations, we just have 1 possible prong per key
radix_mult.resize(1);
radix_mult[0] = 1;
} else {
radix_mult.resize(n);
int r = 1;
for (int i = 0; i < n; ++i) {
r *= enum_sizes[i] + 1;
radix_mult[i] = r;
}
}
}
} // namespace annotation_util