Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/varshneydevansh/benchmark_list_…
Browse files Browse the repository at this point in the history
…tests-work-with-benchmark-format=json-google#1642'
  • Loading branch information
GerHobbelt committed Dec 13, 2024
2 parents 6464088 + 438c8c3 commit c08727e
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 5 deletions.
20 changes: 20 additions & 0 deletions include/benchmark/benchmark.h
Original file line number Diff line number Diff line change
Expand Up @@ -2029,6 +2029,20 @@ class BENCHMARK_EXPORT BenchmarkReporter {
// REQUIRES: 'out' is non-null.
static void PrintBasicContext(std::ostream* out, Context const& context);

/**
* @brief Lists and describes the provided benchmarks.
*
* This virtual method is intended to be overridden by derived classes
* to provide specific implementations for listing benchmarks.
* It can be used for outputting, logging, or any other operation
* needed to handle or display the benchmarks' names and metadata.
*
* @param benchmarks A vector containing names and details of benchmarks
* that need to be listed or processed.
*/
virtual void List(
const std::vector<internal::BenchmarkInstance>& benchmarks) = 0;

private:
std::ostream* output_stream_;
std::ostream* error_stream_;
Expand All @@ -2050,6 +2064,8 @@ class BENCHMARK_EXPORT ConsoleReporter : public BenchmarkReporter {

bool ReportContext(const Context& context) BENCHMARK_OVERRIDE;
void ReportRuns(const std::vector<Run>& reports) BENCHMARK_OVERRIDE;
void List(const std::vector<internal::BenchmarkInstance>& benchmarks)
BENCHMARK_OVERRIDE;

protected:
virtual void PrintRunData(const Run& report);
Expand All @@ -2067,6 +2083,8 @@ class BENCHMARK_EXPORT JSONReporter : public BenchmarkReporter {
bool ReportContext(const Context& context) BENCHMARK_OVERRIDE;
void ReportRuns(const std::vector<Run>& reports) BENCHMARK_OVERRIDE;
void Finalize() BENCHMARK_OVERRIDE;
void List(const std::vector<internal::BenchmarkInstance>& benchmarks)
BENCHMARK_OVERRIDE;

private:
void PrintRunData(const Run& report);
Expand All @@ -2081,6 +2099,8 @@ class BENCHMARK_EXPORT BENCHMARK_DEPRECATED_MSG(
CSVReporter() : printed_header_(false) {}
bool ReportContext(const Context& context) BENCHMARK_OVERRIDE;
void ReportRuns(const std::vector<Run>& reports) BENCHMARK_OVERRIDE;
void List(const std::vector<internal::BenchmarkInstance>& benchmarks)
BENCHMARK_OVERRIDE;

private:
void PrintRunData(const Run& report);
Expand Down
3 changes: 1 addition & 2 deletions src/benchmark.cc
Original file line number Diff line number Diff line change
Expand Up @@ -651,8 +651,7 @@ size_t RunSpecifiedBenchmarks(const std::string& family, BenchmarkReporter* disp
}

if (FLAGS_benchmark_list_tests) {
for (auto const& benchmark : benchmarks)
Out << benchmark.name().str() << "\n";
display_reporter->List(benchmarks);
} else {
internal::RunBenchmarks(benchmarks, display_reporter, file_reporter);
}
Expand Down
11 changes: 10 additions & 1 deletion src/console_reporter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#include <tuple>
#include <vector>

#include "benchmark/benchmark.h"
#include "benchmark_api_internal.h"
#include "check.h"
#include "colorprint.h"
#include "commandlineflags.h"
Expand Down Expand Up @@ -207,4 +207,13 @@ void ConsoleReporter::PrintRunData(const Run& result) {
printer(Out, COLOR_DEFAULT, "\n");
}

BENCHMARK_EXPORT
void ConsoleReporter::List(
const std::vector<internal::BenchmarkInstance>& benchmarks) {
std::ostream& Out = GetOutputStream();
for (auto const& benchmark : benchmarks) {
Out << benchmark.name().str() << "\n";
}
}

} // end namespace benchmark
9 changes: 8 additions & 1 deletion src/csv_reporter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include <tuple>
#include <vector>

#include "benchmark/benchmark.h"
#include "benchmark_api_internal.h"
#include "check.h"
#include "complexity.h"
#include "string_util.h"
Expand Down Expand Up @@ -166,4 +166,11 @@ void CSVReporter::PrintRunData(const Run& run) {
Out << '\n';
}

void CSVReporter::List(
const std::vector<internal::BenchmarkInstance>& benchmarks) {
(void)benchmarks; // Suppress unused parameter warning
std::ostream& err = GetErrorStream();
err << "List() method is not implemented for CSVReporter.\n";
}

} // end namespace benchmark
16 changes: 15 additions & 1 deletion src/json_reporter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include <tuple>
#include <vector>

#include "benchmark/benchmark.h"
#include "benchmark_api_internal.h"
#include "complexity.h"
#include "string_util.h"
#include "timers.h"
Expand Down Expand Up @@ -324,4 +324,18 @@ void JSONReporter::PrintRunData(Run const& run) {
const int64_t MemoryManager::TombstoneValue =
std::numeric_limits<int64_t>::max();

void JSONReporter::List(
const std::vector<internal::BenchmarkInstance>& benchmarks) {
std::ostream& Out = GetOutputStream();
Out << "[";
for (size_t i = 0; i < benchmarks.size(); ++i) {
const auto& benchmark = benchmarks[i];
Out << "{" << FormatKV("name", benchmark.name().str()) << "}";
if (i != benchmarks.size() - 1) {
Out << ", ";
}
}
Out << "]";
}

} // end namespace benchmark
2 changes: 2 additions & 0 deletions test/benchmark_random_interleaving_gtest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class NullReporter : public BenchmarkReporter {
public:
bool ReportContext(const Context& /*context*/) override { return true; }
void ReportRuns(const std::vector<Run>& /* report */) override {}
void List(
const std::vector<benchmark::internal::BenchmarkInstance>&) override {}
};

class BenchmarkTest : public testing::Test {
Expand Down
8 changes: 8 additions & 0 deletions test/output_test_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,14 @@ class TestReporter : public benchmark::BenchmarkReporter {
for (auto rep : reporters_) rep->Finalize();
}

void List(const std::vector<benchmark::internal::BenchmarkInstance>&
benchmarks) override {
// simply logging the status
for (const auto& benchmark : benchmarks) {
std::cout << benchmark.name().str() << std::endl;
}
}

private:
std::vector<benchmark::BenchmarkReporter*> reporters_;
};
Expand Down
109 changes: 109 additions & 0 deletions test/reporter_list_gtest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <sstream>
#include "benchmark/benchmark.h"

namespace benchmark {
namespace internal {

// Helper function to register benchmarks
void RegisterBenchmarks() {
benchmark::RegisterBenchmark("BM_simple", [](benchmark::State& state) {
for (auto _ : state) {}
});
benchmark::RegisterBenchmark("BM_complex", [](benchmark::State& state) {
for (auto _ : state) {
// Simulating a complex operation
for (int i = 0; i < 1000; ++i) {
benchmark::DoNotOptimize(i * i);
}
}
});
benchmark::RegisterBenchmark("BM_special_chars", [](benchmark::State& state) {
for (auto _ : state) {}
})->Name("BM_special!@#");
}

class ReporterListTest : public ::testing::Test {
protected:
std::stringstream ss;
BenchmarkReporter::Context context;

void SetUp() override {
benchmark::ClearRegisteredBenchmarks();
ss.str("");
ss.clear();
}

void RunList(BenchmarkReporter& reporter) {
RegisterBenchmarks(); // Register all benchmarks
benchmark::RunSpecifiedBenchmarks(&reporter);
}
};

// Tests the behavior of reporters when no benchmarks are registered
TEST_F(ReporterListTest, HandlesEmptyBenchmarkList) {
benchmark::ConsoleReporter console_reporter(&ss);
benchmark::JSONReporter json_reporter(&ss);
benchmark::CSVReporter csv_reporter(&ss);

// Expect no output as no benchmarks are registered
RunList(console_reporter);
EXPECT_TRUE(ss.str().empty());

ss.str("");
RunList(json_reporter);
EXPECT_TRUE(ss.str().empty());

ss.str("");
RunList(csv_reporter);
EXPECT_TRUE(ss.str().empty());
}

// Tests the output of reporters when benchmarks are listed
TEST_F(ReporterListTest, ListsBenchmarksWithDifferentReporters) {
benchmark::ConsoleReporter console_reporter(&ss);
benchmark::JSONReporter json_reporter(&ss);
benchmark::CSVReporter csv_reporter(&ss);

RegisterBenchmarks(); // Ensure some benchmarks are registered

RunList(console_reporter);
EXPECT_THAT(ss.str(), ::testing::HasSubstr("BM_simple"));
EXPECT_THAT(ss.str(), ::testing::HasSubstr("BM_complex"));
EXPECT_THAT(ss.str(), ::testing::HasSubstr("BM_special!@#"));

ss.str("");
RunList(json_reporter);
EXPECT_THAT(ss.str(), ::testing::HasSubstr("\"name\": \"BM_simple\""));
EXPECT_THAT(ss.str(), ::testing::HasSubstr("\"name\": \"BM_complex\""));
EXPECT_THAT(ss.str(), ::testing::HasSubstr("\"name\": \"BM_special!@#\""));

// Check JSON structure
std::string json_output = ss.str();
EXPECT_THAT(json_output.front(), testing::Eq('['));
EXPECT_THAT(json_output.back(), testing::Eq(']'))

ss.str("");
RunList(csv_reporter);
EXPECT_THAT(ss.str(), ::testing::HasSubstr("BM_simple"));
EXPECT_THAT(ss.str(), ::testing::HasSubstr("BM_complex"));
EXPECT_THAT(ss.str(), ::testing::HasSubstr("BM_special!@#"));
}

} // namespace internal
} // namespace benchmark

2 comments on commit c08727e

@varshneydevansh
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What am I missing, exactly. I did try to look into this but was missing information on the direction which I took.

@GerHobbelt
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just pulling your edit there into my experimental fork, that's all.

Please sign in to comment.