Edit

kc3-lang/angle/src/tests/test_utils/runner/HistogramWriter.cpp

Branch :

  • Show log

    Commit

  • Author : Jamie Madill
    Date : 2020-10-31 12:33:28
    Hash : 3e5b6f81
    Message : Enable writing histogram-set-json-format. This uses the protobuf histogram functionality to build up a histogram set. The test suites then output the histograms to JSON. This is only implemented for angle_perftests. Bug: angleproject:5161 Change-Id: Ia5a7868e8d8dcf4f13d83115ae622828c63ef0d9 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2482295 Reviewed-by: Brian Sheedy <bsheedy@chromium.org> Reviewed-by: Yuly Novikov <ynovikov@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/tests/test_utils/runner/HistogramWriter.cpp
  • //
    // Copyright 2020 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // HistogramWriter:
    //   Helper class for writing histogram-json-set-format files to JSON.
    
    #include "HistogramWriter.h"
    
    #include "common/debug.h"
    
    #include <rapidjson/document.h>
    
    #if !defined(ANGLE_HAS_HISTOGRAMS)
    #    error "Must have histograms enabled"
    #endif  // !defined(ANGLE_HAS_HISTOGRAMS)
    
    ANGLE_DISABLE_EXTRA_SEMI_WARNING
    ANGLE_DISABLE_EXTRA_SEMI_STMT_WARNING
    ANGLE_DISABLE_DESTRUCTOR_OVERRIDE_WARNING
    ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS
    #include "tracing/tracing/value/diagnostics/reserved_infos.h"
    #include "tracing/tracing/value/histogram.h"
    ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS
    ANGLE_REENABLE_DESTRUCTOR_OVERRIDE_WARNING
    ANGLE_REENABLE_EXTRA_SEMI_STMT_WARNING
    ANGLE_REENABLE_EXTRA_SEMI_WARNING
    
    namespace js    = rapidjson;
    namespace proto = catapult::tracing::tracing::proto;
    
    namespace angle
    {
    namespace
    {
    std::string AsJsonString(const std::string string)
    {
        return "\"" + string + "\"";
    }
    
    std::string GetUnitAndDirection(proto::UnitAndDirection unit)
    {
        ASSERT(unit.improvement_direction() == proto::SMALLER_IS_BETTER);
        ASSERT(unit.unit() == proto::MS_BEST_FIT_FORMAT);
        return "msBestFitFormat";
    }
    }  // namespace
    
    HistogramWriter::HistogramWriter() = default;
    
    HistogramWriter::~HistogramWriter() = default;
    
    void HistogramWriter::addSample(const std::string &measurement,
                                    const std::string &story,
                                    double value,
                                    const std::string &units)
    {
        std::string measurementAndStory = measurement + story;
        if (mHistograms.count(measurementAndStory) == 0)
        {
            proto::UnitAndDirection unitAndDirection;
            unitAndDirection.set_improvement_direction(proto::SMALLER_IS_BETTER);
            unitAndDirection.set_unit(proto::MS_BEST_FIT_FORMAT);
    
            std::unique_ptr<catapult::HistogramBuilder> builder =
                std::make_unique<catapult::HistogramBuilder>(measurement, unitAndDirection);
    
            // Set all summary options as false - we don't want to generate metric_std, metric_count,
            // and so on for all metrics.
            builder->SetSummaryOptions(proto::SummaryOptions());
            mHistograms[measurementAndStory] = std::move(builder);
    
            proto::Diagnostic stories;
            proto::GenericSet *genericSet = stories.mutable_generic_set();
            genericSet->add_values(AsJsonString(story));
            mHistograms[measurementAndStory]->AddDiagnostic(catapult::kStoriesDiagnostic, stories);
        }
    
        mHistograms[measurementAndStory]->AddSample(value);
    }
    
    void HistogramWriter::getAsJSON(js::Document *doc) const
    {
        proto::HistogramSet histogramSet;
    
        for (const auto &histogram : mHistograms)
        {
            std::unique_ptr<proto::Histogram> proto = histogram.second->toProto();
            histogramSet.mutable_histograms()->AddAllocated(proto.release());
        }
    
        // Custom JSON serialization for histogram-json-set.
        doc->SetArray();
    
        js::Document::AllocatorType &allocator = doc->GetAllocator();
    
        for (int histogramIndex = 0; histogramIndex < histogramSet.histograms_size(); ++histogramIndex)
        {
            const proto::Histogram &histogram = histogramSet.histograms(histogramIndex);
    
            js::Value obj(js::kObjectType);
    
            js::Value name(histogram.name(), allocator);
            obj.AddMember("name", name, allocator);
    
            js::Value description(histogram.description(), allocator);
            obj.AddMember("description", description, allocator);
    
            js::Value unitAndDirection(GetUnitAndDirection(histogram.unit()), allocator);
            obj.AddMember("unit", unitAndDirection, allocator);
    
            if (histogram.has_diagnostics())
            {
                js::Value diags(js::kObjectType);
    
                for (const auto &mapIter : histogram.diagnostics().diagnostic_map())
                {
                    js::Value key(mapIter.first, allocator);
                    const proto::Diagnostic &diagnostic = mapIter.second;
    
                    if (!diagnostic.shared_diagnostic_guid().empty())
                    {
                        js::Value guid(diagnostic.shared_diagnostic_guid(), allocator);
                        diags.AddMember(key, guid, allocator);
                    }
                    else if (diagnostic.has_generic_set())
                    {
                        const proto::GenericSet genericSet = diagnostic.generic_set();
    
                        js::Value setObj(js::kObjectType);
                        setObj.AddMember("type", "GenericSet", allocator);
    
                        js::Value values(js::kArrayType);
    
                        for (const std::string &value : genericSet.values())
                        {
                            js::Value valueStr(value, allocator);
                            values.PushBack(valueStr, allocator);
                        }
    
                        setObj.AddMember("values", values, allocator);
    
                        diags.AddMember(key, setObj, allocator);
                    }
                    else
                    {
                        UNREACHABLE();
                    }
                }
    
                obj.AddMember("diagnostics", diags, allocator);
            }
    
            js::Value sampleValues(js::kArrayType);
    
            for (int sampleIndex = 0; sampleIndex < histogram.sample_values_size(); ++sampleIndex)
            {
                js::Value sample(histogram.sample_values(sampleIndex));
                sampleValues.PushBack(sample, allocator);
            }
    
            obj.AddMember("sampleValues", sampleValues, allocator);
    
            js::Value maxNumSamplesValues(histogram.max_num_sample_values());
            obj.AddMember("maxNumSamplesValues", maxNumSamplesValues, allocator);
    
            if (histogram.has_bin_boundaries())
            {
                js::Value binBoundaries(js::kArrayType);
    
                const proto::BinBoundaries &boundaries = histogram.bin_boundaries();
                for (int binIndex = 0; binIndex < boundaries.bin_specs_size(); ++binIndex)
                {
                    js::Value binSpec(boundaries.bin_specs(binIndex).bin_boundary());
                    binBoundaries.PushBack(binSpec, allocator);
                }
    
                obj.AddMember("binBoundaries", binBoundaries, allocator);
            }
    
            if (histogram.has_summary_options())
            {
                const proto::SummaryOptions &options = histogram.summary_options();
    
                js::Value summary(js::kObjectType);
    
                js::Value avg(options.avg());
                js::Value count(options.count());
                js::Value max(options.max());
                js::Value min(options.min());
                js::Value std(options.std());
                js::Value sum(options.sum());
    
                summary.AddMember("avg", avg, allocator);
                summary.AddMember("count", count, allocator);
                summary.AddMember("max", max, allocator);
                summary.AddMember("min", min, allocator);
                summary.AddMember("std", std, allocator);
                summary.AddMember("sum", sum, allocator);
    
                obj.AddMember("summaryOptions", summary, allocator);
            }
    
            if (histogram.has_running())
            {
                const proto::RunningStatistics &running = histogram.running();
    
                js::Value stats(js::kArrayType);
    
                js::Value count(running.count());
                js::Value max(running.max());
                js::Value meanlogs(running.meanlogs());
                js::Value mean(running.mean());
                js::Value min(running.min());
                js::Value sum(running.sum());
                js::Value variance(running.variance());
    
                stats.PushBack(count, allocator);
                stats.PushBack(max, allocator);
                stats.PushBack(meanlogs, allocator);
                stats.PushBack(mean, allocator);
                stats.PushBack(min, allocator);
                stats.PushBack(sum, allocator);
                stats.PushBack(variance, allocator);
    
                obj.AddMember("running", stats, allocator);
            }
    
            doc->PushBack(obj, allocator);
        }
    
        for (const auto &diagnosticIt : histogramSet.shared_diagnostics())
        {
            const proto::Diagnostic &diagnostic = diagnosticIt.second;
    
            js::Value obj(js::kObjectType);
    
            js::Value name(diagnosticIt.first, allocator);
            obj.AddMember("name", name, allocator);
    
            switch (diagnostic.diagnostic_oneof_case())
            {
                case proto::Diagnostic::kGenericSet:
                {
                    js::Value type("GenericSet", allocator);
                    obj.AddMember("type", type, allocator);
    
                    const proto::GenericSet &genericSet = diagnostic.generic_set();
    
                    js::Value values(js::kArrayType);
    
                    for (const std::string &value : genericSet.values())
                    {
                        js::Value valueStr(value, allocator);
                        values.PushBack(valueStr, allocator);
                    }
    
                    obj.AddMember("values", values, allocator);
                    break;
                }
    
                default:
                    UNREACHABLE();
            }
    
            doc->PushBack(obj, allocator);
        }
    }
    }  // namespace angle