1 /*
2 * Copyright 2018 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 "clearcutserializer.h"
18
19 #include "tuningfork/protobuf_nano_util.h"
20 #include "nano/tuningfork_clearcut_log.pb.h"
21
22 namespace tuningfork {
23
writeCountArray(pb_ostream_t * stream,const pb_field_t * field,void * const * arg)24 bool ClearcutSerializer::writeCountArray(pb_ostream_t *stream, const pb_field_t *field,
25 void *const *arg) {
26 const Histogram* h = static_cast<Histogram*>(*arg);
27 if(!pb_encode_tag(stream, PB_WT_STRING, logs_proto_tuningfork_TuningForkHistogram_counts_tag))
28 return false;
29 // Get the length of the data
30 pb_ostream_t sizing_stream = PB_OSTREAM_SIZING;
31 for (int i = 0; i < h->num_buckets_; ++i)
32 pb_encode_varint(&sizing_stream, h->buckets_[i]);
33 // Encode the length of the packed array in bytes
34 if (!pb_encode_varint(stream, sizing_stream.bytes_written))
35 return false;
36 // Encode each item, without the type, since it's packed
37 for (int i = 0; i < h->num_buckets_; ++i) {
38 if(!pb_encode_varint(stream, h->buckets_[i]))
39 return false;
40 }
41 return true;
42 }
writeCpuFreqs(pb_ostream_t * stream,const pb_field_t * field,void * const * arg)43 bool ClearcutSerializer::writeCpuFreqs(pb_ostream_t *stream, const pb_field_t *field,
44 void *const *arg) {
45 std::vector<uint64_t>* v = static_cast<std::vector<uint64_t>*>(*arg);
46 // Encode each item
47 for (int i = 0; i < v->size(); ++i) {
48 pb_encode_tag_for_field(stream, field);
49 pb_encode_varint(stream, (*v)[i]);
50 }
51 return true;
52 }
53
Fill(const Histogram & h,ClearcutHistogram & ch)54 void ClearcutSerializer::Fill(const Histogram& h, ClearcutHistogram& ch) {
55 ch.counts.funcs.encode = writeCountArray;
56 ch.counts.arg = (void*)(&h);
57 }
58
writeAnnotation(pb_ostream_t * stream,const pb_field_t * field,void * const * arg)59 bool ClearcutSerializer::writeAnnotation(pb_ostream_t* stream, const pb_field_t *field,
60 void *const *arg) {
61 const Prong* p = static_cast<const Prong*>(*arg);
62 if(p->annotation_.size()>0) {
63 pb_encode_tag_for_field(stream, field);
64 pb_encode_string(stream, &p->annotation_[0], p->annotation_.size());
65 }
66 return true;
67 }
Fill(const Prong & p,ClearcutHistogram & h)68 void ClearcutSerializer::Fill(const Prong& p, ClearcutHistogram& h) {
69 h.has_instrument_id = true;
70 h.instrument_id = p.instrumentation_key_;
71 h.annotation.funcs.encode = writeAnnotation;
72 h.annotation.arg = (void*)(&p);
73 Fill(p.histogram_, h);
74 }
Fill(const ExtraUploadInfo & tdi,DeviceInfo & di)75 void ClearcutSerializer::Fill(const ExtraUploadInfo& tdi, DeviceInfo& di) {
76 di.has_total_memory_bytes = true;
77 di.total_memory_bytes = tdi.total_memory_bytes;
78 di.has_gl_es_version = true;
79 di.gl_es_version = tdi.gl_es_version;
80 di.build_fingerprint.funcs.encode = writeString;
81 di.build_fingerprint.arg = (void*)&tdi.build_fingerprint;
82 di.build_version_sdk.funcs.encode = writeString;
83 di.build_version_sdk.arg = (void*)&tdi.build_version_sdk;
84 di.cpu_max_freq_hz.funcs.encode = writeCpuFreqs;
85 di.cpu_max_freq_hz.arg = (void*)&tdi.cpu_max_freq_hz;
86 }
writeHistograms(pb_ostream_t * stream,const pb_field_t * field,void * const * arg)87 bool ClearcutSerializer::writeHistograms(pb_ostream_t* stream, const pb_field_t *field,
88 void *const *arg) {
89 const ProngCache* pc =static_cast<const ProngCache*>(*arg);
90 for (auto &p: pc->prongs_) {
91 if (p->histogram_.Count() > 0) {
92 ClearcutHistogram h;
93 Fill(*p, h);
94 pb_encode_tag_for_field(stream, field);
95 // Get size, then fill object
96 pb_ostream_t sizing_stream = PB_OSTREAM_SIZING;
97 pb_encode(&sizing_stream, logs_proto_tuningfork_TuningForkHistogram_fields, &h);
98 pb_encode_varint(stream, sizing_stream.bytes_written);
99 pb_encode(stream, logs_proto_tuningfork_TuningForkHistogram_fields, &h);
100 }
101 }
102 return true;
103 }
writeDeviceInfo(pb_ostream_t * stream,const pb_field_t * field,void * const * arg)104 bool ClearcutSerializer::writeDeviceInfo(pb_ostream_t* stream, const pb_field_t *field,
105 void *const *arg) {
106 const ExtraUploadInfo* tdi =static_cast<const ExtraUploadInfo*>(*arg);
107 DeviceInfo di;
108 Fill(*tdi, di);
109 pb_encode_tag_for_field(stream, field);
110 // Get size, then fill object
111 pb_ostream_t sizing_stream = PB_OSTREAM_SIZING;
112 pb_encode(&sizing_stream, logs_proto_tuningfork_DeviceInfo_fields, &di);
113 pb_encode_varint(stream, sizing_stream.bytes_written);
114 pb_encode(stream, logs_proto_tuningfork_DeviceInfo_fields, &di);
115 return true;
116 }
117
writeString(pb_ostream_t * stream,const pb_field_t * field,void * const * arg)118 bool ClearcutSerializer::writeString(pb_ostream_t* stream, const pb_field_t *field,
119 void *const *arg) {
120
121 const std::string* str = static_cast<std::string*>(*arg);
122 if(!pb_encode_tag_for_field(stream, field)) return false;
123 return pb_encode_string(stream, (uint8_t*) str->data(), str->size());
124 }
125
FillExtras(const ExtraUploadInfo & info,TuningForkLogEvent & evt)126 void ClearcutSerializer::FillExtras(const ExtraUploadInfo& info,
127 TuningForkLogEvent& evt) {
128 evt.experiment_id.funcs.encode = writeString;
129 evt.experiment_id.arg = (void*)&info.experiment_id;
130 evt.session_id.funcs.encode = writeString;
131 evt.session_id.arg = (void*)&info.session_id;
132 evt.apk_package_name.funcs.encode = writeString;
133 evt.apk_package_name.arg = (void*)&info.apk_package_name;
134 evt.has_apk_version_code = true;
135 evt.apk_version_code = info.apk_version_code;
136 evt.has_tuningfork_version = true;
137 evt.tuningfork_version = info.tuningfork_version;
138 }
139
FillHistograms(const ProngCache & pc,TuningForkLogEvent & evt)140 void ClearcutSerializer::FillHistograms(const ProngCache& pc, TuningForkLogEvent &evt) {
141 evt.histograms.funcs.encode = writeHistograms;
142 evt.histograms.arg = (void*)&pc;
143 }
144
writeFidelityParams(pb_ostream_t * stream,const pb_field_t * field,void * const * arg)145 bool ClearcutSerializer::writeFidelityParams(pb_ostream_t* stream, const pb_field_t *field,
146 void *const *arg) {
147 const ProtobufSerialization* fp = static_cast<const ProtobufSerialization*>(*arg);
148 if(fp->size()>0) {
149 pb_encode_tag_for_field(stream, field);
150 pb_encode_string(stream, &(*fp)[0], fp->size());
151 }
152 return true;
153 }
SerializeEvent(const ProngCache & pc,const ProtobufSerialization & fidelity_params,const ExtraUploadInfo & device_info,ProtobufSerialization & evt_ser)154 void ClearcutSerializer::SerializeEvent(const ProngCache& pc,
155 const ProtobufSerialization& fidelity_params,
156 const ExtraUploadInfo& device_info,
157 ProtobufSerialization& evt_ser) {
158 TuningForkLogEvent evt = logs_proto_tuningfork_TuningForkLogEvent_init_default;
159 evt.fidelityparams.funcs.encode = writeFidelityParams;
160 evt.fidelityparams.arg = (void*)&fidelity_params;
161 FillHistograms(pc,evt);
162 evt.has_device_info = true;
163 Fill(device_info, evt.device_info);
164 FillExtras(device_info, evt);
165 VectorStream str {&evt_ser, 0};
166 pb_ostream_t stream = {VectorStream::Write, &str, SIZE_MAX, 0};
167 pb_encode(&stream, logs_proto_tuningfork_TuningForkLogEvent_fields, &evt);
168 }
169
170 } // namespace tuningfork
171