/*
* Copyright 2018 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 "clearcutserializer.h"
#include "tuningfork/protobuf_nano_util.h"
#include "nano/tuningfork_clearcut_log.pb.h"
namespace tuningfork {
bool ClearcutSerializer::writeCountArray(pb_ostream_t *stream, const pb_field_t *field,
void *const *arg) {
const Histogram* h = static_cast<Histogram*>(*arg);
if(!pb_encode_tag(stream, PB_WT_STRING, logs_proto_tuningfork_TuningForkHistogram_counts_tag))
return false;
// Get the length of the data
pb_ostream_t sizing_stream = PB_OSTREAM_SIZING;
for (int i = 0; i < h->num_buckets_; ++i)
pb_encode_varint(&sizing_stream, h->buckets_[i]);
// Encode the length of the packed array in bytes
if (!pb_encode_varint(stream, sizing_stream.bytes_written))
return false;
// Encode each item, without the type, since it's packed
for (int i = 0; i < h->num_buckets_; ++i) {
if(!pb_encode_varint(stream, h->buckets_[i]))
return false;
}
return true;
}
bool ClearcutSerializer::writeCpuFreqs(pb_ostream_t *stream, const pb_field_t *field,
void *const *arg) {
std::vector<uint64_t>* v = static_cast<std::vector<uint64_t>*>(*arg);
// Encode each item
for (int i = 0; i < v->size(); ++i) {
pb_encode_tag_for_field(stream, field);
pb_encode_varint(stream, (*v)[i]);
}
return true;
}
void ClearcutSerializer::Fill(const Histogram& h, ClearcutHistogram& ch) {
ch.counts.funcs.encode = writeCountArray;
ch.counts.arg = (void*)(&h);
}
bool ClearcutSerializer::writeAnnotation(pb_ostream_t* stream, const pb_field_t *field,
void *const *arg) {
const Prong* p = static_cast<const Prong*>(*arg);
if(p->annotation_.size()>0) {
pb_encode_tag_for_field(stream, field);
pb_encode_string(stream, &p->annotation_[0], p->annotation_.size());
}
return true;
}
void ClearcutSerializer::Fill(const Prong& p, ClearcutHistogram& h) {
h.has_instrument_id = true;
h.instrument_id = p.instrumentation_key_;
h.annotation.funcs.encode = writeAnnotation;
h.annotation.arg = (void*)(&p);
Fill(p.histogram_, h);
}
void ClearcutSerializer::Fill(const ExtraUploadInfo& tdi, DeviceInfo& di) {
di.has_total_memory_bytes = true;
di.total_memory_bytes = tdi.total_memory_bytes;
di.has_gl_es_version = true;
di.gl_es_version = tdi.gl_es_version;
di.build_fingerprint.funcs.encode = writeString;
di.build_fingerprint.arg = (void*)&tdi.build_fingerprint;
di.build_version_sdk.funcs.encode = writeString;
di.build_version_sdk.arg = (void*)&tdi.build_version_sdk;
di.cpu_max_freq_hz.funcs.encode = writeCpuFreqs;
di.cpu_max_freq_hz.arg = (void*)&tdi.cpu_max_freq_hz;
}
bool ClearcutSerializer::writeHistograms(pb_ostream_t* stream, const pb_field_t *field,
void *const *arg) {
const ProngCache* pc =static_cast<const ProngCache*>(*arg);
for (auto &p: pc->prongs_) {
if (p->histogram_.Count() > 0) {
ClearcutHistogram h;
Fill(*p, h);
pb_encode_tag_for_field(stream, field);
// Get size, then fill object
pb_ostream_t sizing_stream = PB_OSTREAM_SIZING;
pb_encode(&sizing_stream, logs_proto_tuningfork_TuningForkHistogram_fields, &h);
pb_encode_varint(stream, sizing_stream.bytes_written);
pb_encode(stream, logs_proto_tuningfork_TuningForkHistogram_fields, &h);
}
}
return true;
}
bool ClearcutSerializer::writeDeviceInfo(pb_ostream_t* stream, const pb_field_t *field,
void *const *arg) {
const ExtraUploadInfo* tdi =static_cast<const ExtraUploadInfo*>(*arg);
DeviceInfo di;
Fill(*tdi, di);
pb_encode_tag_for_field(stream, field);
// Get size, then fill object
pb_ostream_t sizing_stream = PB_OSTREAM_SIZING;
pb_encode(&sizing_stream, logs_proto_tuningfork_DeviceInfo_fields, &di);
pb_encode_varint(stream, sizing_stream.bytes_written);
pb_encode(stream, logs_proto_tuningfork_DeviceInfo_fields, &di);
return true;
}
bool ClearcutSerializer::writeString(pb_ostream_t* stream, const pb_field_t *field,
void *const *arg) {
const std::string* str = static_cast<std::string*>(*arg);
if(!pb_encode_tag_for_field(stream, field)) return false;
return pb_encode_string(stream, (uint8_t*) str->data(), str->size());
}
void ClearcutSerializer::FillExtras(const ExtraUploadInfo& info,
TuningForkLogEvent& evt) {
evt.experiment_id.funcs.encode = writeString;
evt.experiment_id.arg = (void*)&info.experiment_id;
evt.session_id.funcs.encode = writeString;
evt.session_id.arg = (void*)&info.session_id;
evt.apk_package_name.funcs.encode = writeString;
evt.apk_package_name.arg = (void*)&info.apk_package_name;
evt.has_apk_version_code = true;
evt.apk_version_code = info.apk_version_code;
evt.has_tuningfork_version = true;
evt.tuningfork_version = info.tuningfork_version;
}
void ClearcutSerializer::FillHistograms(const ProngCache& pc, TuningForkLogEvent &evt) {
evt.histograms.funcs.encode = writeHistograms;
evt.histograms.arg = (void*)&pc;
}
bool ClearcutSerializer::writeFidelityParams(pb_ostream_t* stream, const pb_field_t *field,
void *const *arg) {
const ProtobufSerialization* fp = static_cast<const ProtobufSerialization*>(*arg);
if(fp->size()>0) {
pb_encode_tag_for_field(stream, field);
pb_encode_string(stream, &(*fp)[0], fp->size());
}
return true;
}
void ClearcutSerializer::SerializeEvent(const ProngCache& pc,
const ProtobufSerialization& fidelity_params,
const ExtraUploadInfo& device_info,
ProtobufSerialization& evt_ser) {
TuningForkLogEvent evt = logs_proto_tuningfork_TuningForkLogEvent_init_default;
evt.fidelityparams.funcs.encode = writeFidelityParams;
evt.fidelityparams.arg = (void*)&fidelity_params;
FillHistograms(pc,evt);
evt.has_device_info = true;
Fill(device_info, evt.device_info);
FillExtras(device_info, evt);
VectorStream str {&evt_ser, 0};
pb_ostream_t stream = {VectorStream::Write, &str, SIZE_MAX, 0};
pb_encode(&stream, logs_proto_tuningfork_TuningForkLogEvent_fields, &evt);
}
} // namespace tuningfork