From 4a2c23277d2f91f3fd6fb39bc2901e23d3e53b4a Mon Sep 17 00:00:00 2001 From: silverweed Date: Mon, 29 Jul 2024 23:36:27 +0200 Subject: [PATCH] add more hover info --- src/rntuple.cpp | 134 +++++++++++++++++++++++++++--------------------- src/rntuple.h | 1 + src/types.h | 10 ++++ 3 files changed, 87 insertions(+), 58 deletions(-) diff --git a/src/rntuple.cpp b/src/rntuple.cpp index ce7fdaf..231ce1d 100644 --- a/src/rntuple.cpp +++ b/src/rntuple.cpp @@ -129,7 +129,7 @@ void gather_ntuple_metadata(Arena *arena, RMicroFileReader &reader, const RNTupl // Very commonly pages are already sorted either in increasing or decreasing order. // By starting to look from the last inserted page we are very likely to find the // proper slot immediately. - b8 inserted = false; + [[maybe_unused]] b8 inserted = false; b8 pinfo_is_after_last = pinfo->range.start >= last_inserted_pinfo->range.end(); if (pinfo_is_after_last) { for (Page_Info_Node *node = last_inserted_pinfo->next; node; node = node->next) { @@ -262,7 +262,7 @@ TFile_Data get_tfile_data(const Inspected_File &file) const u64 version_seek = 4; u32 version_be; memcpy(&version_be, file.mem + version_seek, sizeof(version_be)); - u32 version = bswap_32(version_be); + u32 version = bswap(version_be); b32 is_big_file = version > 1000000; version -= is_big_file * 1000000; u32 version_major = version / 10000; @@ -280,35 +280,35 @@ TFile_Data get_tfile_data(const Inspected_File &file) // parse compression u32 compression_be; memcpy(&compression_be, file.mem + root_file_info.compression_seek, sizeof(compression_be)); - tfile_data.compression = bswap_32(compression_be); + tfile_data.compression = bswap(compression_be); // parse info if (is_big_file) { u64 info_seek_be; memcpy(&info_seek_be, file.mem + root_file_info.info_seek_seek, sizeof(info_seek_be)); - tfile_data.rng_root_file_info.start = bswap_64(info_seek_be); + tfile_data.rng_root_file_info.start = bswap(info_seek_be); } else { u32 info_seek_be; memcpy(&info_seek_be, file.mem + root_file_info.info_seek_seek, sizeof(info_seek_be)); - tfile_data.rng_root_file_info.start = bswap_32(info_seek_be); + tfile_data.rng_root_file_info.start = bswap(info_seek_be); } u32 info_nbytes_be; memcpy(&info_nbytes_be, file.mem + root_file_info.info_nbytes_seek, sizeof(info_nbytes_be)); - tfile_data.rng_root_file_info.len = bswap_32(info_nbytes_be); + tfile_data.rng_root_file_info.len = bswap(info_nbytes_be); // parse free list if (is_big_file) { u64 free_seek_be; memcpy(&free_seek_be, file.mem + root_file_info.free_seek_seek, sizeof(free_seek_be)); - tfile_data.rng_root_file_free.start = bswap_64(free_seek_be); + tfile_data.rng_root_file_free.start = bswap(free_seek_be); } else { u32 free_seek_be; memcpy(&free_seek_be, file.mem + root_file_info.free_seek_seek, sizeof(free_seek_be)); - tfile_data.rng_root_file_free.start = bswap_32(free_seek_be); + tfile_data.rng_root_file_free.start = bswap(free_seek_be); } u32 free_nbytes_be; memcpy(&free_nbytes_be, file.mem + root_file_info.free_nbytes_seek, sizeof(free_nbytes_be)); - tfile_data.rng_root_file_free.len = bswap_32(free_nbytes_be); + tfile_data.rng_root_file_free.len = bswap(free_nbytes_be); return tfile_data; } @@ -349,7 +349,7 @@ Byte_Range get_section_range(const App_State &app, Section_Id sec) { switch (sec) { default: return { 0, 0 }; - case Sec_TFile_Header: return Byte_Range { 0, app.tfile_data.root_file_header_size }; + case Sec_TFile_Header: return { 0, app.tfile_data.root_file_header_size }; case Sec_TFile_Object: return app.tfile_data.rng_root_file_obj; case Sec_TFile_Info: return app.tfile_data.rng_root_file_info; case Sec_TFile_FreeList: return app.tfile_data.rng_root_file_free; @@ -369,52 +369,53 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1) b8 hilite = false; // TFile start - if (off < tdata.root_file_header_size) return { Sec_TFile_Header, { 0, tdata.root_file_header_size }, 0, hilite }; - if (tdata.rng_root_file_obj.start <= off && off < tdata.rng_root_file_obj.end()) return { Sec_TFile_Object, tdata.rng_root_file_obj, 0, hilite }; - if (tdata.rng_root_file_info.start <= off && off < tdata.rng_root_file_info.end()) return { Sec_TFile_Info, tdata.rng_root_file_info, 0, hilite }; - if (tdata.rng_root_file_free.start <= off && off < tdata.rng_root_file_free.end()) return { Sec_TFile_FreeList, tdata.rng_root_file_free, 0, hilite }; + u64 root_header_padding = tdata.rng_root_file_obj.start - tdata.root_file_header_size; + if (off < tdata.rng_root_file_obj.start) return { Sec_TFile_Header, { 0, tdata.root_file_header_size }, 0, root_header_padding, hilite }; + if (tdata.rng_root_file_obj.start <= off && off < tdata.rng_root_file_obj.end()) return { Sec_TFile_Object, tdata.rng_root_file_obj, 0, 0, hilite }; + if (tdata.rng_root_file_info.start <= off && off < tdata.rng_root_file_info.end()) return { Sec_TFile_Info, tdata.rng_root_file_info, 0, 0, hilite }; + if (tdata.rng_root_file_free.start <= off && off < tdata.rng_root_file_free.end()) return { Sec_TFile_FreeList, tdata.rng_root_file_free, 0, 0, hilite }; /// Handle pages { // fast case: `off` is in the same page info as previous `off`. - if (app.last_pinfo->range.start < off && off < app.last_pinfo->range.end()) { + if (app.last_pinfo->range.start - rblob_sz < off && off < app.last_pinfo->range.end()) { hilite = hilite_cluster >= 0 && app.last_pinfo->cluster_id == (u64)hilite_cluster; - return { Sec_Page, app.last_pinfo->range, app.last_pinfo->checksum_size(), hilite }; + return { Sec_Page, app.last_pinfo->range, rblob_sz, app.last_pinfo->checksum_size(), hilite }; } // still fast case: `off is in the next page info as the previous. if (app.last_pinfo->next) // don't check if it's checksum, since it's the first byte of the page app.last_pinfo = app.last_pinfo->next; - if (app.last_pinfo && app.last_pinfo->range.start <= off && off < app.last_pinfo->range.end()) { + if (app.last_pinfo && app.last_pinfo->range.start - rblob_sz <= off && off < app.last_pinfo->range.end()) { hilite = hilite_cluster >= 0 && app.last_pinfo->cluster_id == (u64)hilite_cluster; - return { Sec_Page, app.last_pinfo->range, app.last_pinfo->checksum_size(), hilite }; + return { Sec_Page, app.last_pinfo->range, rblob_sz, app.last_pinfo->checksum_size(), hilite }; } } if (rdata.rng_anchor_key.start <= off && off < rdata.rng_anchor.end()) - return { Sec_RNTuple_Anchor, rdata.rng_anchor, 8, hilite }; + return { Sec_RNTuple_Anchor, rdata.rng_anchor, rdata.rng_anchor_key.len, 8, hilite }; if (rdata.rng_header.start - rblob_sz <= off && off < rdata.rng_header.end()) - return { Sec_RNTuple_Header, rdata.rng_header, 8, hilite }; + return { Sec_RNTuple_Header, rdata.rng_header, rblob_sz, 8, hilite }; if (rdata.rng_footer.start - rblob_sz <= off && off < rdata.rng_footer.end()) - return { Sec_RNTuple_Footer, rdata.rng_footer, 8, hilite }; + return { Sec_RNTuple_Footer, rdata.rng_footer, rblob_sz, 8, hilite }; if (rdata.rng_tkeys_list.start <= off && off < rdata.rng_tkeys_list.end()) - return { Sec_TKey_List, rdata.rng_tkeys_list, 0, hilite }; + return { Sec_TKey_List, rdata.rng_tkeys_list, rblob_sz, 0, hilite }; // @Speed for (u64 cg_idx = 0; cg_idx < rdata.n_cluster_groups; ++cg_idx) { Cluster_Group_Info &cg_info = rdata.cluster_groups[cg_idx]; if (cg_info.rng_page_list.start - rblob_sz <= off && off < cg_info.rng_page_list.end()) - return { Sec_Page_List, cg_info.rng_page_list, 8, hilite }; + return { Sec_Page_List, cg_info.rng_page_list, rblob_sz, 8, hilite }; } // Slow page group lookup, ideally only done once per render when last_pinfo is invalid. for (Page_Info_Chunk *chunk = rdata.page_chunks; chunk; chunk = chunk->next) { // If we're at the start of a chunk, return a fake Sec_Page used to highlight the RBlob header bytes. if (chunk->range.start - rblob_sz <= off && off < chunk->range.start) - return { Sec_Page, { chunk->range.start, 0 }, 0, hilite }; + return { Sec_Page, { chunk->range.start, 0 }, rblob_sz, 0, hilite }; if (chunk->range.start <= off && off < chunk->range.end()) { for (u64 group_idx = chunk->first_group; group_idx < rdata.n_page_groups; ++group_idx) { @@ -426,7 +427,7 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1) if (pinfo->range.start <= off && off < pinfo->range.end()) { app.last_pinfo = pinfo; hilite = hilite_cluster >= 0 && pinfo->cluster_id == (u64)hilite_cluster; - return { Sec_Page, pinfo->range, pinfo->checksum_size(), hilite }; + return { Sec_Page, pinfo->range, rblob_sz, pinfo->checksum_size(), hilite }; } } } @@ -445,29 +446,34 @@ struct Sec_Hover_Info { String8_Node *desc; }; -template void hover_postproc_val(T &) {} -template <> void hover_postproc_val(u16 &x) { x = bswap_16(x); } -template <> void hover_postproc_val(u32 &x) { x = bswap_32(x); } -template <> void hover_postproc_val(u64 &x) { x = bswap_64(x); } +template T bswap_if_needed(T x) { return x; } +template <> u16 bswap_if_needed(u16 x) { return bswap(x); } +template <> u32 bswap_if_needed(u32 x) { return bswap(x); } +template <> u64 bswap_if_needed(u64 x) { return bswap(x); } template -String8_Node *hover_display_val(Arena *arena, String8_Node *prev, const char *fmt, T val) +String8_Node *hover_display_val_be(Arena *arena, String8_Node *prev, const char *fmt, T val) { - hover_postproc_val(val); + val = bswap_if_needed(val); return push_str8_node(arena, prev, fmt, val); } template <> -String8_Node *hover_display_val(Arena *arena, String8_Node *prev, const char *fmt, String8 val) +String8_Node *hover_display_val_be(Arena *arena, String8_Node *prev, const char *fmt, String8 val) { - hover_postproc_val(val); return push_str8_node(arena, prev, fmt, val.c()); } +template +String8_Node *hover_display_val_le(Arena *arena, String8_Node *prev, const char *fmt, T val) +{ + return push_str8_node(arena, prev, fmt, val); +} + internal String8_Node *hover_display_datetime_str(Arena *arena, String8_Node *prev, const char *fmt_pre, u32 datetime) { - hover_postproc_val(datetime); + datetime = bswap(datetime); // datetime: // year (6b) | month (4b) | day (5b) | hour (5b) | min (6b) | sec (6b) @@ -480,6 +486,7 @@ String8_Node *hover_display_datetime_str(Arena *arena, String8_Node *prev, const return push_str8_node(arena, prev, "%s%u/%02u/%02u %02u:%02u:%02u", fmt_pre, year, month, day, hour, min, sec); } +// Functor used by get_section_hover_info to describe the structure of a section and print data about it. struct Try_Sec_Hover_Fn { u64 start; u64 roff; @@ -490,7 +497,7 @@ struct Try_Sec_Hover_Fn { template bool field(const char *desc_fmt, - String8_Node *(*display_val)(Arena *, String8_Node *, const char *, TField_Type) = hover_display_val + String8_Node *(*display_val)(Arena *, String8_Node *, const char *, TField_Type) = hover_display_val_be ) const { u64 field_len = sizeof(TField_Type); @@ -541,13 +548,13 @@ bool hover_try_key(const Try_Sec_Hover_Fn &try_sec_hover, const u8 *data, u64 st { u16 version_be; memcpy(&version_be, data + start + 4, sizeof(u16)); - u32 version = bswap_16(version_be); + u32 version = bswap(version_be); b8 is_big = version > 1000; if (is_big) { return try_sec_hover.field("NBytes: %u") || try_sec_hover.field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { - x = bswap_16(x); + x = bswap(x); x -= (x > 1000) * 1000; return push_str8_node(arena, prev, fmt, x); }) @@ -557,11 +564,14 @@ bool hover_try_key(const Try_Sec_Hover_Fn &try_sec_hover, const u8 *data, u64 st || try_sec_hover.field("Cycle: %u") || try_sec_hover.field("Seek Key: 0x%lX") || try_sec_hover.field("Seek Pdir: 0x%lX") + || try_sec_hover.field("Class Name: %s") + || try_sec_hover.field("Obj Name: %s") + || try_sec_hover.field("Obj Title: %s") ; } else { return try_sec_hover.field("NBytes: %u") || try_sec_hover.field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { - x = bswap_16(x); + x = bswap(x); x -= (x > 1000) * 1000; return push_str8_node(arena, prev, fmt, x); }) @@ -571,6 +581,9 @@ bool hover_try_key(const Try_Sec_Hover_Fn &try_sec_hover, const u8 *data, u64 st || try_sec_hover.field("Cycle: %u") || try_sec_hover.field("Seek Key: 0x%lX") || try_sec_hover.field("Seek Pdir: 0x%lX") + || try_sec_hover.field("Class Name: %s") + || try_sec_hover.field("Obj Name: %s") + || try_sec_hover.field("Obj Title: %s") ; } } @@ -581,23 +594,21 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co { Sec_Hover_Info info {}; - // printf("off: 0x%lX, sec start: 0x%lX\n", off, section.range.start); - // assert(off >= section.range.start); - if (off < section.range.start) { - printf("WRONG\n"); // TODO: fix TKey Header case - } + // printf("off: 0x%lX, sec start - pre_size: (0x%lX - %lu) = 0x%lX\n", off, section.range.start, section.pre_size, section.range.start - section.pre_size); + assert(off >= section.range.start - section.pre_size); info.desc = push_str8_node(arena, nullptr, section_names[section.id].c()); - u64 start = section.range.start; + u64 start = section.range.start - section.pre_size; u64 roff = off - start; // offset relative to `section` u64 cur_field_off = 0; Try_Sec_Hover_Fn try_sec_hover { start, roff, data, arena, info, cur_field_off }; switch (section.id) { case Sec_RNTuple_Anchor: { - try_sec_hover.field("Object len: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { - x = bswap_32(x); + hover_try_key(try_sec_hover, data, start) + || try_sec_hover.field("Object len: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { + x = bswap(x); x -= 0x4000'0000; return push_str8_node(arena, prev, fmt, x); }) @@ -613,19 +624,20 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co || try_sec_hover.field("NBytes Footer: %u") || try_sec_hover.field("Len Footer: %u") || try_sec_hover.field("Max Key Size: %u") + || try_sec_hover.field("Checksum: 0x%lX", hover_display_val_le) ; } break; case Sec_TFile_Header: { u32 root_version_be; memcpy(&root_version_be, data + start + 4, sizeof(u32)); - u32 root_version = bswap_32(root_version_be); + u32 root_version = bswap(root_version_be); b8 is_big = root_version > 1000000; if (is_big) { try_sec_hover.field("ROOT magic number") || try_sec_hover.field("ROOT version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u32 x) { - x = bswap_32(x); + x = bswap(x); x -= 1000000; return push_str8_node(arena, prev, fmt, x); }) @@ -639,6 +651,7 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co || try_sec_hover.field("Compression: %u") || try_sec_hover.field("Seek Info: 0x%lX") || try_sec_hover.field("NBytes Info: %u") + || try_sec_hover.range("Padding", section.post_size) ; } else { try_sec_hover.field("ROOT magic number") @@ -653,28 +666,25 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co || try_sec_hover.field("Compression: %u") || try_sec_hover.field("Seek Info: 0x%lX") || try_sec_hover.field("NBytes Info: %u") + || try_sec_hover.range("Padding", section.post_size) ; } } break; case Sec_TFile_Object: { if (!hover_try_key(try_sec_hover, data, start)) { - b8 ok = try_sec_hover.field("Class Name: %s") - || try_sec_hover.field("Obj Name: %s") - || try_sec_hover.field("Obj Title: %s") - || try_sec_hover.field("File Name: %s") + b8 ok = try_sec_hover.field("File Name: %s") || try_sec_hover.field("File Title: %s") ; - if (!ok) { u16 version_be; memcpy(&version_be, data + cur_field_off, sizeof(u16)); - u16 version = bswap_16(version_be); + u16 version = bswap(version_be); b8 is_big = version > 1000; if (is_big) { ok = ok || try_sec_hover.field("Version: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { - x = bswap_16(x); + x = bswap(x); x -= 1000; return push_str8_node(arena, prev, fmt, x); }) @@ -698,15 +708,23 @@ Sec_Hover_Info get_section_hover_info(Arena *arena, Section section, u64 off, co ; } ok = ok || try_sec_hover.field("UUID Vers.Class: %u") - || try_sec_hover.field("UUID: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) { - return push_str8_node(arena, prev, fmt, x); - }) + || try_sec_hover.field("UUID: %u", hover_display_val_le) || try_sec_hover.range("Padding", 3 * sizeof(u32)) ; } } } break; + case Sec_RNTuple_Header: + case Sec_RNTuple_Footer: + case Sec_Page_List: + case Sec_Page: { + hover_try_key(try_sec_hover, data, start) + || try_sec_hover.range("Payload", section.range.len - section.post_size) // TODO: improve + || try_sec_hover.field("Checksum: 0x%lX", hover_display_val_le) + ; + } break; + default:; } diff --git a/src/rntuple.h b/src/rntuple.h index b6485aa..877e032 100644 --- a/src/rntuple.h +++ b/src/rntuple.h @@ -107,6 +107,7 @@ enum Section_Id { struct Section { Section_Id id; Byte_Range range; + u64 pre_size; // usually the TKey header, excluded from `range` u64 post_size; // usually the checksum, included in `range` b8 highlighted; }; diff --git a/src/types.h b/src/types.h index 32750ca..c5666d8 100644 --- a/src/types.h +++ b/src/types.h @@ -25,3 +25,13 @@ using i64 = int64_t; #define LIKELY(x) __builtin_expect(!!(x), 1) #define UNLIKELY(x) __builtin_expect(!!(x), 0) + +#ifdef R__BYTESWAP +u16 bswap(u16 x) { return bswap_16(x); } +u32 bswap(u32 x) { return bswap_32(x); } +u64 bswap(u64 x) { return bswap_64(x); } +#else +u16 bswap(u16 x) { return x; } +u32 bswap(u32 x) { return x; } +u64 bswap(u64 x) { return x; } +#endif