Home | History | Annotate | Download | only in tuningfork
      1 /*
      2  * Copyright 2019 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "annotation_util.h"
     18 
     19 #include <cstdlib>
     20 
     21 #define LOG_TAG "TuningFork"
     22 #include "Log.h"
     23 
     24 namespace annotation_util {
     25 
     26 typedef uint64_t AnnotationId;
     27 
     28 // This is a protobuf 1-based index
     29 int GetKeyIndex(uint8_t b) {
     30     int type = b & 0x7;
     31     if (type != 0) return kKeyError;
     32     return b >> 3;
     33 }
     34 
     35 uint64_t GetBase128IntegerFromByteStream(const std::vector<uint8_t> &bytes, int &index) {
     36     uint64_t m = 0;
     37     uint64_t r = 0;
     38     while (index < bytes.size() && m <= (64 - 7)) {
     39         auto b = bytes[index];
     40         r |= (((uint64_t) b) & 0x7f) << m;
     41         if ((b & 0x80) != 0) m += 7;
     42         else return r;
     43         ++index;
     44     }
     45     return kStreamError;
     46 }
     47 
     48 void WriteBase128IntToStream(uint64_t x, std::vector<uint8_t> &bytes) {
     49     do {
     50         uint8_t a = x & 0x7f;
     51         int b = x & 0xffffffffffffff80;
     52         if (b) {
     53             bytes.push_back(a | 0x80);
     54             x >>= 7;
     55         } else {
     56             bytes.push_back(a);
     57             return;
     58         }
     59     } while(x);
     60 }
     61 
     62 AnnotationId DecodeAnnotationSerialization(const SerializedAnnotation &ser,
     63                                            const std::vector<int>& radix_mult) {
     64     AnnotationId result = 0;
     65     for (int i = 0; i < ser.size(); ++i) {
     66         int key = GetKeyIndex(ser[i]);
     67         if (key == kKeyError)
     68             return kAnnotationError;
     69         // Convert to 0-based index
     70         --key;
     71         if (key >= radix_mult.size())
     72             return kAnnotationError;
     73         ++i;
     74         if (i >= ser.size())
     75             return kAnnotationError;
     76         uint64_t value = GetBase128IntegerFromByteStream(ser, i);
     77         if (value == kStreamError)
     78             return kAnnotationError;
     79         // Check the range of the value
     80         if (value == 0 || value >= radix_mult[key])
     81             return kAnnotationError;
     82         // We don't allow enums with more that 255 values
     83         if (value > 0xff)
     84             return kAnnotationError;
     85         if (key > 0)
     86             result += radix_mult[key - 1] * value;
     87         else
     88             result += value;
     89     }
     90     return result;
     91 }
     92 
     93 int SerializeAnnotationId(uint64_t id, SerializedAnnotation& ser,
     94                           const std::vector<int>& radix_mult) {
     95   int err = 0;
     96   uint64_t x = id;
     97   for (int i = 0; i < radix_mult.size(); ++i) {
     98     auto r = ::div(x, radix_mult[i]);
     99     int value = r.rem;
    100     if (value > 0) {
    101       int key = (i + 1) << 3;
    102       ser.push_back(key);
    103       WriteBase128IntToStream(value, ser);
    104     }
    105     x = r.quot;
    106   }
    107   return err;
    108 }
    109 
    110 void SetUpAnnotationRadixes( std::vector<int>& radix_mult,
    111                              const std::vector<int>& enum_sizes) {
    112     ALOGV("Settings::annotation_enum_size");
    113     for(int i=0; i< enum_sizes.size();++i) {
    114       ALOGV("%d", enum_sizes[i]);
    115     }
    116     int n = enum_sizes.size();
    117     if (n == 0) {
    118         // With no annotations, we just have 1 possible prong per key
    119         radix_mult.resize(1);
    120         radix_mult[0] = 1;
    121     } else {
    122         radix_mult.resize(n);
    123         int r = 1;
    124         for (int i = 0; i < n; ++i) {
    125             r *= enum_sizes[i] + 1;
    126             radix_mult[i] = r;
    127         }
    128     }
    129 }
    130 
    131 } // namespace annotation_util
    132