Index: llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp =================================================================== --- llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp +++ llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp @@ -245,6 +245,7 @@ Options.OnlyASCII = Flags.only_ascii; Options.TBMDepth = Flags.tbm_depth; Options.TBMWidth = Flags.tbm_width; + Options.OutputCSV = Flags.output_csv; if (Flags.runs >= 0) Options.MaxNumberOfRuns = Flags.runs; if (!Inputs->empty()) Index: llvm/trunk/lib/Fuzzer/FuzzerFlags.def =================================================================== --- llvm/trunk/lib/Fuzzer/FuzzerFlags.def +++ llvm/trunk/lib/Fuzzer/FuzzerFlags.def @@ -69,3 +69,4 @@ "$(artifact_prefix)file") FUZZER_FLAG_INT(drill, 0, "Experimental: fuzz using a single unit as the seed " "corpus, then merge with the initial corpus") +FUZZER_FLAG_INT(output_csv, 0, "Enable pulse output in CSV format.") Index: llvm/trunk/lib/Fuzzer/FuzzerInternal.h =================================================================== --- llvm/trunk/lib/Fuzzer/FuzzerInternal.h +++ llvm/trunk/lib/Fuzzer/FuzzerInternal.h @@ -96,6 +96,7 @@ std::string ArtifactPrefix = "./"; bool SaveArtifacts = true; bool PrintNEW = true; // Print a status line when new units are found; + bool OutputCSV = false; }; Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options); void AddToCorpus(const Unit &U) { Corpus.push_back(U); } Index: llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp =================================================================== --- llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp +++ llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp @@ -108,9 +108,23 @@ } void Fuzzer::PrintStats(const char *Where, const char *End) { - if (!Options.Verbosity) return; size_t Seconds = secondsSinceProcessStartUp(); size_t ExecPerSec = (Seconds ? TotalNumberOfRuns / Seconds : 0); + + if (Options.OutputCSV) { + static bool csvHeaderPrinted = false; + if (!csvHeaderPrinted) { + csvHeaderPrinted = true; + Printf("runs,block_cov,bits,cc_cov,corpus,execs_per_sec,tbms,reason\n"); + } + Printf("%zd,%zd,%zd,%zd,%zd,%zd,%zd,%s\n", TotalNumberOfRuns, + LastRecordedBlockCoverage, TotalBits(), + LastRecordedCallerCalleeCoverage, Corpus.size(), ExecPerSec, + TotalNumberOfExecutedTraceBasedMutations, Where); + } + + if (!Options.Verbosity) + return; Printf("#%zd\t%s", TotalNumberOfRuns, Where); if (LastRecordedBlockCoverage) Printf(" cov: %zd", LastRecordedBlockCoverage); @@ -144,8 +158,7 @@ CurrentUnit.insert(CurrentUnit.begin(), X.begin(), X.end()); if (RunOne(CurrentUnit)) { Corpus.push_back(X); - if (Options.Verbosity >= 1) - PrintStats("RELOAD"); + PrintStats("RELOAD"); } } } @@ -198,9 +211,8 @@ auto UnitStopTime = system_clock::now(); auto TimeOfUnit = duration_cast(UnitStopTime - UnitStartTime).count(); - if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) - && secondsSinceProcessStartUp() >= 2 - && Options.Verbosity) + if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && + secondsSinceProcessStartUp() >= 2) PrintStats("pulse "); if (TimeOfUnit > TimeOfLongestUnitInSeconds && TimeOfUnit >= Options.ReportSlowUnits) { @@ -452,11 +464,11 @@ SyncCorpus(); RereadOutputCorpus(); if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) - return; + break; if (Options.MaxTotalTimeSec > 0 && secondsSinceProcessStartUp() > static_cast(Options.MaxTotalTimeSec)) - return; + break; CurrentUnit = Corpus[J1]; // Optionally, cross with another unit. if (Options.DoCrossOver && USF.GetRand().RandBool()) { @@ -476,6 +488,8 @@ // Perform several mutations and runs. MutateAndTestOne(&CurrentUnit); } + + PrintStats("DONE ", "\n"); } void Fuzzer::SyncCorpus() {