LibcMemoryBenchmarkMain.cpp 3.36 KB
//===-- Benchmark ---------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "LibcMemoryBenchmarkMain.h"
#include "JSON.h"
#include "LibcBenchmark.h"
#include "LibcMemoryBenchmark.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"

#include <string>

namespace llvm {
namespace libc_benchmarks {

static cl::opt<std::string>
    Configuration("conf", cl::desc("Specify configuration filename"),
                  cl::value_desc("filename"), cl::init(""));

static cl::opt<std::string> Output("o", cl::desc("Specify output filename"),
                                   cl::value_desc("filename"), cl::init("-"));

extern std::unique_ptr<BenchmarkRunner>
getRunner(const StudyConfiguration &Conf);

void Main() {
#ifndef NDEBUG
  static_assert(
      false,
      "For reproducibility benchmarks should not be compiled in DEBUG mode.");
#endif
  checkRequirements();
  ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
      MemoryBuffer::getFileOrSTDIN(Configuration);
  if (!MB)
    report_fatal_error(
        Twine("Could not open configuration file: ").concat(Configuration));
  auto ErrorOrStudy = ParseJsonStudy((*MB)->getBuffer());
  if (!ErrorOrStudy)
    report_fatal_error(ErrorOrStudy.takeError());

  const auto StudyPrototype = *ErrorOrStudy;

  Study S;
  S.Host = HostState::get();
  S.Options = StudyPrototype.Options;
  S.Configuration = StudyPrototype.Configuration;

  const auto Runs = S.Configuration.Runs;
  const auto &SR = S.Configuration.Size;
  std::unique_ptr<BenchmarkRunner> Runner = getRunner(S.Configuration);
  const size_t TotalSteps =
      Runner->getFunctionNames().size() * Runs * ((SR.To - SR.From) / SR.Step);
  size_t Steps = 0;
  for (auto FunctionName : Runner->getFunctionNames()) {
    FunctionMeasurements FM;
    FM.Name = std::string(FunctionName);
    for (size_t Run = 0; Run < Runs; ++Run) {
      for (uint32_t Size = SR.From; Size <= SR.To; Size += SR.Step) {
        const auto Result = Runner->benchmark(S.Options, FunctionName, Size);
        Measurement Measurement;
        Measurement.Runtime = Result.BestGuess;
        Measurement.Size = Size;
        FM.Measurements.push_back(Measurement);
        outs() << format("%3d%% run: %2d / %2d size: %5d ",
                         (Steps * 100 / TotalSteps), Run, Runs, Size)
               << FunctionName
               << "                                                  \r";
        ++Steps;
      }
    }
    S.Functions.push_back(std::move(FM));
  }

  std::error_code EC;
  raw_fd_ostream FOS(Output, EC);
  if (EC)
    report_fatal_error(Twine("Could not open file: ")
                           .concat(EC.message())
                           .concat(", ")
                           .concat(Output));
  json::OStream JOS(FOS);
  SerializeToJson(S, JOS);
}

} // namespace libc_benchmarks
} // namespace llvm

int main(int argc, char **argv) {
  llvm::cl::ParseCommandLineOptions(argc, argv);
  llvm::libc_benchmarks::Main();
  return EXIT_SUCCESS;
}