//===-- Analyze benchmark JSON files ----------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LIBC_BENCHMARKS_AUTOMEMCPY_RESULTANALYZER_H
#define LIBC_BENCHMARKS_AUTOMEMCPY_RESULTANALYZER_H

#include "automemcpy/FunctionDescriptor.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringMap.h"
#include <array>
#include <vector>

namespace llvm {
namespace automemcpy {

// A Grade as in the Majority Judgment voting system.
struct Grade {
  enum GradeEnum {
    EXCELLENT,
    VERY_GOOD,
    GOOD,
    PASSABLE,
    INADEQUATE,
    MEDIOCRE,
    BAD,
    ARRAY_SIZE,
  };

  // Returns a human readable string of the enum.
  static StringRef getString(const GradeEnum &GE);

  // Turns 'Score' into a GradeEnum.
  static GradeEnum judge(double Score);
};

// A 'GradeEnum' indexed array with counts for each grade.
using GradeHistogram = std::array<size_t, Grade::ARRAY_SIZE>;

// Identifies a Function by its name and type. Used as a key in a map.
struct FunctionId {
  StringRef Name;
  FunctionType Type;
  COMPARABLE_AND_HASHABLE(FunctionId, Type, Name)
};

struct PerDistributionData {
  double MedianBytesPerSecond; // Median of samples for this distribution.
  double Score;                // Normalized score for this distribution.
  Grade::GradeEnum Grade;      // Grade for this distribution.
};

struct FunctionData {
  FunctionId Id;
  StringMap<PerDistributionData> PerDistributionData;
  GradeHistogram GradeHisto = {};           // GradeEnum indexed array
  Grade::GradeEnum FinalGrade = Grade::BAD; // Overall grade for this function
};

// Identifies a Distribution by its name. Used as a key in a map.
struct DistributionId {
  StringRef Name;
  COMPARABLE_AND_HASHABLE(DistributionId, Name)
};

// Identifies a Sample by its distribution and function. Used as a key in a map.
struct SampleId {
  FunctionId Function;
  DistributionId Distribution;
  COMPARABLE_AND_HASHABLE(SampleId, Function.Type, Function.Name,
                          Distribution.Name)
};

// A SampleId with an associated measured throughput.
struct Sample {
  SampleId Id;
  double BytesPerSecond = 0;
};

// This function collects Samples that belong to the same distribution and
// function and retains the median one. It then stores each of them into a
// 'FunctionData' and returns them as a vector.
std::vector<FunctionData> getThroughputs(ArrayRef<Sample> Samples);

// Normalize the function's throughput per distribution.
void fillScores(MutableArrayRef<FunctionData> Functions);

// Convert scores into Grades, stores an histogram of Grade for each functions
// and cast a median grade for the function.
void castVotes(MutableArrayRef<FunctionData> Functions);

} // namespace automemcpy
} // namespace llvm

#endif // LIBC_BENCHMARKS_AUTOMEMCPY_RESULTANALYZER_H
