• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // HistogramWriter:
7 //   Helper class for writing histogram-json-set-format files to JSON.
8 
9 #include "HistogramWriter.h"
10 
11 #include "common/debug.h"
12 
13 #include <rapidjson/document.h>
14 
15 #if !defined(ANGLE_HAS_HISTOGRAMS)
16 #    error "Must have histograms enabled"
17 #endif  // !defined(ANGLE_HAS_HISTOGRAMS)
18 
19 ANGLE_DISABLE_EXTRA_SEMI_WARNING
20 ANGLE_DISABLE_EXTRA_SEMI_STMT_WARNING
21 ANGLE_DISABLE_DESTRUCTOR_OVERRIDE_WARNING
22 ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS
23 #include "tracing/tracing/value/diagnostics/reserved_infos.h"
24 #include "tracing/tracing/value/histogram.h"
25 ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS
26 ANGLE_REENABLE_DESTRUCTOR_OVERRIDE_WARNING
27 ANGLE_REENABLE_EXTRA_SEMI_STMT_WARNING
28 ANGLE_REENABLE_EXTRA_SEMI_WARNING
29 
30 namespace js    = rapidjson;
31 namespace proto = catapult::tracing::tracing::proto;
32 
33 namespace angle
34 {
35 namespace
36 {
GetUnitAndDirection(proto::UnitAndDirection unit)37 std::string GetUnitAndDirection(proto::UnitAndDirection unit)
38 {
39     ASSERT(unit.improvement_direction() == proto::SMALLER_IS_BETTER);
40     ASSERT(unit.unit() == proto::MS_BEST_FIT_FORMAT);
41     return "msBestFitFormat_smallerIsBetter";
42 }
43 }  // namespace
44 
45 HistogramWriter::HistogramWriter() = default;
46 
47 HistogramWriter::~HistogramWriter() = default;
48 
addSample(const std::string & measurement,const std::string & story,double value,const std::string & units)49 void HistogramWriter::addSample(const std::string &measurement,
50                                 const std::string &story,
51                                 double value,
52                                 const std::string &units)
53 {
54     std::string measurementAndStory = measurement + story;
55     if (mHistograms.count(measurementAndStory) == 0)
56     {
57         proto::UnitAndDirection unitAndDirection;
58         unitAndDirection.set_improvement_direction(proto::SMALLER_IS_BETTER);
59         unitAndDirection.set_unit(proto::MS_BEST_FIT_FORMAT);
60 
61         std::unique_ptr<catapult::HistogramBuilder> builder =
62             std::make_unique<catapult::HistogramBuilder>(measurement, unitAndDirection);
63 
64         // Set all summary options as false - we don't want to generate metric_std, metric_count,
65         // and so on for all metrics.
66         builder->SetSummaryOptions(proto::SummaryOptions());
67         mHistograms[measurementAndStory] = std::move(builder);
68 
69         proto::Diagnostic stories;
70         proto::GenericSet *genericSet = stories.mutable_generic_set();
71         genericSet->add_values(story);
72         mHistograms[measurementAndStory]->AddDiagnostic(catapult::kStoriesDiagnostic, stories);
73     }
74 
75     mHistograms[measurementAndStory]->AddSample(value);
76 }
77 
getAsJSON(js::Document * doc) const78 void HistogramWriter::getAsJSON(js::Document *doc) const
79 {
80     proto::HistogramSet histogramSet;
81 
82     for (const auto &histogram : mHistograms)
83     {
84         std::unique_ptr<proto::Histogram> proto = histogram.second->toProto();
85         histogramSet.mutable_histograms()->AddAllocated(proto.release());
86     }
87 
88     // Custom JSON serialization for histogram-json-set.
89     doc->SetArray();
90 
91     js::Document::AllocatorType &allocator = doc->GetAllocator();
92 
93     for (int histogramIndex = 0; histogramIndex < histogramSet.histograms_size(); ++histogramIndex)
94     {
95         const proto::Histogram &histogram = histogramSet.histograms(histogramIndex);
96 
97         js::Value obj(js::kObjectType);
98 
99         js::Value name(histogram.name(), allocator);
100         obj.AddMember("name", name, allocator);
101 
102         js::Value description(histogram.description(), allocator);
103         obj.AddMember("description", description, allocator);
104 
105         js::Value unitAndDirection(GetUnitAndDirection(histogram.unit()), allocator);
106         obj.AddMember("unit", unitAndDirection, allocator);
107 
108         if (histogram.has_diagnostics())
109         {
110             js::Value diags(js::kObjectType);
111 
112             for (const auto &mapIter : histogram.diagnostics().diagnostic_map())
113             {
114                 js::Value key(mapIter.first, allocator);
115                 const proto::Diagnostic &diagnostic = mapIter.second;
116 
117                 if (!diagnostic.shared_diagnostic_guid().empty())
118                 {
119                     js::Value guid(diagnostic.shared_diagnostic_guid(), allocator);
120                     diags.AddMember(key, guid, allocator);
121                 }
122                 else if (diagnostic.has_generic_set())
123                 {
124                     const proto::GenericSet genericSet = diagnostic.generic_set();
125 
126                     js::Value setObj(js::kObjectType);
127                     setObj.AddMember("type", "GenericSet", allocator);
128 
129                     js::Value values(js::kArrayType);
130 
131                     for (const std::string &value : genericSet.values())
132                     {
133                         js::Value valueStr(value, allocator);
134                         values.PushBack(valueStr, allocator);
135                     }
136 
137                     setObj.AddMember("values", values, allocator);
138 
139                     diags.AddMember(key, setObj, allocator);
140                 }
141                 else
142                 {
143                     UNREACHABLE();
144                 }
145             }
146 
147             obj.AddMember("diagnostics", diags, allocator);
148         }
149 
150         js::Value sampleValues(js::kArrayType);
151 
152         for (int sampleIndex = 0; sampleIndex < histogram.sample_values_size(); ++sampleIndex)
153         {
154             js::Value sample(histogram.sample_values(sampleIndex));
155             sampleValues.PushBack(sample, allocator);
156         }
157 
158         obj.AddMember("sampleValues", sampleValues, allocator);
159 
160         js::Value maxNumSamplesValues(histogram.max_num_sample_values());
161         obj.AddMember("maxNumSamplesValues", maxNumSamplesValues, allocator);
162 
163         if (histogram.has_bin_boundaries())
164         {
165             js::Value binBoundaries(js::kArrayType);
166 
167             const proto::BinBoundaries &boundaries = histogram.bin_boundaries();
168             for (int binIndex = 0; binIndex < boundaries.bin_specs_size(); ++binIndex)
169             {
170                 js::Value binSpec(boundaries.bin_specs(binIndex).bin_boundary());
171                 binBoundaries.PushBack(binSpec, allocator);
172             }
173 
174             obj.AddMember("binBoundaries", binBoundaries, allocator);
175         }
176 
177         if (histogram.has_summary_options())
178         {
179             const proto::SummaryOptions &options = histogram.summary_options();
180 
181             js::Value summary(js::kObjectType);
182 
183             js::Value avg(options.avg());
184             js::Value count(options.count());
185             js::Value max(options.max());
186             js::Value min(options.min());
187             js::Value std(options.std());
188             js::Value sum(options.sum());
189 
190             summary.AddMember("avg", avg, allocator);
191             summary.AddMember("count", count, allocator);
192             summary.AddMember("max", max, allocator);
193             summary.AddMember("min", min, allocator);
194             summary.AddMember("std", std, allocator);
195             summary.AddMember("sum", sum, allocator);
196 
197             obj.AddMember("summaryOptions", summary, allocator);
198         }
199 
200         if (histogram.has_running())
201         {
202             const proto::RunningStatistics &running = histogram.running();
203 
204             js::Value stats(js::kArrayType);
205 
206             js::Value count(running.count());
207             js::Value max(running.max());
208             js::Value meanlogs(running.meanlogs());
209             js::Value mean(running.mean());
210             js::Value min(running.min());
211             js::Value sum(running.sum());
212             js::Value variance(running.variance());
213 
214             stats.PushBack(count, allocator);
215             stats.PushBack(max, allocator);
216             stats.PushBack(meanlogs, allocator);
217             stats.PushBack(mean, allocator);
218             stats.PushBack(min, allocator);
219             stats.PushBack(sum, allocator);
220             stats.PushBack(variance, allocator);
221 
222             obj.AddMember("running", stats, allocator);
223         }
224 
225         doc->PushBack(obj, allocator);
226     }
227 
228     for (const auto &diagnosticIt : histogramSet.shared_diagnostics())
229     {
230         const proto::Diagnostic &diagnostic = diagnosticIt.second;
231 
232         js::Value obj(js::kObjectType);
233 
234         js::Value name(diagnosticIt.first, allocator);
235         obj.AddMember("name", name, allocator);
236 
237         switch (diagnostic.diagnostic_oneof_case())
238         {
239             case proto::Diagnostic::kGenericSet:
240             {
241                 js::Value type("GenericSet", allocator);
242                 obj.AddMember("type", type, allocator);
243 
244                 const proto::GenericSet &genericSet = diagnostic.generic_set();
245 
246                 js::Value values(js::kArrayType);
247 
248                 for (const std::string &value : genericSet.values())
249                 {
250                     js::Value valueStr(value, allocator);
251                     values.PushBack(valueStr, allocator);
252                 }
253 
254                 obj.AddMember("values", values, allocator);
255                 break;
256             }
257 
258             default:
259                 UNREACHABLE();
260         }
261 
262         doc->PushBack(obj, allocator);
263     }
264 }
265 }  // namespace angle
266