@@ -1174,6 +1174,16 @@ config BOOTSTAGE_REPORT_JSON
Enable output of the boot time report in JSON format in addition to
the human-readable text format.
+config BOOTSTAGE_REPORT_INFLUXDB
+ bool "Display boot timing report in InfluxDB v2 line protocol"
+ depends on BOOTSTAGE_REPORT
+ help
+ Enable output of the boot time report in InfluxDB v2 line protocol
+ format in addition to the human-readable text format.
+ The report may be uploaded to the InfluxDB Cloud via an HTTPS POST.
+ See https://docs.influxdata.com/influxdb/v2/reference/syntax/line-protocol/
+ and https://docs.influxdata.com/influxdb/v2/write-data/developer-tools/api/.
+
config BOOTSTAGE_RECORD_COUNT
int "Number of boot stage records to store"
depends on BOOTSTAGE
@@ -497,6 +497,137 @@ static void bootstage_report_json(void)
puts("=== End JSON bootstage report ===\n");
}
+/**
+ * puts_influxdb_escape() - Print a string, escaping the characters that have a
+ * special meaning in the InfluxDB v2 line protocol
+ *
+ * @str: the string to print
+ */
+static void puts_influxdb_escape(const char *str)
+{
+ const char *p = str;
+
+ while (p && *p) {
+ if (*p == ' ' || *p == ',' || *p == '=')
+ putc('\\');
+ putc(*p);
+ p++;
+ }
+}
+
+/**
+ * print_time_record_influxdb() - print a time entry in InfluxDB v2 line
+ * protocolformat for a bootstage record or a couple of bootstage records.
+ *
+ * The function prints [,]key_name=value
+ *
+ * - If @rec->start_us is non-zero, it means @rec holds accumulated time. In
+ * this case, key_name is the unique record name and value is @rec->time_us.
+ * - Otherwise, @rec represents a boot stage with an associated timestamp. The
+ * key name is obtained by concatenating the previous record name and the
+ * current record name, separated by a tilda. The value is the elapsed time
+ * between the two stages, that is: @rec->time_us - @prev->time_us.
+ *
+ * @rec: the record to print
+ * @prev: the previous timestamp record (used as a reference when @rec is a
+ * timestamp)
+ * @is_first: true if this is the first reported data (won't print a
+ * continuation comma first ',')
+ * Returns @rec if it is a timestamp, @prev otherwise
+ */
+static struct bootstage_record *
+print_time_record_influxdb(struct bootstage_record *rec,
+ struct bootstage_record *prev, bool is_first)
+{
+ char buf1[24];
+ char buf2[24];
+
+ if (!is_first)
+ puts(",");
+ if (rec->start_us) {
+ /* An "Accumulated time" entry in the text report */
+ printf("%s=%lu",
+ get_unique_record_name(buf1, sizeof(buf1), rec),
+ rec->time_us);
+ return prev;
+ }
+
+ /* Elapsed time between two consecutive stages */
+ printf("%s~%s=%lu",
+ get_unique_record_name(buf1, sizeof(buf1), prev),
+ get_unique_record_name(buf2, sizeof(buf2), rec),
+ rec->time_us - prev->time_us);
+
+ return rec;
+}
+
+/**
+ * print_env_influxdb() - print an environment variable in InfluxDB v2 line
+ * protocol format
+ *
+ * @env: the variable to print
+ * @cont: true if a continuation comma ', ' should be printed afterwards
+ */
+static void print_env_influxdb(const char *env, bool cont)
+{
+ char *val = env_get(env);
+
+ puts("env_");
+ puts(env);
+ puts("=\"");
+ if (val)
+ puts_influxdb_escape(val);
+ puts("\"");
+ if (cont)
+ puts(",");
+}
+
+/**
+ * bootstage_report_influxdb() - print the InfluxDB bootstage report
+ */
+static void bootstage_report_influxdb(void)
+{
+ struct bootstage_data *data = gd->bootstage;
+ struct bootstage_record *prev = data->record;
+ struct bootstage_record *rec = data->record;
+ struct bootstage_record *boot_end = NULL;
+ bool is_first = true;
+ int i;
+
+ puts("=== Begin InfluxDB v2 bootstage report ===\n");
+ puts("u-boot_bootstage_report,");
+ puts("u_boot_version=\"");
+ puts_influxdb_escape(PLAIN_VERSION);
+ puts("\",");
+ puts("u_boot_date=\"");
+ puts_influxdb_escape(U_BOOT_DATE);
+ puts("\",");
+ puts("u_boot_time=\"");
+ puts_influxdb_escape(U_BOOT_TIME);
+ puts("\",");
+ puts("u_boot_tz=\"");
+ puts_influxdb_escape(U_BOOT_TZ);
+ puts("\",");
+ print_env_influxdb("arch", 1);
+ print_env_influxdb("board", 1);
+ print_env_influxdb("board_name", 1);
+ print_env_influxdb("cpu", 1);
+ print_env_influxdb("vendor", 0);
+ puts(" ");
+ for (i = 1, rec++; i < data->rec_count; i++, rec++) {
+ if (rec->id) {
+ if (!rec->start_us)
+ boot_end = rec;
+ prev = print_time_record_influxdb(rec, prev, is_first);
+ is_first = false;
+ }
+ }
+ if (boot_end)
+ printf(",total=%ld", boot_end->time_us);
+ puts("\n");
+ puts("=== End InfluxDB v2 bootstage report ===\n");
+}
+
/**
* bootstage_report() - print the bootstage report(s)
*/
@@ -505,6 +636,8 @@ void bootstage_report(void)
bootstage_report_text();
if (CONFIG_IS_ENABLED(BOOTSTAGE_REPORT_JSON))
bootstage_report_json();
+ if (CONFIG_IS_ENABLED(BOOTSTAGE_REPORT_INFLUXDB))
+ bootstage_report_influxdb();
}
/**
Add a new Kconfig symbol: BOOTSTAGE_REPORT_INFLUXDB to report the bootstage timing information in InfluxDB v2 line protocol format in addition to the human-readable text format. InfluxDB provides an easy way to record boot statistics during CI in order to detect performance regressions. [1] https://docs.influxdata.com/influxdb/v2/reference/syntax/line-protocol/ Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org> --- boot/Kconfig | 10 ++++ common/bootstage.c | 133 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+)