224 lines
6.0 KiB
C++
224 lines
6.0 KiB
C++
// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
|
|
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
|
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
|
//
|
|
// This file is part of the MFEM library. For more information and source code
|
|
// availability visit https://mfem.org.
|
|
//
|
|
// MFEM is free software; you can redistribute it and/or modify it under the
|
|
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
|
// CONTRIBUTING.md for details.
|
|
|
|
#include "bench.hpp"
|
|
|
|
#ifdef MFEM_USE_BENCHMARK
|
|
|
|
using namespace mfem;
|
|
|
|
// Default macro to register the tests
|
|
#define MFEM_VECTOR_BENCHMARK(x) BENCHMARK(x)->RangeMultiplier(4)->Range(1,KB);
|
|
|
|
// benchmark::CLASS generator with specific prefix
|
|
namespace benchmark
|
|
{
|
|
|
|
#define GENERATE_CLASS(CLASS, PREFIX)\
|
|
class CLASS{\
|
|
protected:\
|
|
Memory<double> data; int size;\
|
|
public:\
|
|
explicit CLASS(int s);\
|
|
PREFIX ~CLASS();\
|
|
PREFIX void UseDevice(bool use_dev) const { data.UseDevice(use_dev); }\
|
|
PREFIX bool UseDevice() const { return data.UseDevice(); }\
|
|
PREFIX const double *Read(bool on_dev = true) const\
|
|
{ return mfem::Read(data, size, on_dev); }\
|
|
PREFIX double *Write(bool on_dev = true)\
|
|
{ return mfem::Write(data, size, on_dev); }\
|
|
PREFIX double *ReadWrite(bool on_dev = true)\
|
|
{ return mfem::ReadWrite(data, size, on_dev); }\
|
|
CLASS &operator=(double value);\
|
|
CLASS &operator+=(const CLASS &v);\
|
|
};\
|
|
inline CLASS::CLASS(int s){\
|
|
if (s > 0) { size = s; data.New(s); }\
|
|
else { size = 0; data.Reset(); }\
|
|
}\
|
|
inline CLASS::~CLASS() { data.Delete(); }\
|
|
inline CLASS &CLASS::operator=(double value){\
|
|
const bool use_dev = UseDevice()/*true*/;\
|
|
const int N = size;\
|
|
auto y = /*mfem::Write(data, size, use_dev)*/Write(use_dev);\
|
|
forall_switch(use_dev, N, [=] MFEM_HOST_DEVICE (int i) {y[i] = value;});\
|
|
return *this;\
|
|
}\
|
|
inline CLASS &CLASS::operator+=(const CLASS &v){\
|
|
MFEM_ASSERT(size == v.size, "incompatible Vectors!");\
|
|
const bool use_dev = UseDevice() || v.UseDevice();\
|
|
const int N = size;\
|
|
auto y = ReadWrite(use_dev);\
|
|
auto x = v.Read(use_dev);\
|
|
forall_switch(use_dev, N, [=] MFEM_HOST_DEVICE (int i) {y[i] += x[i];});\
|
|
return *this;\
|
|
}
|
|
|
|
GENERATE_CLASS(Vector,);
|
|
GENERATE_CLASS(Vector_Virtuals, virtual);
|
|
GENERATE_CLASS(Vector_Virtuals_Inlined, virtual inline);
|
|
|
|
} // namespace benchmark
|
|
|
|
|
|
// Operator =
|
|
|
|
static void Vector_EQ_MFEM(benchmark::State& state)
|
|
{
|
|
const size_t size = state.range(0);
|
|
mfem::Vector x(size);
|
|
for (auto _ : state) { x = M_PI; }
|
|
}
|
|
MFEM_VECTOR_BENCHMARK(Vector_EQ_MFEM);
|
|
|
|
static void Vector_EQ(benchmark::State& state)
|
|
{
|
|
const size_t size = state.range(0);
|
|
benchmark::Vector x(size);
|
|
for (auto _ : state) { x = M_PI; }
|
|
}
|
|
MFEM_VECTOR_BENCHMARK(Vector_EQ);
|
|
|
|
static void Vector_EQ_Virtuals(benchmark::State& state)
|
|
{
|
|
const size_t size = state.range(0);
|
|
benchmark::Vector_Virtuals x(size);
|
|
for (auto _ : state) { x = M_PI; }
|
|
}
|
|
MFEM_VECTOR_BENCHMARK(Vector_EQ_Virtuals);
|
|
|
|
static void Vector_EQ_Virtuals_Inlined(benchmark::State& state)
|
|
{
|
|
const size_t size = state.range(0);
|
|
benchmark::Vector_Virtuals_Inlined x(size);
|
|
for (auto _ : state) { x = M_PI; }
|
|
}
|
|
MFEM_VECTOR_BENCHMARK(Vector_EQ_Virtuals_Inlined);
|
|
|
|
|
|
// Operator +=
|
|
|
|
static void Vector_PE_MFEM(benchmark::State& state)
|
|
{
|
|
const size_t size = state.range(0);
|
|
mfem::Vector x(size), y(size);
|
|
x = M_PI; y = M_E;
|
|
for (auto _ : state) { x += y; }
|
|
}
|
|
MFEM_VECTOR_BENCHMARK(Vector_PE_MFEM);
|
|
|
|
static void Vector_PE_MFEM_64(benchmark::State& state)
|
|
{
|
|
const size_t size = state.range(0);
|
|
mfem::Vector x(size, MemoryType::HOST_64);
|
|
mfem::Vector y(size, MemoryType::HOST_64);
|
|
x = M_PI; y = M_E;
|
|
for (auto _ : state) { x += y; }
|
|
}
|
|
MFEM_VECTOR_BENCHMARK(Vector_PE_MFEM_64);
|
|
|
|
static void Vector_PE(benchmark::State& state)
|
|
{
|
|
const size_t size = state.range(0);
|
|
benchmark::Vector x(size); x = M_PI;
|
|
benchmark::Vector y(size); y = M_E;
|
|
for (auto _ : state) { x += y; }
|
|
}
|
|
MFEM_VECTOR_BENCHMARK(Vector_PE);
|
|
|
|
static void Vector_PE_Virtuals(benchmark::State& state)
|
|
{
|
|
const size_t size = state.range(0);
|
|
benchmark::Vector_Virtuals x(size); x = M_PI;
|
|
benchmark::Vector_Virtuals y(size); y = M_E;
|
|
for (auto _ : state) { x += y; }
|
|
}
|
|
MFEM_VECTOR_BENCHMARK(Vector_PE_Virtuals);
|
|
|
|
static void Vector_Virtuals_Inlined_PE(benchmark::State& state)
|
|
{
|
|
const size_t size = state.range(0);
|
|
benchmark::Vector_Virtuals_Inlined x(size); x = M_PI;
|
|
benchmark::Vector_Virtuals_Inlined y(size); y = M_E;
|
|
for (auto _ : state) { x += y; }
|
|
}
|
|
MFEM_VECTOR_BENCHMARK(Vector_Virtuals_Inlined_PE);
|
|
|
|
// Base class
|
|
struct Base
|
|
{
|
|
void nop()
|
|
{
|
|
int unused;
|
|
benchmark::DoNotOptimize(unused);
|
|
asm volatile("nop" : "=r" (unused));
|
|
}
|
|
};
|
|
|
|
static void Base(benchmark::State& state)
|
|
{
|
|
struct Base b;
|
|
for (auto _ : state) { b.nop(); }
|
|
}
|
|
MFEM_VECTOR_BENCHMARK(Base);
|
|
|
|
class Base_Virtuals
|
|
{
|
|
public:
|
|
virtual void nop()
|
|
{
|
|
int unused;
|
|
benchmark::DoNotOptimize(unused);
|
|
asm volatile("nop" : "=r" (unused));
|
|
}
|
|
};
|
|
|
|
static void Base_Virtuals_inlined(benchmark::State& state)
|
|
{
|
|
// it will be resolved at compile time, so it can be inlined
|
|
Base_Virtuals b;
|
|
for (auto _ : state) { b.nop(); }
|
|
}
|
|
MFEM_VECTOR_BENCHMARK(Base_Virtuals_inlined);
|
|
|
|
// Base dummy BMDerivedVector class
|
|
class Base_Virtuals_Derived: public Base_Virtuals
|
|
{
|
|
public:
|
|
void nop()
|
|
{
|
|
int unused;
|
|
benchmark::DoNotOptimize(unused);
|
|
asm volatile("nop" : "=r" (unused));
|
|
}
|
|
};
|
|
|
|
static void Base_Virtuals_Derived_not_inlined(benchmark::State& state)
|
|
{
|
|
// cannot be inlined through the pointer
|
|
Base_Virtuals *ptr = new Base_Virtuals_Derived();
|
|
for (auto _ : state) { ptr->nop(); }
|
|
}
|
|
MFEM_VECTOR_BENCHMARK(Base_Virtuals_Derived_not_inlined);
|
|
|
|
// --benchmark_filter=all
|
|
// --benchmark_filter=Vector_PE_MFEM
|
|
int main(int argc, char *argv[])
|
|
{
|
|
mfem::Reporter mfem_reporter;
|
|
::benchmark::Initialize(&argc, argv);
|
|
if (::benchmark::ReportUnrecognizedArguments(argc, argv)) { return 1; }
|
|
::benchmark::RunSpecifiedBenchmarks(&mfem_reporter);
|
|
return 0;
|
|
}
|
|
|
|
#endif // MFEM_USE_BENCHMARK
|