Skip to content

Commit

Permalink
hashtest: add time target argument for test runner
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 674035291
  • Loading branch information
ncbray authored and copybara-github committed Sep 12, 2024
1 parent c93822d commit d2cafe1
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 5 deletions.
19 changes: 15 additions & 4 deletions fuzzer/hashtest/hashtest_runner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ void ResultReporter::CheckIn() {
std::cout << hits.size() << " hits" << "\n";
next_update = now + update_period;
}
if (now >= testing_deadline) {
SetShouldHalt();
}
}

void ResultReporter::ReportHit(int cpu, size_t test_index, const Test& test,
Expand Down Expand Up @@ -254,7 +257,7 @@ void RunTest(size_t test_index, const Test& test, const TestConfig& config,
}
}

void RunBatch(absl::Span<const Test> tests, absl::Span<const Input> inputs,
bool RunBatch(absl::Span<const Test> tests, absl::Span<const Input> inputs,
absl::Span<const EndState> end_states, const RunConfig& config,
size_t test_offset, ThreadStats& stats, ResultReporter& result) {
// Repeat the batch.
Expand All @@ -280,19 +283,27 @@ void RunBatch(absl::Span<const Test> tests, absl::Span<const Input> inputs,
if (stats.num_run % 100000 == 0) {
result.CheckIn();
}
if (result.ShouldHalt()) {
return false;
}
}
}
}
return true;
}

void RunTests(absl::Span<const Test> tests, absl::Span<const Input> inputs,
absl::Span<const EndState> end_states, const RunConfig& config,
size_t test_offset, ThreadStats& stats, ResultReporter& result) {
for (size_t g = 0; g < tests.size(); g += config.batch_size) {
size_t batch_size = std::min(config.batch_size, tests.size() - g);
RunBatch(tests.subspan(g, batch_size), inputs,
end_states.subspan(g * inputs.size(), batch_size * inputs.size()),
config, test_offset + g, stats, result);
bool keep_running = RunBatch(
tests.subspan(g, batch_size), inputs,
end_states.subspan(g * inputs.size(), batch_size * inputs.size()),
config, test_offset + g, stats, result);
if (!keep_running) {
return;
}
}
}

Expand Down
20 changes: 19 additions & 1 deletion fuzzer/hashtest/hashtest_runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#ifndef THIRD_PARTY_SILIFUZZ_FUZZER_HASHTEST_HASHTEST_RUNNER_H_
#define THIRD_PARTY_SILIFUZZ_FUZZER_HASHTEST_HASHTEST_RUNNER_H_

#include <atomic>
#include <cstddef>
#include <cstdint>
#include <random>
Expand Down Expand Up @@ -206,14 +207,24 @@ struct Hit {
struct ResultReporter {
ResultReporter(absl::Duration update_period = absl::Seconds(10))
: update_period(update_period),
next_update(absl::Now() + update_period) {}
next_update(absl::Now() + update_period),
testing_deadline(absl::InfiniteFuture()),
should_halt(false) {}
// Called periodically to produce a heartbeat.
void CheckIn();

// Called for every hit.
void ReportHit(int cpu, size_t test_index, const Test& test,
size_t input_index, const Input& input);

inline void SetShouldHalt() {
return should_halt.store(true, std::memory_order_relaxed);
}

inline bool ShouldHalt() const {
return should_halt.load(std::memory_order_relaxed);
}

// It's usually much more compact to collect each hit rather than keep
// per-test statistics. We can always recreate those statistics later from the
// hits.
Expand All @@ -222,6 +233,13 @@ struct ResultReporter {
absl::Mutex mutex;
absl::Duration update_period;
absl::Time next_update;

// The time at which we should interrupt testing and exit.
absl::Time testing_deadline;

// A flag that indicates if we should stop running tests.
// TODO(ncbray): ensure this value is on a relatively immutable cache line.
std::atomic<bool> should_halt;
};

struct ThreadStats {
Expand Down
1 change: 1 addition & 0 deletions fuzzer/hashtest/hashtest_runner_integration_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ RUNNER="${TEST_SRCDIR}/silifuzz/fuzzer/hashtest/hashtest_runner"
readonly RUNNER

${RUNNER} --seed 123 --tests 10000 --inputs 5 --repeat 5
${RUNNER} --seed 123 --tests 10000 --inputs 5 --repeat 5 --time 1s

echo "PASS"
16 changes: 16 additions & 0 deletions fuzzer/hashtest/hashtest_runner_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <limits>
#include <optional>
#include <random>
#include <vector>
Expand Down Expand Up @@ -52,6 +53,9 @@ ABSL_FLAG(size_t, iterations, 100,
"Number of internal iterations for each test.");
ABSL_FLAG(std::optional<uint64_t>, seed, std::nullopt,
"Fixed seed to use for random number generation.");
ABSL_FLAG(std::optional<absl::Duration>, time, std::nullopt,
"Time limit for testing. For example: 1m30s. If specified, will "
"generate and test corpora until the time limit is hit.");

ABSL_FLAG(bool, verbose, false, "Print additional debugging information.");

Expand Down Expand Up @@ -185,6 +189,8 @@ std::vector<EndState> DetermineEndStates(ParallelWorkerPool& workers,
}

int TestMain(std::vector<char*> positional_args) {
absl::Time test_started = absl::Now();

InitXedIfNeeded();

std::cout << "Version: " << kHashTestVersionMajor << "."
Expand Down Expand Up @@ -265,6 +271,12 @@ int TestMain(std::vector<char*> positional_args) {

ResultReporter result;

std::optional<absl::Duration> maybe_time = absl::GetFlag(FLAGS_time);
if (maybe_time.has_value()) {
result.testing_deadline = test_started + maybe_time.value();
num_corpora = std::numeric_limits<typeof(num_corpora)>::max();
}

std::vector<ThreadStats> stats(workers.NumWorkers());
for (size_t c = 0; c < num_corpora; ++c) {
RunConfig config = {
Expand Down Expand Up @@ -349,6 +361,10 @@ int TestMain(std::vector<char*> positional_args) {
});
test_time += absl::Now() - begin;
tests_run += corpus.tests.size();

if (result.ShouldHalt()) {
break;
}
}

// Aggregate thread stats.
Expand Down

0 comments on commit d2cafe1

Please sign in to comment.