add more hover info

This commit is contained in:
silverweed 2024-07-29 23:36:27 +02:00
parent b758f63ed3
commit 4a2c23277d
3 changed files with 87 additions and 58 deletions

View file

@ -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 <typename T> 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 <typename T> 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 <typename T>
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 <typename T>
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 <typename TField_Type>
bool field(const char *desc_fmt,
String8_Node *(*display_val)(Arena *, String8_Node *, const char *, TField_Type) = hover_display_val<TField_Type>
String8_Node *(*display_val)(Arena *, String8_Node *, const char *, TField_Type) = hover_display_val_be<TField_Type>
) 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<u32>("NBytes: %u")
|| try_sec_hover.field<u16>("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<u16>("Cycle: %u")
|| try_sec_hover.field<u64>("Seek Key: 0x%lX")
|| try_sec_hover.field<u64>("Seek Pdir: 0x%lX")
|| try_sec_hover.field<String8>("Class Name: %s")
|| try_sec_hover.field<String8>("Obj Name: %s")
|| try_sec_hover.field<String8>("Obj Title: %s")
;
} else {
return try_sec_hover.field<u32>("NBytes: %u")
|| try_sec_hover.field<u16>("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<u16>("Cycle: %u")
|| try_sec_hover.field<u32>("Seek Key: 0x%lX")
|| try_sec_hover.field<u32>("Seek Pdir: 0x%lX")
|| try_sec_hover.field<String8>("Class Name: %s")
|| try_sec_hover.field<String8>("Obj Name: %s")
|| try_sec_hover.field<String8>("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<u32>("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<u32>("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<u64>("NBytes Footer: %u")
|| try_sec_hover.field<u64>("Len Footer: %u")
|| try_sec_hover.field<u64>("Max Key Size: %u")
|| try_sec_hover.field<u64>("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<u32>("ROOT magic number")
|| try_sec_hover.field<u32>("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<u32>("Compression: %u")
|| try_sec_hover.field<u64>("Seek Info: 0x%lX")
|| try_sec_hover.field<u32>("NBytes Info: %u")
|| try_sec_hover.range("Padding", section.post_size)
;
} else {
try_sec_hover.field<u32>("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<u32>("Compression: %u")
|| try_sec_hover.field<u32>("Seek Info: 0x%lX")
|| try_sec_hover.field<u32>("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<String8>("Class Name: %s")
|| try_sec_hover.field<String8>("Obj Name: %s")
|| try_sec_hover.field<String8>("Obj Title: %s")
|| try_sec_hover.field<String8>("File Name: %s")
b8 ok = try_sec_hover.field<String8>("File Name: %s")
|| try_sec_hover.field<String8>("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<u16>("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<u16>("UUID Vers.Class: %u")
|| try_sec_hover.field<u16>("UUID: %u", [] (Arena *arena, String8_Node *prev, const char *fmt, u16 x) {
return push_str8_node(arena, prev, fmt, x);
})
|| try_sec_hover.field<u16>("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<u64>("Checksum: 0x%lX", hover_display_val_le)
;
} break;
default:;
}

View file

@ -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;
};

View file

@ -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