/* * 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(*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* v = static_cast*>(*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(*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(*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(*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(*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(*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