brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.2 KiB · 6443ff4 Raw
327 lines · cpp
1//===-- JSON serialization routines ---------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "JSON.h"10#include "LibcBenchmark.h"11#include "llvm/ADT/DenseSet.h"12#include "llvm/ADT/SmallVector.h"13#include "llvm/ADT/StringRef.h"14#include "llvm/ADT/StringSwitch.h"15#include "llvm/Support/Errc.h"16#include "llvm/Support/Error.h"17#include "llvm/Support/ErrorHandling.h"18#include "llvm/Support/JSON.h"19#include "llvm/Support/MathExtras.h"20 21#include <chrono>22#include <limits>23#include <memory>24#include <optional>25#include <string>26#include <vector>27 28namespace llvm {29namespace libc_benchmarks {30 31template <typename T>32static Error intFromJsonTemplate(const json::Value &V, T &Out) {33  if (const auto &MaybeInt64 = V.getAsInteger()) {34    int64_t Value = *MaybeInt64;35    if (Value < std::numeric_limits<T>::min() ||36        Value > std::numeric_limits<T>::max())37      return createStringError(errc::io_error, "Out of bound Integer");38    Out = Value;39    return Error::success();40  }41  return createStringError(errc::io_error, "Can't parse Integer");42}43 44static Error fromJson(const json::Value &V, bool &Out) {45  if (auto B = V.getAsBoolean()) {46    Out = *B;47    return Error::success();48  }49  return createStringError(errc::io_error, "Can't parse Boolean");50}51 52static Error fromJson(const json::Value &V, double &Out) {53  if (auto S = V.getAsNumber()) {54    Out = *S;55    return Error::success();56  }57  return createStringError(errc::io_error, "Can't parse Double");58}59 60static Error fromJson(const json::Value &V, std::string &Out) {61  if (auto S = V.getAsString()) {62    Out = std::string(*S);63    return Error::success();64  }65  return createStringError(errc::io_error, "Can't parse String");66}67 68static Error fromJson(const json::Value &V, uint32_t &Out) {69  return intFromJsonTemplate(V, Out);70}71 72static Error fromJson(const json::Value &V, int &Out) {73  return intFromJsonTemplate(V, Out);74}75 76static Error fromJson(const json::Value &V, libc_benchmarks::Duration &D) {77  if (V.kind() != json::Value::Kind::Number)78    return createStringError(errc::io_error, "Can't parse Duration");79  D = libc_benchmarks::Duration(*V.getAsNumber());80  return Error::success();81}82 83static Error fromJson(const json::Value &V, MaybeAlign &Out) {84  const auto MaybeInt = V.getAsInteger();85  if (!MaybeInt)86    return createStringError(errc::io_error,87                             "Can't parse Align, not an Integer");88  const int64_t Value = *MaybeInt;89  if (!Value) {90    Out = std::nullopt;91    return Error::success();92  }93  if (isPowerOf2_64(Value)) {94    Out = Align(Value);95    return Error::success();96  }97  return createStringError(errc::io_error,98                           "Can't parse Align, not a power of two");99}100 101static Error fromJson(const json::Value &V,102                      libc_benchmarks::BenchmarkLog &Out) {103  if (V.kind() != json::Value::Kind::String)104    return createStringError(errc::io_error,105                             "Can't parse BenchmarkLog, not a String");106  const auto String = *V.getAsString();107  auto Parsed =108      llvm::StringSwitch<std::optional<libc_benchmarks::BenchmarkLog>>(String)109          .Case("None", libc_benchmarks::BenchmarkLog::None)110          .Case("Last", libc_benchmarks::BenchmarkLog::Last)111          .Case("Full", libc_benchmarks::BenchmarkLog::Full)112          .Default(std::nullopt);113  if (!Parsed)114    return createStringError(errc::io_error,115                             Twine("Can't parse BenchmarkLog, invalid value '")116                                 .concat(String)117                                 .concat("'"));118  Out = *Parsed;119  return Error::success();120}121 122template <typename C>123Error vectorFromJsonTemplate(const json::Value &V, C &Out) {124  auto *A = V.getAsArray();125  if (!A)126    return createStringError(errc::io_error, "Can't parse Array");127  Out.clear();128  Out.resize(A->size());129  for (auto InOutPair : llvm::zip(*A, Out))130    if (auto E = fromJson(std::get<0>(InOutPair), std::get<1>(InOutPair)))131      return std::move(E);132  return Error::success();133}134 135template <typename T>136static Error fromJson(const json::Value &V, std::vector<T> &Out) {137  return vectorFromJsonTemplate(V, Out);138}139 140// Same as llvm::json::ObjectMapper but adds a finer error reporting mechanism.141class JsonObjectMapper {142  const json::Object *O;143  Error E;144  SmallDenseSet<StringRef> SeenFields;145 146public:147  explicit JsonObjectMapper(const json::Value &V)148      : O(V.getAsObject()),149        E(O ? Error::success()150            : createStringError(errc::io_error, "Expected JSON Object")) {}151 152  Error takeError() {153    if (E)154      return std::move(E);155    for (const auto &Itr : *O) {156      const StringRef Key = Itr.getFirst();157      if (!SeenFields.count(Key))158        E = createStringError(errc::io_error,159                              Twine("Unknown field: ").concat(Key));160    }161    return std::move(E);162  }163 164  template <typename T> void map(StringRef Key, T &Out) {165    if (E)166      return;167    if (const json::Value *Value = O->get(Key)) {168      SeenFields.insert(Key);169      E = fromJson(*Value, Out);170    }171  }172};173 174static Error fromJson(const json::Value &V,175                      libc_benchmarks::BenchmarkOptions &Out) {176  JsonObjectMapper O(V);177  O.map("MinDuration", Out.MinDuration);178  O.map("MaxDuration", Out.MaxDuration);179  O.map("InitialIterations", Out.InitialIterations);180  O.map("MaxIterations", Out.MaxIterations);181  O.map("MinSamples", Out.MinSamples);182  O.map("MaxSamples", Out.MaxSamples);183  O.map("Epsilon", Out.Epsilon);184  O.map("ScalingFactor", Out.ScalingFactor);185  O.map("Log", Out.Log);186  return O.takeError();187}188 189static Error fromJson(const json::Value &V,190                      libc_benchmarks::StudyConfiguration &Out) {191  JsonObjectMapper O(V);192  O.map("Function", Out.Function);193  O.map("NumTrials", Out.NumTrials);194  O.map("IsSweepMode", Out.IsSweepMode);195  O.map("SweepModeMaxSize", Out.SweepModeMaxSize);196  O.map("SizeDistributionName", Out.SizeDistributionName);197  O.map("AccessAlignment", Out.AccessAlignment);198  O.map("MemcmpMismatchAt", Out.MemcmpMismatchAt);199  return O.takeError();200}201 202static Error fromJson(const json::Value &V, libc_benchmarks::CacheInfo &Out) {203  JsonObjectMapper O(V);204  O.map("Type", Out.Type);205  O.map("Level", Out.Level);206  O.map("Size", Out.Size);207  O.map("NumSharing", Out.NumSharing);208  return O.takeError();209}210 211static Error fromJson(const json::Value &V, libc_benchmarks::HostState &Out) {212  JsonObjectMapper O(V);213  O.map("CpuName", Out.CpuName);214  O.map("CpuFrequency", Out.CpuFrequency);215  O.map("Caches", Out.Caches);216  return O.takeError();217}218 219static Error fromJson(const json::Value &V, libc_benchmarks::Runtime &Out) {220  JsonObjectMapper O(V);221  O.map("Host", Out.Host);222  O.map("BufferSize", Out.BufferSize);223  O.map("BatchParameterCount", Out.BatchParameterCount);224  O.map("BenchmarkOptions", Out.BenchmarkOptions);225  return O.takeError();226}227 228static Error fromJson(const json::Value &V, libc_benchmarks::Study &Out) {229  JsonObjectMapper O(V);230  O.map("StudyName", Out.StudyName);231  O.map("Runtime", Out.Runtime);232  O.map("Configuration", Out.Configuration);233  O.map("Measurements", Out.Measurements);234  return O.takeError();235}236 237static double seconds(const Duration &D) {238  return std::chrono::duration<double>(D).count();239}240 241Expected<Study> parseJsonStudy(StringRef Content) {242  Expected<json::Value> EV = json::parse(Content);243  if (!EV)244    return EV.takeError();245  Study S;246  if (Error E = fromJson(*EV, S))247    return std::move(E);248  return S;249}250 251static StringRef serialize(const BenchmarkLog &L) {252  switch (L) {253  case BenchmarkLog::None:254    return "None";255  case BenchmarkLog::Last:256    return "Last";257  case BenchmarkLog::Full:258    return "Full";259  }260  llvm_unreachable("Unhandled BenchmarkLog value");261}262 263static void serialize(const BenchmarkOptions &BO, json::OStream &JOS) {264  JOS.attribute("MinDuration", seconds(BO.MinDuration));265  JOS.attribute("MaxDuration", seconds(BO.MaxDuration));266  JOS.attribute("InitialIterations", BO.InitialIterations);267  JOS.attribute("MaxIterations", BO.MaxIterations);268  JOS.attribute("MinSamples", BO.MinSamples);269  JOS.attribute("MaxSamples", BO.MaxSamples);270  JOS.attribute("Epsilon", BO.Epsilon);271  JOS.attribute("ScalingFactor", BO.ScalingFactor);272  JOS.attribute("Log", serialize(BO.Log));273}274 275static void serialize(const CacheInfo &CI, json::OStream &JOS) {276  JOS.attribute("Type", CI.Type);277  JOS.attribute("Level", CI.Level);278  JOS.attribute("Size", CI.Size);279  JOS.attribute("NumSharing", CI.NumSharing);280}281 282static void serialize(const StudyConfiguration &SC, json::OStream &JOS) {283  JOS.attribute("Function", SC.Function);284  JOS.attribute("NumTrials", SC.NumTrials);285  JOS.attribute("IsSweepMode", SC.IsSweepMode);286  JOS.attribute("SweepModeMaxSize", SC.SweepModeMaxSize);287  JOS.attribute("SizeDistributionName", SC.SizeDistributionName);288  JOS.attribute("AccessAlignment",289                static_cast<int64_t>(SC.AccessAlignment->value()));290  JOS.attribute("MemcmpMismatchAt", SC.MemcmpMismatchAt);291}292 293static void serialize(const HostState &HS, json::OStream &JOS) {294  JOS.attribute("CpuName", HS.CpuName);295  JOS.attribute("CpuFrequency", HS.CpuFrequency);296  JOS.attributeArray("Caches", [&]() {297    for (const auto &CI : HS.Caches)298      JOS.object([&]() { serialize(CI, JOS); });299  });300}301 302static void serialize(const Runtime &RI, json::OStream &JOS) {303  JOS.attributeObject("Host", [&]() { serialize(RI.Host, JOS); });304  JOS.attribute("BufferSize", RI.BufferSize);305  JOS.attribute("BatchParameterCount", RI.BatchParameterCount);306  JOS.attributeObject("BenchmarkOptions",307                      [&]() { serialize(RI.BenchmarkOptions, JOS); });308}309 310void serializeToJson(const Study &S, json::OStream &JOS) {311  JOS.object([&]() {312    JOS.attribute("StudyName", S.StudyName);313    JOS.attributeObject("Runtime", [&]() { serialize(S.Runtime, JOS); });314    JOS.attributeObject("Configuration",315                        [&]() { serialize(S.Configuration, JOS); });316    if (!S.Measurements.empty()) {317      JOS.attributeArray("Measurements", [&]() {318        for (const auto &M : S.Measurements)319          JOS.value(seconds(M));320      });321    }322  });323}324 325} // namespace libc_benchmarks326} // namespace llvm327