Jakub Czapiga has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/62474 )
Change subject: util/cbmem: Add FlameGraph-compatible timestamps output ......................................................................
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(×tamp_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();