trace_processor: print non-zero error stats and stop counter events from log spam
While the stats table is very important for putting data that we consider
important context to trace analysis, often people can overlook looking at
it until after some significant investigation has been done. This can lead
to frustration that these stats were not surfaced earlier.
Change this by querying stats at the end of importing the trace in trace
processor shell and printing it out to stderr. This allows users to see if their
trace is busted/trace processor has a bug before they get into proper analysis.
And since we have stats for this now and print them in shell,
turn the ELOG into a DLOG for counter out of order
to avoid log spam if this does happen.
Bug: 126443808
Change-Id: I2cdb7e2710242d044c78f729c004ab93c38fcc90
diff --git a/src/trace_processor/trace_processor_shell.cc b/src/trace_processor/trace_processor_shell.cc
index 3d4e84a..2e3d5c9 100644
--- a/src/trace_processor/trace_processor_shell.cc
+++ b/src/trace_processor/trace_processor_shell.cc
@@ -141,6 +141,56 @@
#endif
+bool PrintStats() {
+ auto it = g_tp->ExecuteQuery(
+ "SELECT name, idx, source, value from stats "
+ "where severity = 'error' and value > 0");
+
+ bool first = true;
+ for (uint32_t rows = 0; it.Next(); rows++) {
+ if (first) {
+ fprintf(stderr, "Error stats for this trace:\n");
+
+ for (uint32_t i = 0; i < it.ColumnCount(); i++)
+ fprintf(stderr, "%40s ", it.GetColumName(i).c_str());
+ fprintf(stderr, "\n");
+
+ for (uint32_t i = 0; i < it.ColumnCount(); i++)
+ fprintf(stderr, "%40s ", "----------------------------------------");
+ fprintf(stderr, "\n");
+
+ first = false;
+ }
+
+ for (uint32_t c = 0; c < it.ColumnCount(); c++) {
+ auto value = it.Get(c);
+ switch (value.type) {
+ case SqlValue::Type::kNull:
+ fprintf(stderr, "%-40.40s", "[NULL]");
+ break;
+ case SqlValue::Type::kDouble:
+ fprintf(stderr, "%40f", value.double_value);
+ break;
+ case SqlValue::Type::kLong:
+ fprintf(stderr, "%40" PRIi64, value.long_value);
+ break;
+ case SqlValue::Type::kString:
+ fprintf(stderr, "%-40.40s", value.string_value);
+ break;
+ }
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "\n");
+ }
+
+ auto opt_error = it.GetLastError();
+ if (PERFETTO_UNLIKELY(opt_error.has_value())) {
+ PERFETTO_ELOG("Error while iterating stats %s", opt_error->c_str());
+ return false;
+ }
+ return true;
+}
+
int ExportTraceToDatabase(const std::string& output_name) {
PERFETTO_CHECK(output_name.find("'") == std::string::npos);
{
@@ -564,6 +614,11 @@
signal(SIGINT, [](int) { g_tp->InterruptQuery(); });
#endif
+ // Print out the stats to stderr for the trace.
+ if (!PrintStats()) {
+ return 1;
+ }
+
// First, see if we have some metrics to run. If we do, just run them and
// return.
if (metric_names) {