C++程序  |  171行  |  7.05 KB

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