Jakub Czapiga has uploaded this change for review.

View Change

util/cbmem: Add FlameGraph-compatible timestamps output

Flame graphs are used to visualize hierarchical data, like call stacks.
Timestamps collected by coreboot can be processed to resemble
profiler-like output, and thus can be feed to flame graph generation
tools.

TEST=Run on coreboot-enabled device and extract timestamps using
-t/-T/-S options

Signed-off-by: Jakub Czapiga <jacz@semihalf.com>
Change-Id: I3a4e20a267e9e0fbc6b3a4d6a2409b32ce8fca33
---
M src/commonlib/include/commonlib/timestamp_serialized.h
M util/cbmem/cbmem.c
2 files changed, 367 insertions(+), 27 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/74/62474/1
diff --git a/src/commonlib/include/commonlib/timestamp_serialized.h b/src/commonlib/include/commonlib/timestamp_serialized.h
index 2f592c4..7033c4d 100644
--- a/src/commonlib/include/commonlib/timestamp_serialized.h
+++ b/src/commonlib/include/commonlib/timestamp_serialized.h
@@ -282,7 +282,7 @@
{ TS_ME_END_OF_POST_END, "after sending EOP to ME"},
{ TS_ME_BOOT_STALL_END, "CSE sent 'Boot Stall Done' to PMC"},
{ TS_ME_ICC_CONFIG_START, "CSE started to handle ICC configuration"},
- { TS_ME_HOST_BOOT_PREP_DONE, "CSE sent 'Host BIOS Prep Done' to PMC"},
+ { TS_ME_HOST_BOOT_PREP_END, "CSE sent 'Host BIOS Prep Done' to PMC"},
{ TS_ME_RECEIVED_CRDA_FROM_PMC, "CSE received 'CPU Reset Done Ack sent' from PMC"},
{ TS_CSE_FW_SYNC_START, "starting CSE firmware sync"},
{ TS_CSE_FW_SYNC_END, "finished CSE firmware sync"},
@@ -313,4 +313,202 @@
{ TS_POSTCAR_END, "end of postcar" },
};

+static const struct timestamp_id_to_enum_name {
+ uint32_t id;
+ const char *name;
+} timestamp_enum_ids[] = {
+ { 0, "TS_START"},
+ { TS_ROMSTAGE_START, "TS_ROMSTAGE_START" },
+ { TS_INITRAM_START, "TS_INITRAM_START" },
+ { TS_INITRAM_END, "TS_INITRAM_END" },
+ { TS_ROMSTAGE_END, "TS_ROMSTAGE_END" },
+ { TS_VBOOT_START, "TS_VBOOT_START" },
+ { TS_VBOOT_END, "TS_VBOOT_END" },
+ { TS_COPYRAM_START, "TS_COPYRAM_START" },
+ { TS_COPYRAM_END, "TS_COPYRAM_END" },
+ { TS_RAMSTAGE_START, "TS_RAMSTAGE_START" },
+ { TS_BOOTBLOCK_START, "TS_BOOTBLOCK_START" },
+ { TS_BOOTBLOCK_END, "TS_BOOTBLOCK_END" },
+ { TS_COPYROM_START, "TS_COPYROM_START" },
+ { TS_COPYROM_END, "TS_COPYROM_END" },
+ { TS_ULZMA_START, "TS_ULZMA_START" },
+ { TS_ULZMA_END, "TS_ULZMA_END" },
+ { TS_ULZ4F_START, "TS_ULZ4F_START" },
+ { TS_ULZ4F_END, "TS_ULZ4F_END" },
+ { TS_DEVICE_ENUMERATE, "TS_DEVICE_ENUMERATE" },
+ { TS_DEVICE_CONFIGURE, "TS_DEVICE_CONFIGURE" },
+ { TS_DEVICE_ENABLE, "TS_DEVICE_ENABLE" },
+ { TS_DEVICE_INITIALIZE, "TS_DEVICE_INITIALIZE" },
+ { TS_OPROM_INITIALIZE, "TS_OPROM_INITIALIZE" },
+ { TS_OPROM_COPY_END, "TS_OPROM_COPY_END" },
+ { TS_OPROM_END, "TS_OPROM_END" },
+ { TS_DEVICE_DONE, "TS_DEVICE_DONE" },
+ { TS_CBMEM_POST, "TS_CBMEM_POST" },
+ { TS_WRITE_TABLES, "TS_WRITE_TABLES" },
+ { TS_FINALIZE_CHIPS, "TS_FINALIZE_CHIPS" },
+ { TS_LOAD_PAYLOAD, "TS_LOAD_PAYLOAD" },
+ { TS_ACPI_WAKE_JUMP, "TS_ACPI_WAKE_JUMP" },
+ { TS_SELFBOOT_JUMP, "TS_SELFBOOT_JUMP" },
+ { TS_POSTCAR_START, "TS_POSTCAR_START" },
+ { TS_POSTCAR_END, "TS_POSTCAR_END" },
+ { TS_DELAY_START, "TS_DELAY_START" },
+ { TS_DELAY_END, "TS_DELAY_END" },
+ { TS_READ_UCODE_START, "TS_READ_UCODE_START" },
+ { TS_READ_UCODE_END, "TS_READ_UCODE_END" },
+ { TS_ELOG_INIT_START, "TS_ELOG_INIT_START" },
+ { TS_ELOG_INIT_END, "TS_ELOG_INIT_END" },
+ { TS_COPYVER_START, "TS_COPYVER_START" },
+ { TS_COPYVER_END, "TS_COPYVER_END" },
+ { TS_TPMINIT_START, "TS_TPMINIT_START" },
+ { TS_TPMINIT_END, "TS_TPMINIT_END" },
+ { TS_VERIFY_SLOT_START, "TS_VERIFY_SLOT_START" },
+ { TS_VERIFY_SLOT_END, "TS_VERIFY_SLOT_END" },
+ { TS_HASH_BODY_START, "TS_HASH_BODY_START" },
+ { TS_LOADING_END, "TS_LOADING_END" },
+ { TS_HASHING_END, "TS_HASHING_END" },
+ { TS_HASH_BODY_END, "TS_HASH_BODY_END" },
+ { TS_TPMPCR_START, "TS_TPMPCR_START" },
+ { TS_TPMPCR_END, "TS_TPMPCR_END" },
+ { TS_TPMLOCK_START, "TS_TPMLOCK_START" },
+ { TS_TPMLOCK_END, "TS_TPMLOCK_END" },
+ { TS_EC_SYNC_START, "TS_EC_SYNC_START" },
+ { TS_EC_HASH_READY, "TS_EC_HASH_READY" },
+ { TS_EC_POWER_LIMIT_WAIT, "TS_EC_POWER_LIMIT_WAIT" },
+ { TS_EC_SYNC_END, "TS_EC_SYNC_END" },
+ { TS_COPYVPD_START, "TS_COPYVPD_START" },
+ { TS_COPYVPD_RO_END, "TS_COPYVPD_RO_END" },
+ { TS_COPYVPD_RW_END, "TS_COPYVPD_RW_END" },
+ { TS_TPM_ENABLE_UPDATE_START, "TS_TPM_ENABLE_UPDATE_START" },
+ { TS_TPM_ENABLE_UPDATE_END, "TS_TPM_ENABLE_UPDATE_END" },
+ { TS_AGESA_INIT_RESET_START, "TS_AGESA_INIT_RESET_START" },
+ { TS_AGESA_INIT_RESET_END, "TS_AGESA_INIT_RESET_END" },
+ { TS_AGESA_INIT_EARLY_START, "TS_AGESA_INIT_EARLY_START" },
+ { TS_AGESA_INIT_EARLY_END, "TS_AGESA_INIT_EARLY_END" },
+ { TS_AGESA_INIT_POST_START, "TS_AGESA_INIT_POST_START" },
+ { TS_AGESA_INIT_POST_END, "TS_AGESA_INIT_POST_END" },
+ { TS_AGESA_INIT_ENV_START, "TS_AGESA_INIT_ENV_START" },
+ { TS_AGESA_INIT_ENV_END, "TS_AGESA_INIT_ENV_END" },
+ { TS_AGESA_INIT_MID_START, "TS_AGESA_INIT_MID_START" },
+ { TS_AGESA_INIT_MID_END, "TS_AGESA_INIT_MID_END" },
+ { TS_AGESA_INIT_LATE_START, "TS_AGESA_INIT_LATE_START" },
+ { TS_AGESA_INIT_LATE_END, "TS_AGESA_INIT_LATE_END" },
+ { TS_AGESA_INIT_RTB_START, "TS_AGESA_INIT_RTB_START" },
+ { TS_AGESA_INIT_RTB_END, "TS_AGESA_INIT_RTB_END" },
+ { TS_AGESA_INIT_RESUME_START, "TS_AGESA_INIT_RESUME_START" },
+ { TS_AGESA_INIT_RESUME_END, "TS_AGESA_INIT_RESUME_END" },
+ { TS_AGESA_S3_LATE_START, "TS_AGESA_S3_LATE_START" },
+ { TS_AGESA_S3_LATE_END, "TS_AGESA_S3_LATE_END" },
+ { TS_AGESA_S3_FINAL_START, "TS_AGESA_S3_FINAL_START" },
+ { TS_AGESA_S3_FINAL_END, "TS_AGESA_S3_FINAL_END" },
+ { TS_AMD_APOB_READ_START, "TS_AMD_APOB_READ_START" },
+ { TS_AMD_APOB_ERASE_START, "TS_AMD_APOB_ERASE_START" },
+ { TS_AMD_APOB_WRITE_START, "TS_AMD_APOB_WRITE_START" },
+ { TS_AMD_APOB_END, "TS_AMD_APOB_END" },
+ { TS_ME_INFORM_DRAM_START, "TS_ME_INFORM_DRAM_START" },
+ { TS_ME_INFORM_DRAM_END, "TS_ME_INFORM_DRAM_END" },
+ { TS_ME_END_OF_POST_START, "TS_ME_END_OF_POST_START" },
+ { TS_ME_END_OF_POST_END, "TS_ME_END_OF_POST_END" },
+ { TS_ME_BOOT_STALL_END, "TS_ME_BOOT_STALL_END" },
+ { TS_ME_ICC_CONFIG_START, "TS_ME_ICC_CONFIG_START" },
+ { TS_ME_HOST_BOOT_PREP_END, "TS_ME_HOST_BOOT_PREP_END" },
+ { TS_ME_RECEIVED_CRDA_FROM_PMC, "TS_ME_RECEIVED_CRDA_FROM_PMC" },
+ { TS_CSE_FW_SYNC_START, "TS_CSE_FW_SYNC_START" },
+ { TS_CSE_FW_SYNC_END, "TS_CSE_FW_SYNC_END" },
+ { TS_FSP_MEMORY_INIT_START, "TS_FSP_MEMORY_INIT_START" },
+ { TS_FSP_MEMORY_INIT_END, "TS_FSP_MEMORY_INIT_END" },
+ { TS_FSP_TEMP_RAM_EXIT_START, "TS_FSP_TEMP_RAM_EXIT_START" },
+ { TS_FSP_TEMP_RAM_EXIT_END, "TS_FSP_TEMP_RAM_EXIT_END" },
+ { TS_FSP_SILICON_INIT_START, "TS_FSP_SILICON_INIT_START" },
+ { TS_FSP_SILICON_INIT_END, "TS_FSP_SILICON_INIT_END" },
+ { TS_FSP_ENUMERATE_START, "TS_FSP_ENUMERATE_START" },
+ { TS_FSP_ENUMERATE_END, "TS_FSP_ENUMERATE_END" },
+ { TS_FSP_FINALIZE_START, "TS_FSP_FINALIZE_START" },
+ { TS_FSP_FINALIZE_END, "TS_FSP_FINALIZE_END" },
+ { TS_FSP_END_OF_FIRMWARE_START, "TS_FSP_END_OF_FIRMWARE_START" },
+ { TS_FSP_END_OF_FIRMWARE_END, "TS_FSP_END_OF_FIRMWARE_END" },
+ { TS_FSP_MULTI_PHASE_SI_INIT_START, "TS_FSP_MULTI_PHASE_SI_INIT_START" },
+ { TS_FSP_MULTI_PHASE_SI_INIT_END, "TS_FSP_MULTI_PHASE_SI_INIT_END" },
+ { TS_FSP_MEMORY_INIT_LOAD, "TS_FSP_MEMORY_INIT_LOAD" },
+ { TS_FSP_SILICON_INIT_LOAD, "TS_FSP_SILICON_INIT_LOAD" },
+ { TS_ME_ROM_START, "TS_ME_ROM_START" },
+ { TS_DC_START, "TS_DC_START" },
+ { TS_RO_PARAMS_INIT, "TS_RO_PARAMS_INIT" },
+ { TS_RO_VB_INIT, "TS_RO_VB_INIT" },
+ { TS_RO_VB_SELECT_FIRMWARE, "TS_RO_VB_SELECT_FIRMWARE" },
+ { TS_RO_VB_SELECT_AND_LOAD_KERNEL, "TS_RO_VB_SELECT_AND_LOAD_KERNEL" },
+ { TS_RW_VB_SELECT_AND_LOAD_KERNEL, "TS_RW_VB_SELECT_AND_LOAD_KERNEL" },
+ { TS_VB_SELECT_AND_LOAD_KERNEL, "TS_VB_SELECT_AND_LOAD_KERNEL" },
+ { TS_VB_EC_VBOOT_DONE, "TS_VB_EC_VBOOT_DONE" },
+ { TS_VB_STORAGE_INIT_DONE, "TS_VB_STORAGE_INIT_DONE" },
+ { TS_VB_READ_KERNEL_DONE, "TS_VB_READ_KERNEL_DONE" },
+ { TS_VB_VBOOT_DONE, "TS_VB_VBOOT_DONE" },
+ { TS_KERNEL_START, "TS_KERNEL_START" },
+ { TS_KERNEL_DECOMPRESSION, "TS_KERNEL_DECOMPRESSION" },
+};
+
+static const struct timestamp_start_end_pair {
+ uint32_t id_start;
+ uint32_t id_end;
+} timestamp_start_end_pairs[] = {
+ { TS_ROMSTAGE_START, TS_ROMSTAGE_END },
+ { TS_INITRAM_START, TS_INITRAM_END },
+ { TS_VBOOT_START, TS_VBOOT_END },
+ { TS_COPYRAM_START, TS_COPYRAM_END },
+ { TS_BOOTBLOCK_START, TS_BOOTBLOCK_END },
+ { TS_COPYROM_START, TS_COPYROM_END },
+ { TS_ULZMA_START, TS_ULZMA_END },
+ { TS_ULZ4F_START, TS_ULZ4F_END },
+ { TS_DEVICE_ENUMERATE, TS_DEVICE_CONFIGURE },
+ { TS_DEVICE_CONFIGURE, TS_DEVICE_ENABLE },
+ { TS_DEVICE_ENABLE, TS_DEVICE_INITIALIZE },
+ { TS_DEVICE_INITIALIZE, TS_DEVICE_DONE },
+ { TS_OPROM_INITIALIZE, TS_OPROM_END},
+
+ { TS_POSTCAR_START, TS_POSTCAR_END },
+ { TS_DELAY_START, TS_DELAY_END },
+ { TS_READ_UCODE_START, TS_READ_UCODE_END },
+ { TS_ELOG_INIT_START, TS_ELOG_INIT_END },
+ { TS_COPYVER_START, TS_COPYVER_END },
+ { TS_TPMINIT_START, TS_TPMINIT_END },
+ { TS_VERIFY_SLOT_START, TS_VERIFY_SLOT_END },
+ { TS_HASH_BODY_START, TS_HASH_BODY_END },
+
+ { TS_TPMPCR_START, TS_TPMPCR_END },
+ { TS_TPMLOCK_START, TS_TPMLOCK_END },
+ { TS_EC_SYNC_START, TS_EC_SYNC_END },
+
+ /* Order does matter. From largest to smallest ranges. */
+ { TS_COPYVPD_START, TS_COPYVPD_RW_END },
+ { TS_COPYVPD_START, TS_COPYVPD_RO_END },
+ { TS_COPYVPD_RO_END, TS_COPYVPD_RW_END },
+ { TS_TPM_ENABLE_UPDATE_START, TS_TPM_ENABLE_UPDATE_END },
+
+ { TS_AGESA_INIT_RESET_START, TS_AGESA_INIT_RESET_END },
+ { TS_AGESA_INIT_EARLY_START, TS_AGESA_INIT_EARLY_END },
+ { TS_AGESA_INIT_POST_START, TS_AGESA_INIT_POST_END },
+ { TS_AGESA_INIT_ENV_START, TS_AGESA_INIT_ENV_END },
+ { TS_AGESA_INIT_MID_START, TS_AGESA_INIT_MID_END },
+ { TS_AGESA_INIT_LATE_START, TS_AGESA_INIT_LATE_END },
+ { TS_AGESA_INIT_RTB_START, TS_AGESA_INIT_RTB_END },
+ { TS_AGESA_INIT_RESUME_START, TS_AGESA_INIT_RESUME_END },
+ { TS_AGESA_S3_LATE_START, TS_AGESA_S3_LATE_END },
+ { TS_AGESA_S3_FINAL_START, TS_AGESA_S3_FINAL_END },
+
+ { TS_AMD_APOB_READ_START, TS_AMD_APOB_END },
+ { TS_AMD_APOB_ERASE_START, TS_AMD_APOB_END },
+ { TS_AMD_APOB_WRITE_START, TS_AMD_APOB_END },
+
+ { TS_ME_INFORM_DRAM_START, TS_ME_INFORM_DRAM_END },
+ { TS_ME_END_OF_POST_START, TS_ME_END_OF_POST_END },
+
+ { TS_CSE_FW_SYNC_START, TS_CSE_FW_SYNC_END },
+ { TS_FSP_MEMORY_INIT_START, TS_FSP_MEMORY_INIT_END },
+ { TS_FSP_TEMP_RAM_EXIT_START, TS_FSP_TEMP_RAM_EXIT_END },
+ { TS_FSP_SILICON_INIT_START, TS_FSP_SILICON_INIT_END },
+ { TS_FSP_ENUMERATE_START, TS_FSP_ENUMERATE_END },
+ { TS_FSP_FINALIZE_START, TS_FSP_FINALIZE_END },
+ { TS_FSP_END_OF_FIRMWARE_START, TS_FSP_END_OF_FIRMWARE_END },
+ { TS_FSP_MULTI_PHASE_SI_INIT_START, TS_FSP_MULTI_PHASE_SI_INIT_END },
+};
+
#endif
diff --git a/util/cbmem/cbmem.c b/util/cbmem/cbmem.c
index a39ef2a..13f8cb3d 100644
--- a/util/cbmem/cbmem.c
+++ b/util/cbmem/cbmem.c
@@ -590,8 +590,139 @@
return 0;
}

+static int find_matching_end(struct timestamp_table *sorted_tst_p, uint32_t start, uint32_t end)
+{
+ uint32_t id = sorted_tst_p->entries[start].entry_id;
+
+ for (uint32_t i = start; i < end; i++) {
+ for (uint32_t k = 0; k < ARRAY_SIZE(timestamp_start_end_pairs); k++) {
+ if (timestamp_start_end_pairs[k].id_start == id
+ && timestamp_start_end_pairs[k].id_end
+ == sorted_tst_p->entries[i].entry_id)
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static const char *get_timestamp_name(uint32_t id)
+{
+ for (uint32_t i = 0; i < ARRAY_SIZE(timestamp_enum_ids); i++)
+ if (timestamp_enum_ids[i].id == id)
+ return timestamp_enum_ids[i].name;
+
+ return "UNKNOWN";
+}
+
+static char *new_timestamp_path(const char *parent_path, uint32_t id)
+{
+ char *new_path;
+ const char *name = get_timestamp_name(id);
+
+ if (parent_path) {
+ const size_t parent_path_len = strlen(parent_path);
+ const size_t name_len = strlen(name);
+
+ new_path = malloc(parent_path_len + 1 + name_len + 1);
+ memcpy(new_path, parent_path, parent_path_len);
+ new_path[parent_path_len] = ';';
+ memcpy(&new_path[parent_path_len + 1], name, name_len + 1);
+ } else {
+ new_path = strdup(name);
+ }
+
+ return new_path;
+}
+
+static char *new_timestamp_range_path(const char *parent_path, uint32_t start_id, uint32_t end_id)
+{
+ const char *start_name = get_timestamp_name(start_id);
+ const char *end_name = get_timestamp_name(end_id);
+ const size_t start_name_len = strlen(start_name);
+ const size_t end_name_len = strlen(end_name);
+ char *new_path;
+ size_t offset = 0;
+
+ if (parent_path) {
+ const size_t parent_path_len = strlen(parent_path);
+ new_path = malloc(parent_path_len + 1 + start_name_len + 1 + end_name_len + 1);
+ memcpy(new_path, parent_path, parent_path_len);
+ new_path[parent_path_len] = ';';
+ offset = parent_path_len + 1;
+ } else {
+ new_path = malloc(start_name_len + 1 + end_name_len + 1);
+ }
+
+ memcpy(&new_path[offset], start_name, start_name_len);
+ new_path[offset + start_name_len] = '/';
+ memcpy(&new_path[offset + start_name_len + 1], end_name, end_name_len + 1);
+
+ return new_path;
+}
+
+static void process_subrange(struct timestamp_table *sorted_tst_p, uint32_t start, uint32_t end,
+ const char *parent_path)
+{
+ for (uint32_t i = start; i < end;) {
+ const struct timestamp_entry *tse = &sorted_tst_p->entries[i];
+
+ /* Prepare path to current timestamp */
+ char *new_path;
+ uint64_t stamp;
+ int match = find_matching_end(sorted_tst_p, i, end);
+ /* Make all timestamps absolute. */
+ stamp = tse->entry_stamp + sorted_tst_p->base_time;
+ if (match == -1) {
+ /* Check, if there is a previous timestamp */
+ if (i > 0)
+ stamp = stamp
+ - (sorted_tst_p->entries[i - 1].entry_stamp
+ + sorted_tst_p->base_time);
+ stamp = arch_convert_raw_ts_entry(stamp);
+ new_path = new_timestamp_path(parent_path, tse->entry_id);
+
+ printf("%s %lu\n", new_path, stamp);
+ i++; /* Go to next one */
+ } else {
+ const struct timestamp_entry *tse_end = &sorted_tst_p->entries[match];
+ stamp = (tse_end->entry_stamp + sorted_tst_p->base_time) - stamp;
+ stamp = arch_convert_raw_ts_entry(stamp);
+ new_path = new_timestamp_range_path(parent_path, tse->entry_id,
+ tse_end->entry_id);
+
+ printf("%s %lu\n", new_path, stamp);
+
+ const int new_start = i + 1;
+ const int new_end = match;
+
+ if (new_end - new_start > 0)
+ process_subrange(sorted_tst_p, new_start, new_end, new_path);
+
+ if (find_matching_end(sorted_tst_p, match, end) == -1)
+ i = match + 1; /* Current range does not start any other one */
+ else
+ i = match; /* End of current range is beginning of another */
+ }
+
+ free(new_path);
+ }
+}
+
+static void dump_timestamps_stacked(struct timestamp_table *sorted_tst_p)
+{
+ /* Skip first timestamp, as it only marks the start of coreboot execution */
+ process_subrange(sorted_tst_p, 1, sorted_tst_p->num_entries, NULL);
+}
+
+enum timestamps_print_type {
+ TIMESTAMPS_PRINT_NORMAL = 0,
+ TIMESTAMPS_PRINT_MACHINE_READABLE = 1,
+ TIMESTAMPS_PRINT_STACKED = 2,
+};
+
/* dump the timestamp table */
-static void dump_timestamps(int mach_readable)
+static void dump_timestamps(enum timestamps_print_type output_type)
{
const struct timestamp_table *tst_p;
struct timestamp_table *sorted_tst_p;
@@ -612,7 +743,7 @@

timestamp_set_tick_freq(tst_p->tick_freq_mhz);

- if (!mach_readable)
+ if (output_type == TIMESTAMPS_PRINT_NORMAL)
printf("%d entries total:\n\n", tst_p->num_entries);
size += tst_p->num_entries * sizeof(tst_p->entries[0]);

@@ -644,29 +775,32 @@
*/
if (sorted_tst_p->entries[0].entry_stamp < 0)
sorted_tst_p->base_time = -sorted_tst_p->entries[0].entry_stamp;
- prev_stamp = 0;

- total_time = 0;
- for (uint32_t i = 0; i < sorted_tst_p->num_entries; i++) {
- uint64_t stamp;
- const struct timestamp_entry *tse = &sorted_tst_p->entries[i];
+ if (output_type == TIMESTAMPS_PRINT_STACKED) {
+ dump_timestamps_stacked(sorted_tst_p);
+ } else {
+ prev_stamp = 0;
+ total_time = 0;
+ for (uint32_t i = 0; i < sorted_tst_p->num_entries; i++) {
+ uint64_t stamp;
+ const struct timestamp_entry *tse = &sorted_tst_p->entries[i];

- /* Make all timestamps absolute. */
- stamp = tse->entry_stamp + sorted_tst_p->base_time;
- if (mach_readable)
- total_time +=
- timestamp_print_parseable_entry(tse->entry_id,
- stamp, prev_stamp);
- else
- total_time += timestamp_print_entry(tse->entry_id,
- stamp, prev_stamp);
- prev_stamp = stamp;
- }
+ /* Make all timestamps absolute. */
+ stamp = tse->entry_stamp + sorted_tst_p->base_time;
+ if (output_type == TIMESTAMPS_PRINT_MACHINE_READABLE)
+ total_time += timestamp_print_parseable_entry(
+ tse->entry_id, stamp, prev_stamp);
+ else if (output_type == TIMESTAMPS_PRINT_NORMAL)
+ total_time +=
+ timestamp_print_entry(tse->entry_id, stamp, prev_stamp);
+ prev_stamp = stamp;
+ }

- if (!mach_readable) {
- printf("\nTotal Time: ");
- print_norm(total_time);
- printf("\n");
+ if (output_type == TIMESTAMPS_PRINT_NORMAL) {
+ printf("\nTotal Time: ");
+ print_norm(total_time);
+ printf("\n");
+ }
}

unmap_memory(&timestamp_mapping);
@@ -1166,6 +1300,7 @@
" -r | --rawdump ID: print rawdump of specific ID (in hex) of cbtable\n"
" -t | --timestamps: print timestamp information\n"
" -T | --parseable-timestamps: print parseable timestamps\n"
+ " -S | --stacked-timestamps: print stacked timestamps (e.g. for flame graph tools)\n"
" -L | --tcpa-log print TCPA log\n"
" -V | --verbose: verbose (debugging) output\n"
" -v | --version: print the version\n"
@@ -1299,7 +1434,7 @@
int print_rawdump = 0;
int print_timestamps = 0;
int print_tcpa_log = 0;
- int machine_readable_timestamps = 0;
+ enum timestamps_print_type timestamp_type = TIMESTAMPS_PRINT_NORMAL;
enum console_print_type console_type = CONSOLE_PRINT_FULL;
unsigned int rawdump_id = 0;
int max_loglevel = BIOS_NEVER;
@@ -1316,6 +1451,7 @@
{"tcpa-log", 0, 0, 'L'},
{"timestamps", 0, 0, 't'},
{"parseable-timestamps", 0, 0, 'T'},
+ {"stacked-timestamps", 0, 0, 'S'},
{"hexdump", 0, 0, 'x'},
{"rawdump", required_argument, 0, 'r'},
{"verbose", 0, 0, 'V'},
@@ -1323,7 +1459,7 @@
{"help", 0, 0, 'h'},
{0, 0, 0, 0}
};
- while ((opt = getopt_long(argc, argv, "c12B:CltTLxVvh?r:",
+ while ((opt = getopt_long(argc, argv, "c12B:CltTSLxVvh?r:",
long_options, &option_index)) != EOF) {
switch (opt) {
case 'c':
@@ -1366,11 +1502,17 @@
break;
case 't':
print_timestamps = 1;
+ timestamp_type = TIMESTAMPS_PRINT_NORMAL;
print_defaults = 0;
break;
case 'T':
print_timestamps = 1;
- machine_readable_timestamps = 1;
+ timestamp_type = TIMESTAMPS_PRINT_MACHINE_READABLE;
+ print_defaults = 0;
+ break;
+ case 'S':
+ print_timestamps = 1;
+ timestamp_type = TIMESTAMPS_PRINT_STACKED;
print_defaults = 0;
break;
case 'V':
@@ -1483,7 +1625,7 @@
dump_cbmem_raw(rawdump_id);

if (print_defaults || print_timestamps)
- dump_timestamps(machine_readable_timestamps);
+ dump_timestamps(timestamp_type);

if (print_tcpa_log)
dump_tcpa_log();

To view, visit change 62474. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I3a4e20a267e9e0fbc6b3a4d6a2409b32ce8fca33
Gerrit-Change-Number: 62474
Gerrit-PatchSet: 1
Gerrit-Owner: Jakub Czapiga <jacz@semihalf.com>
Gerrit-MessageType: newchange