Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] DoNotOptimize build break with GCC #1675

Open
marcalff opened this issue Oct 9, 2023 · 2 comments
Open

[BUG] DoNotOptimize build break with GCC #1675

marcalff opened this issue Oct 9, 2023 · 2 comments

Comments

@marcalff
Copy link

marcalff commented Oct 9, 2023

See downstream bug:

When building the following code:

void BM_ParentBasedSamplerConstruction(benchmark::State &state)
{
  while (state.KeepRunning())
  {
    benchmark::DoNotOptimize(ParentBasedSampler(std::make_shared<AlwaysOnSampler>())); // line 49
  }
}

and

void BM_TraceIdRatioBasedSamplerConstruction(benchmark::State &state)
{
  while (state.KeepRunning())
  {
    benchmark::DoNotOptimize(TraceIdRatioBasedSampler(0.01)); // line 58
  }
}

the build fails with GCC 7.4.1, GCC 7.5.0, GCC 12.3.0.

The error reported is:

[ 56%] Building CXX object sdk/test/trace/CMakeFiles/sampler_benchmark.dir/sampler_benchmark.cc.o
In file included from /home/malff/CODE/MARC_GITHUB/opentelemetry-cpp/sdk/test/trace/sampler_benchmark.cc:17:
/opt/benchmark-1.8.2/include/benchmark/benchmark.h: In instantiation of ‘typename std::enable_if<((! std::is_trivially_copyable<_Tp>::value) || (sizeof (Tp) > sizeof (Tp*)))>::type benchmark::DoNotOptimize(Tp&&) [with Tp = opentelemetry::v1::sdk::trace::ParentBasedSampler; typename std::enable_if<((! std::is_trivially_copyable<_Tp>::value) || (sizeof (Tp) > sizeof (Tp*)))>::type = void]’:
/home/malff/CODE/MARC_GITHUB/opentelemetry-cpp/sdk/test/trace/sampler_benchmark.cc:49:29:   required from here
/opt/benchmark-1.8.2/include/benchmark/benchmark.h:540:3: error: read-only reference ‘value’ used as ‘asm’ output
  540 |   asm volatile("" : "+m"(value) : : "memory");
      |   ^~~
/opt/benchmark-1.8.2/include/benchmark/benchmark.h: In instantiation of ‘typename std::enable_if<((! std::is_trivially_copyable<_Tp>::value) || (sizeof (Tp) > sizeof (Tp*)))>::type benchmark::DoNotOptimize(Tp&&) [with Tp = opentelemetry::v1::sdk::trace::TraceIdRatioBasedSampler; typename std::enable_if<((! std::is_trivially_copyable<_Tp>::value) || (sizeof (Tp) > sizeof (Tp*)))>::type = void]’:
/home/malff/CODE/MARC_GITHUB/opentelemetry-cpp/sdk/test/trace/sampler_benchmark.cc:58:29:   required from here
/opt/benchmark-1.8.2/include/benchmark/benchmark.h:540:3: error: read-only reference ‘value’ used as ‘asm’ output
make[2]: *** [sdk/test/trace/CMakeFiles/sampler_benchmark.dir/build.make:76: sdk/test/trace/CMakeFiles/sampler_benchmark.dir/sampler_benchmark.cc.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:4217: sdk/test/trace/CMakeFiles/sampler_benchmark.dir/all] Error 2
make: *** [Makefile:146: all] Error 2

Verified with benchmark 1.8.2 and 1.8.3.

Note that the same code builds fine with CLang.

If this matters, ParentBasedSampler and TraceIdRatioBasedSampler are classes: what is benchmarked here is a call to the constructor.

Note how the benchmark header file is different for GCC, with:

The build failure occurs in:

template <class Tp>
inline BENCHMARK_ALWAYS_INLINE
    typename std::enable_if<!std::is_trivially_copyable<Tp>::value ||
                            (sizeof(Tp) > sizeof(Tp*))>::type
    DoNotOptimize(Tp&& value) {
  asm volatile("" : "+m"(value) : : "memory"); // line 540
}

Expected result is a successful build with both GCC and Clang.

@marcalff
Copy link
Author

marcalff commented Oct 9, 2023

Reproducible test case:


// Build with:
// g++-12 -I/opt/benchmark-1.8.3/include/ foo.cc
//
// Fails:
//
// In file included from foo.cc:5:
// /opt/benchmark-1.8.3/include/benchmark/benchmark.h: In instantiation of ‘typename std::enable_if<((! std::is_trivially_copyable<_Tp>::value) || (sizeof (Tp) > sizeof (Tp*)))>::type benchmark::DoNotOptimize(Tp&&) [with Tp = TraceIdRatioBasedSampler; typename std::enable_if<((! std::is_trivially_copyable<_Tp>::value) || (sizeof (Tp) > sizeof (Tp*)))>::type = void]’:
// foo.cc:30:29:   required from here
// /opt/benchmark-1.8.3/include/benchmark/benchmark.h:540:3: error: read-only reference ‘value’ used as ‘asm’ output
//   540 |   asm volatile("" : "+m"(value) : : "memory");
//       |   ^~~


#include "benchmark/benchmark.h"

class Sampler
{
public:
  virtual ~Sampler() = default;

  virtual int GetDescription() const noexcept = 0;
};

class TraceIdRatioBasedSampler : public Sampler
{
public:
  explicit TraceIdRatioBasedSampler(double ratio);

  int GetDescription() const noexcept override;

private:
  // uint64_t threshold_;
  const uint64_t threshold_;
};

void BM_TraceIdRatioBasedSamplerConstruction(benchmark::State &state)
{
  while (state.KeepRunning())
  {
    benchmark::DoNotOptimize(TraceIdRatioBasedSampler(0.01));
  }
}

Note that changing

const uint64_t threshold_;

to

uint64_t threshold_;

resolves the build break.

@LebedevRI
Copy link
Collaborator

I'm 99% sure this is working as intended as per the deprecation of non-non-const DoNotOptimize,
but the error message is rather sub-par here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants