// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0

// Elementwise expressions through the Tensor executor: out = a + b, out = a * b + c and out = exp(a) over 2^16 to
// 2^26 elements, for float and half on aligned maps (the packet path) and unaligned ones (the scalar path), and for
// bfloat16, which has no device packet and takes the scalar path whatever the map. Baselines: a hand-written
// grid-stride float4 kernel and cudaMemcpyAsync device to device, which bounds what a memory-bound kernel can reach.
// Bytes per launch count every operand read once and the result written once.

#include "gpu_bench_common.h"

namespace {

using eigen_bench::DeviceBuffer;

const int kLaunchesPerIteration = 4;
const int kIterations = 10;
const std::vector<int64_t> kSizes = {1 << 16, 1 << 20, 1 << 24, 1 << 26};
const double kExactTolerance = 0.0;
// Result checks in units of the type's epsilon: the device may fuse a * b + c (one rounding fewer than the host's
// two), and its exp is within a few ulps of the host's before the rounding to a narrow type.
template <typename T>
double epsilons(int count) {
  return count * static_cast<double>(std::numeric_limits<T>::epsilon());
}

template <typename T, int MapOptions>
using Map1D = Eigen::TensorMap<Eigen::Tensor<T, 1>, MapOptions>;

// One elementwise benchmark: NumInputs random device buffers, `expression(device, out, inputs)` enqueued on the
// executor, `reference(host_inputs, i)` checked once outside the timed loop, then the timing.
template <typename T, int MapOptions, int NumInputs, typename Expression, typename Reference>
void bench_elementwise(benchmark::State& state, Expression expression, Reference reference, double tolerance,
                       const char* name) {
  const int64_t n = state.range(0);
  std::vector<DeviceBuffer<T>> inputs;
  std::vector<Map1D<T, MapOptions>> maps;
  inputs.reserve(NumInputs);
  for (int k = 0; k < NumInputs; ++k) {
    inputs.emplace_back(n);
    inputs.back().fillRandom();
    maps.push_back(Map1D<T, MapOptions>(inputs.back().data(), n));
  }
  DeviceBuffer<T> out(n);
  Eigen::GpuStreamDevice stream;
  Eigen::GpuDevice device(&stream);
  Map1D<T, MapOptions> tout(out.data(), n);
  const auto enqueue = [&] { expression(device, tout, maps); };
  eigen_bench::warmUp(device.stream(), enqueue);
  {
    std::vector<std::vector<T>> host;
    for (const auto& input : inputs) host.push_back(input.toHost());
    std::vector<T> expected(n);
    for (int64_t i = 0; i < n; ++i) expected[i] = reference(host, i);
    eigen_bench::requireClose(out.toHost(), expected, tolerance, name);
  }
  eigen_bench::timeLaunches(state, device.stream(), enqueue, kLaunchesPerIteration);
  state.counters["bytes_per_second"] = eigen_bench::bytesPerSecond((NumInputs + 1.0) * n * sizeof(T));
}

template <typename T, int MapOptions>
void BM_Add(benchmark::State& state) {
  using Map = Map1D<T, MapOptions>;
  bench_elementwise<T, MapOptions, 2>(
      state,
      [](const Eigen::GpuDevice& device, Map& out, const std::vector<Map>& in) { out.device(device) = in[0] + in[1]; },
      [](const std::vector<std::vector<T>>& x, int64_t i) { return static_cast<T>(x[0][i] + x[1][i]); },
      kExactTolerance, "add");
}

template <typename T, int MapOptions>
void BM_MulAdd(benchmark::State& state) {
  using Map = Map1D<T, MapOptions>;
  bench_elementwise<T, MapOptions, 3>(
      state,
      [](const Eigen::GpuDevice& device, Map& out, const std::vector<Map>& in) {
        out.device(device) = in[0] * in[1] + in[2];
      },
      [](const std::vector<std::vector<T>>& x, int64_t i) { return static_cast<T>(x[0][i] * x[1][i] + x[2][i]); },
      epsilons<T>(4), "mul_add");
}

template <typename T, int MapOptions>
void BM_Exp(benchmark::State& state) {
  using Map = Map1D<T, MapOptions>;
  bench_elementwise<T, MapOptions, 1>(
      state,
      [](const Eigen::GpuDevice& device, Map& out, const std::vector<Map>& in) { out.device(device) = in[0].exp(); },
      [](const std::vector<std::vector<T>>& x, int64_t i) {
        return static_cast<T>(std::exp(static_cast<float>(x[0][i])));
      },
      epsilons<T>(8), "exp");
}

// What a kernel written by hand for this one expression reaches: 16-byte loads and stores, a grid sized to keep
// every multiprocessor busy, no evaluator.
__global__ void add_float4_kernel(const float4* a, const float4* b, float4* out, int n4) {
  for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < n4; i += gridDim.x * blockDim.x) {
    const float4 x = a[i];
    const float4 y = b[i];
    out[i] = make_float4(x.x + y.x, x.y + y.y, x.z + y.z, x.w + y.w);
  }
}

void BM_AddHandWritten(benchmark::State& state) {
  const int64_t n = state.range(0);
  DeviceBuffer<float> a(n), b(n), out(n);
  a.fillRandom();
  b.fillRandom();
  int device_id = 0;
  EIGEN_GPU_RUNTIME_CHECK(cudaGetDevice(&device_id));
  int multiprocessors = 0;
  EIGEN_GPU_RUNTIME_CHECK(cudaDeviceGetAttribute(&multiprocessors, cudaDevAttrMultiProcessorCount, device_id));
  const int n4 = static_cast<int>(n / 4);
  const int block = 256;
  const int grid = std::min((n4 + block - 1) / block, multiprocessors * 8);
  cudaStream_t stream = nullptr;
  const auto enqueue = [&] {
    add_float4_kernel<<<grid, block, 0, stream>>>(reinterpret_cast<const float4*>(a.data()),
                                                  reinterpret_cast<const float4*>(b.data()),
                                                  reinterpret_cast<float4*>(out.data()), n4);
    EIGEN_GPU_RUNTIME_CHECK(cudaGetLastError());
  };
  eigen_bench::warmUp(stream, enqueue);
  {
    const std::vector<float> ha = a.toHost(), hb = b.toHost();
    std::vector<float> expected(n);
    for (int64_t i = 0; i < n; ++i) expected[i] = ha[i] + hb[i];
    eigen_bench::requireClose(out.toHost(), expected, kExactTolerance, "add_hand_written");
  }
  eigen_bench::timeLaunches(state, stream, enqueue, kLaunchesPerIteration);
  state.counters["bytes_per_second"] = eigen_bench::bytesPerSecond(3.0 * n * sizeof(float));
}

// The copy roofline: one read and one write per element, no arithmetic.
void BM_D2DMemcpy(benchmark::State& state) {
  const int64_t n = state.range(0);
  DeviceBuffer<float> a(n), out(n);
  a.fillRandom();
  cudaStream_t stream = nullptr;
  const auto enqueue = [&] {
    EIGEN_GPU_RUNTIME_CHECK(cudaMemcpyAsync(out.data(), a.data(), n * sizeof(float), cudaMemcpyDeviceToDevice, stream));
  };
  eigen_bench::warmUp(stream, enqueue);
  eigen_bench::timeLaunches(state, stream, enqueue, kLaunchesPerIteration);
  state.counters["bytes_per_second"] = eigen_bench::bytesPerSecond(2.0 * n * sizeof(float));
}

}  // namespace

// bfloat16 has no device packet, so it is registered once, as the scalar path it is.
#define EIGEN_GPU_ELEMENTWISE_BENCHMARKS(NAME)                    \
  EIGEN_GPU_BENCHMARK_SIZES(NAME, float, Eigen::Aligned);         \
  EIGEN_GPU_BENCHMARK_SIZES(NAME, float, Eigen::Unaligned);       \
  EIGEN_GPU_BENCHMARK_SIZES(NAME, Eigen::half, Eigen::Aligned);   \
  EIGEN_GPU_BENCHMARK_SIZES(NAME, Eigen::half, Eigen::Unaligned); \
  EIGEN_GPU_BENCHMARK_SIZES(NAME, Eigen::bfloat16, Eigen::Unaligned);

EIGEN_GPU_ELEMENTWISE_BENCHMARKS(BM_Add)
EIGEN_GPU_ELEMENTWISE_BENCHMARKS(BM_MulAdd)
EIGEN_GPU_ELEMENTWISE_BENCHMARKS(BM_Exp)
EIGEN_GPU_BENCHMARK(BM_AddHandWritten)->ArgsProduct({kSizes});
EIGEN_GPU_BENCHMARK(BM_D2DMemcpy)->ArgsProduct({kSizes});

EIGEN_GPU_BENCHMARK_MAIN()
