Skip to content

Commit

Permalink
fuzzer sample gen: optionally create valid holdoffs.
Browse files Browse the repository at this point in the history
If --with_avild_holdoff is set to true and we simulate the
verilog, that Verilog testbench is fed the valid holdoffs
generated by the generator.

The additional holdoff infomration is stored in the
testvector protocol buffer: switch to Sample() constructor
that takes that proto.

PiperOrigin-RevId: 700433878
  • Loading branch information
hzeller authored and copybara-github committed Nov 26, 2024
1 parent 021df56 commit b3e17bb
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 10 deletions.
1 change: 1 addition & 0 deletions xls/fuzzer/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,7 @@ cc_library(
"//xls/dslx/type_system:type",
"//xls/dslx/type_system:type_info",
"//xls/dslx/type_system:unwrap_meta_type",
"//xls/ir:format_preference",
"@com_google_absl//absl/log",
"@com_google_absl//absl/log:check",
"@com_google_absl//absl/random:bit_gen_ref",
Expand Down
4 changes: 4 additions & 0 deletions xls/fuzzer/fuzz_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ ABSL_FLAG(
std::optional<absl::Duration>, sample_timeout, std::nullopt,
"Maximum time to run each sample before timing out. Examples: 10s, 2m, 1h");
ABSL_FLAG(bool, generate_proc, false, "Generate a proc sample.");
ABSL_FLAG(bool, with_valid_holdoff, false,
"If true, emit valid random holdoffs on proc input channels.");

// The maximum number of failures before the test aborts.
constexpr int64_t kMaxFailures = 10;
Expand Down Expand Up @@ -133,6 +135,8 @@ TEST(FuzzIntegrationTest, Fuzzing) {
sample_options.set_timeout_seconds(
absl::ToInt64Seconds(*absl::GetFlag(FLAGS_sample_timeout)));
}
sample_options.set_with_valid_holdoff(
absl::GetFlag(FLAGS_with_valid_holdoff));

int64_t crasher_count = 0;
int64_t sample_count = 0;
Expand Down
5 changes: 5 additions & 0 deletions xls/fuzzer/run_fuzz_multiprocess_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ ABSL_FLAG(
ABSL_FLAG(std::optional<int64_t>, worker_count, std::nullopt,
"Number of workers to use for execution; defaults to number of "
"physical cores detected.");
ABSL_FLAG(bool, with_valid_holdoff, false,
"If true, emit valid random holdoffs on proc input channels.");

namespace xls {
namespace {
Expand All @@ -108,6 +110,7 @@ struct Options {
bool use_llvm_jit;
bool use_system_verilog;
std::optional<int64_t> worker_count;
bool with_valid_holdoff;
};

absl::Status CheckOrCreateWritableDirectory(const std::filesystem::path& path) {
Expand Down Expand Up @@ -168,6 +171,7 @@ absl::Status RealMain(const Options& options) {
}
sample_options.set_use_jit(options.use_llvm_jit);
sample_options.set_use_system_verilog(options.use_system_verilog);
sample_options.set_with_valid_holdoff(options.with_valid_holdoff);

return ParallelGenerateAndRunSamples(
worker_count, ast_generator_options, sample_options, options.seed,
Expand Down Expand Up @@ -216,5 +220,6 @@ int main(int argc, char** argv) {
.use_llvm_jit = absl::GetFlag(FLAGS_use_llvm_jit),
.use_system_verilog = absl::GetFlag(FLAGS_use_system_verilog),
.worker_count = absl::GetFlag(FLAGS_worker_count),
.with_valid_holdoff = absl::GetFlag(FLAGS_with_valid_holdoff),
}));
}
5 changes: 5 additions & 0 deletions xls/fuzzer/sample.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ class SampleOptions {
bool simulate() const { return proto_.simulate(); }
void set_simulate(bool value) { proto_.set_simulate(value); }

bool with_valid_holdoff() const { return proto_.with_valid_holdoff(); }
void set_with_valid_holdoff(bool value) {
proto_.set_with_valid_holdoff(value);
}

const std::string& simulator() const { return proto_.simulator(); }
void set_simulator(std::string_view value) {
proto_.set_simulator(ToProtoString(value));
Expand Down
3 changes: 3 additions & 0 deletions xls/fuzzer/sample.proto
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ message SampleOptionsProto {
// Number ticks to execute the generated proc. Only meaningful for procs.
optional int64 proc_ticks = 14;

// Inputs are spaced out with valid holdoffs
optional bool with_valid_holdoff = 16;

// Regex of error messages which are known to be domain-errors in fuzzing.
//
// Any crasher which has a match the regular-expressions in the correct tool
Expand Down
59 changes: 49 additions & 10 deletions xls/fuzzer/sample_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/types/span.h"
#include "xls/common/logging/log_lines.h"
#include "xls/common/status/ret_check.h"
Expand All @@ -57,6 +58,7 @@
#include "xls/fuzzer/sample.h"
#include "xls/fuzzer/sample.pb.h"
#include "xls/fuzzer/value_generator.h"
#include "xls/ir/format_preference.h"

namespace xls {
namespace {
Expand Down Expand Up @@ -302,6 +304,20 @@ static std::vector<std::string> GetInputChannelNamesOfProc(dslx::Proc* proc) {
return channel_names;
}

// Convert InterpValue to value used in SampleInputsProto
std::string ToArgString(const InterpValue& v) {
return v.ConvertToIr().value().ToString(FormatPreference::kHex);
}

// Converts a list of interpreter values to a string as needed in SampleInputs
std::string InterpValueListToString(
const std::vector<InterpValue>& interpv_list) {
return absl::StrJoin(interpv_list, "; ",
[](std::string* out, const InterpValue& v) {
absl::StrAppend(out, ToArgString(v));
});
}

static absl::StatusOr<Sample> GenerateFunctionSample(
dslx::Function* function, const TypecheckedModule& tm,
const SampleOptions& sample_options, absl::BitGenRef bit_gen,
Expand All @@ -310,14 +326,16 @@ static absl::StatusOr<Sample> GenerateFunctionSample(
GetParamTypesOfFunction(function, tm));
std::vector<const dslx::Type*> params = TranslateTypeList(top_params);

std::vector<std::vector<InterpValue>> args_batch;
testvector::SampleInputsProto testvector;
testvector::FunctionArgsProto* fun_args = testvector.mutable_function_args();

for (int64_t i = 0; i < sample_options.calls_per_sample(); ++i) {
XLS_ASSIGN_OR_RETURN(std::vector<InterpValue> args,
GenerateInterpValues(bit_gen, params));
args_batch.push_back(std::move(args));
fun_args->add_args(InterpValueListToString(args));
}

return Sample(dslx_text, sample_options, std::move(args_batch));
return Sample(dslx_text, sample_options, testvector);
}

static absl::StatusOr<Sample> GenerateProcSample(
Expand All @@ -330,6 +348,9 @@ static absl::StatusOr<Sample> GenerateProcSample(
std::vector<const dslx::Type*> input_channel_payload_types_ptr =
TranslateTypeList(input_channel_payload_types);

// Create number of values needed for the proc_ticks.
// Actual proc-tics the execution needs might be longer depending on
// if it deals with holdoff values.
std::vector<std::vector<InterpValue>> channel_values_batch;
for (int64_t i = 0; i < sample_options.proc_ticks(); ++i) {
XLS_ASSIGN_OR_RETURN(
Expand All @@ -338,16 +359,34 @@ static absl::StatusOr<Sample> GenerateProcSample(
channel_values_batch.push_back(std::move(channel_values));
}

std::vector<std::string> input_channel_names =
const std::vector<std::string> input_channel_names =
GetInputChannelNamesOfProc(proc);
std::vector<std::string> ir_channel_names(input_channel_names.size());
for (int64_t index = 0; index < input_channel_names.size(); ++index) {
ir_channel_names[index] =
absl::StrCat(proc->owner()->name(), "__", input_channel_names[index]);

const int64_t holdoff_range = sample_options.proc_ticks() / 10;
testvector::SampleInputsProto testvector;
testvector::ChannelInputsProto* inputs_proto =
testvector.mutable_channel_inputs();
using testvector::ValidHoldoff;

// Create data per channel. Each channel gets data with randomized
// valid-holdoff prepended if requested.
for (int64_t ch_idx = 0; ch_idx < input_channel_names.size(); ++ch_idx) {
testvector::ChannelInputProto* channel_input = inputs_proto->add_inputs();
channel_input->set_channel_name(
absl::StrCat(proc->owner()->name(), "__", input_channel_names[ch_idx]));
for (int64_t i = 0; i < sample_options.proc_ticks(); ++i) {
if (sample_options.with_valid_holdoff()) {
int64_t holdoff = absl::Uniform<int64_t>(bit_gen, 0, holdoff_range);
ValidHoldoff* holdoff_data = channel_input->add_valid_holdoffs();
holdoff_data->set_cycles(holdoff);
}

const std::vector<InterpValue>& args = channel_values_batch[i];
channel_input->add_values(ToArgString(args[ch_idx]));
}
}

return Sample(dslx_text, sample_options, std::move(channel_values_batch),
std::move(ir_channel_names));
return Sample(dslx_text, sample_options, testvector);
}

absl::StatusOr<Sample> GenerateSample(
Expand Down

0 comments on commit b3e17bb

Please sign in to comment.