#Centipede Fuzzing stats: fix bogus initial timestamps + improve logging
- The stats dumping code used to dump timestamps averaged between the fuzzing threads: with slow targets, dumping sometimes occurred before all the threads got a chance to update their stats, resulting in bogus timestamps. Switched to dumping the timestamp min/max, which seems more useful anyway.
- Also, log timestamps as human-readable formatted times, not UNIX micros.
- Also turned off dumping of the individual timestamp values to LOG: dubious value & log pollution.
PiperOrigin-RevId: 554887117
diff --git a/centipede/BUILD b/centipede/BUILD
index 2fb45e4..c2d39b6 100644
--- a/centipede/BUILD
+++ b/centipede/BUILD
@@ -240,6 +240,7 @@
"@com_google_absl//absl/log:check",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
+ "@com_google_absl//absl/time",
"@com_google_absl//absl/types:span",
],
)
@@ -976,6 +977,7 @@
":util",
"@com_google_absl//absl/log:log_sink",
"@com_google_absl//absl/log:log_sink_registry",
+ "@com_google_absl//absl/time",
"@com_google_googletest//:gtest_main",
],
)
diff --git a/centipede/stats.cc b/centipede/stats.cc
index 713aef3..b3217a0 100644
--- a/centipede/stats.cc
+++ b/centipede/stats.cc
@@ -25,6 +25,7 @@
#include "absl/log/check.h"
#include "absl/strings/str_format.h"
#include "absl/strings/substitute.h"
+#include "absl/time/time.h"
#include "absl/types/span.h"
#include "./centipede/environment.h"
#include "./centipede/logging.h"
@@ -85,6 +86,14 @@
curr_field_info_ = field_info;
}
+namespace {
+std::string FormatTimestamp(uint64_t unix_micros) {
+ return absl::FormatTime("%Y-%m-%d%ET%H:%M:%S",
+ absl::FromUnixMicros(unix_micros),
+ absl::LocalTimeZone());
+}
+} // namespace
+
void StatsLogger::ReportCurrFieldSample(std::vector<uint64_t> &&values) {
// Print min/max/avg and the full sorted contents of `values`.
std::sort(values.begin(), values.end());
@@ -94,18 +103,19 @@
static_cast<double>(values.size());
os_ << std::fixed << std::setprecision(1);
switch (curr_field_info_.aggregation) {
- case Stats::Aggregation::kMinMaxAvg:
+ case Stats::Aggregation::kMinMaxAvg: {
os_ << "min:\t" << min << "\t"
<< "max:\t" << max << "\t"
<< "avg:\t" << avg << "\t";
- break;
- case Stats::Aggregation::kRoundedAvg:
- os_ << "avg:\t" << std::llrint(avg) << "\t";
- break;
- }
- os_ << "--";
- for (const auto value : values) {
- os_ << "\t" << value;
+ os_ << "--";
+ for (const auto value : values) {
+ os_ << "\t" << value;
+ }
+ } break;
+ case Stats::Aggregation::kMinMax: {
+ os_ << "min:\t" << FormatTimestamp(min) << "\t"
+ << "max:\t" << FormatTimestamp(max);
+ } break;
}
os_ << "\n";
}
@@ -141,8 +151,8 @@
for (const auto &field : fields) {
std::string col_names;
switch (field.aggregation) {
- case Stats::Aggregation::kRoundedAvg:
- col_names = absl::Substitute("$0_Avg,", field.name);
+ case Stats::Aggregation::kMinMax:
+ col_names = absl::Substitute("$0_Min,$0_Max,", field.name);
break;
case Stats::Aggregation::kMinMaxAvg:
col_names = absl::Substitute("$0_Min,$0_Max,$0_Avg,", field.name);
@@ -185,8 +195,8 @@
if (!values.empty()) avg /= values.size();
std::string values_str;
switch (curr_field_info_.aggregation) {
- case Stats::Aggregation::kRoundedAvg:
- values_str = absl::StrFormat("%" PRIu64 ",", std::llrint(avg));
+ case Stats::Aggregation::kMinMax:
+ values_str = absl::StrFormat("%" PRIu64 ",%" PRIu64 ",", min, max);
break;
case Stats::Aggregation::kMinMaxAvg:
values_str =
diff --git a/centipede/stats.h b/centipede/stats.h
index 28c0a10..a42cd83 100644
--- a/centipede/stats.h
+++ b/centipede/stats.h
@@ -45,7 +45,7 @@
std::atomic<uint64_t> max_corpus_element_size;
std::atomic<uint64_t> avg_corpus_element_size;
- enum class Aggregation { kMinMaxAvg, kRoundedAvg };
+ enum class Aggregation { kMinMaxAvg, kMinMax };
struct FieldInfo {
std::atomic<uint64_t> Stats::*field;
@@ -89,7 +89,7 @@
&Stats::unix_micros,
"UnixMicros",
"Timestamp (UNIX micros)",
- Aggregation::kRoundedAvg,
+ Aggregation::kMinMax,
},
};
};
diff --git a/centipede/stats_test.cc b/centipede/stats_test.cc
index eeaa29a..45fa46e 100644
--- a/centipede/stats_test.cc
+++ b/centipede/stats_test.cc
@@ -14,6 +14,7 @@
#include "./centipede/stats.h"
+#include <cstdint>
#include <filesystem> // NOLINT
#include <sstream>
#include <vector>
@@ -22,6 +23,8 @@
#include "gtest/gtest.h"
#include "absl/log/log_sink.h"
#include "absl/log/log_sink_registry.h"
+#include "absl/time/civil_time.h"
+#include "absl/time/time.h"
#include "./centipede/logging.h"
#include "./centipede/test_util.h"
#include "./centipede/util.h"
@@ -43,6 +46,12 @@
std::stringstream captured_log_;
};
+uint64_t CivilTimeToUnixMicros( //
+ int64_t y, int64_t m, int64_t d, int64_t hh, int64_t mm, int64_t ss) {
+ return absl::ToUnixMicros(absl::FromCivil(
+ absl::CivilSecond{y, m, d, hh, mm, ss}, absl::LocalTimeZone()));
+}
+
} // namespace
TEST(Stats, PrintStatsToLog) {
@@ -59,7 +68,7 @@
for (size_t i = 0; i < 4; ++i) {
auto &stats = stats_vec[i];
- stats.unix_micros = i + 1000000;
+ stats.unix_micros = CivilTimeToUnixMicros(1970, 1, 1, 0, 0, i);
stats.max_corpus_element_size = 2 * i + 1;
stats.avg_corpus_element_size = i + 1;
stats.num_executions = i + 100;
@@ -93,8 +102,8 @@
"Experiment A: min:\t1\tmax:\t3\tavg:\t2.0\t--\t1\t3\n"
"Experiment B: min:\t2\tmax:\t4\tavg:\t3.0\t--\t2\t4\n"
"Timestamp (UNIX micros):\n"
- "Experiment A: avg:\t1000001\t--\t1000000\t1000002\n"
- "Experiment B: avg:\t1000002\t--\t1000001\t1000003\n"
+ "Experiment A: min:\t1970-01-01T00:00:00\tmax:\t1970-01-01T00:00:02\n"
+ "Experiment B: min:\t1970-01-01T00:00:01\tmax:\t1970-01-01T00:00:03\n"
"Flags:\n"
"Experiment A: AAA\n"
"Experiment B: BBB\n";
@@ -160,13 +169,13 @@
workdir / "fuzzing-stats-.000000.ExperimentB.csv",
};
const std::vector<std::string_view> kExpectedCsvContents = {
- R"(NumCoveredPcs_Min,NumCoveredPcs_Max,NumCoveredPcs_Avg,NumExecs_Min,NumExecs_Max,NumExecs_Avg,CorpusSize_Min,CorpusSize_Max,CorpusSize_Avg,MaxEltSize_Min,MaxEltSize_Max,MaxEltSize_Avg,AvgEltSize_Min,AvgEltSize_Max,AvgEltSize_Avg,UnixMicros_Avg,
-10,25,17.5,100,102,101.0,1000,3000,2000.0,1,5,3.0,1,3,2.0,1000001,
-11,26,18.5,101,103,102.0,1001,3001,2001.0,2,6,4.0,2,4,3.0,1000002,
+ R"(NumCoveredPcs_Min,NumCoveredPcs_Max,NumCoveredPcs_Avg,NumExecs_Min,NumExecs_Max,NumExecs_Avg,CorpusSize_Min,CorpusSize_Max,CorpusSize_Avg,MaxEltSize_Min,MaxEltSize_Max,MaxEltSize_Avg,AvgEltSize_Min,AvgEltSize_Max,AvgEltSize_Avg,UnixMicros_Min,UnixMicros_Max,
+10,25,17.5,100,102,101.0,1000,3000,2000.0,1,5,3.0,1,3,2.0,1000000,1000002,
+11,26,18.5,101,103,102.0,1001,3001,2001.0,2,6,4.0,2,4,3.0,1000001,1000003,
)",
- R"(NumCoveredPcs_Min,NumCoveredPcs_Max,NumCoveredPcs_Avg,NumExecs_Min,NumExecs_Max,NumExecs_Avg,CorpusSize_Min,CorpusSize_Max,CorpusSize_Avg,MaxEltSize_Min,MaxEltSize_Max,MaxEltSize_Avg,AvgEltSize_Min,AvgEltSize_Max,AvgEltSize_Avg,UnixMicros_Avg,
-15,40,27.5,101,103,102.0,2000,4000,3000.0,3,7,5.0,2,4,3.0,1000002,
-16,41,28.5,102,104,103.0,2001,4001,3001.0,4,8,6.0,3,5,4.0,1000003,
+ R"(NumCoveredPcs_Min,NumCoveredPcs_Max,NumCoveredPcs_Avg,NumExecs_Min,NumExecs_Max,NumExecs_Avg,CorpusSize_Min,CorpusSize_Max,CorpusSize_Avg,MaxEltSize_Min,MaxEltSize_Max,MaxEltSize_Avg,AvgEltSize_Min,AvgEltSize_Max,AvgEltSize_Avg,UnixMicros_Min,UnixMicros_Max,
+15,40,27.5,101,103,102.0,2000,4000,3000.0,3,7,5.0,2,4,3.0,1000001,1000003,
+16,41,28.5,102,104,103.0,2001,4001,3001.0,4,8,6.0,3,5,4.0,1000002,1000004,
)",
};