diff --git a/src/app_state.h b/src/app_state.h index d194b45..48e5383 100644 --- a/src/app_state.h +++ b/src/app_state.h @@ -16,13 +16,18 @@ struct Inspected_File { int inot; }; -struct App_State { - u8 should_quit; - - Window_Data win_data; - User_Input user_input; +// These data gets dropped and regenerated every time the file changes +struct Loaded_File_Data { RNTuple_Data rndata; TFile_Data tfile_data; +}; + +struct App_State { + b8 should_quit; + + Loaded_File_Data *fdata; + Window_Data win_data; + User_Input user_input; Inspected_File inspected_file; #ifndef RNT_NO_GFX @@ -34,9 +39,14 @@ struct App_State { Delta_Time_Accum delta_time_accum; - // Cache the last info node selected for faster lookup of offsets + // Cache the last info node selected for faster lookup of offsets. + // These are reset every frame. const Page_Info_Node *last_pinfo; const Section *last_other_root_obj; + + // Saved command line args that are used when hot-reloading the file. + u32 walk_tkeys_flags; + b8 extended_info; }; internal diff --git a/src/mainloop.cpp b/src/mainloop.cpp index a47e930..2b8c48a 100644 --- a/src/mainloop.cpp +++ b/src/mainloop.cpp @@ -157,8 +157,15 @@ void run_main_loop(GLFWwindow *window, Arena *arena, App_State &app) // TODO: this should re-run get_tfile_data and get_rntuple_data! char buf[sizeof(inotify_event) + NAME_MAX + 1]; ssize_t nbytes = read(app.inspected_file.inot, buf, sizeof(buf)); - if (nbytes) - app.inspected_file.size = file_size(app.inspected_file.stream); + if (nbytes > 0) { + printf("nbytes %ld\n", nbytes); + app.inspected_file.size = file_size(app.inspected_file.stream); + // @Leak! Use two arenas? + b8 success = get_tfile_data(arena, app.inspected_file, app.walk_tkeys_flags, app.ntpl_name, app.fdata->tfile_data); + if (success) + app.fdata->rndata = get_rntuple_data(arena, app.inspected_file, app.fdata->tfile_data, app.extended_info); + compute_tot_sections_size(app.fdata->tfile_data.sections); + } } if ((app.user_input.key_state[KEY_ESC] & KEY_STATE_IS_DOWN) || glfwWindowShouldClose(window)) { diff --git a/src/render.cpp b/src/render.cpp index 7d0d13b..68923a4 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -141,15 +141,17 @@ void init_viewer(Arena *arena, App_State &app, u16 n_cols) { Viewer &viewer = app.viewer; viewer.mem_edit = make_memory_editor(app, (i32)n_cols); + + const TFile_Data &tfile_data = app.fdata->tfile_data; // Init title - u32 n_ntuples = app.tfile_data.sections[Sec_RNTuple_Anchor].count; + u32 n_ntuples = tfile_data.sections[Sec_RNTuple_Anchor].count; if (n_ntuples) { Temp scratch = scratch_begin(&arena, 1); defer { scratch_end(scratch); }; if (n_ntuples == 1) { - Section *sec = app.tfile_data.sections[Sec_RNTuple_Anchor].head; + Section *sec = tfile_data.sections[Sec_RNTuple_Anchor].head; const RNTuple_Anchor_Info *anchor = (const RNTuple_Anchor_Info *)sec->info; String8 ntpl_desc = rntuple_description(scratch.arena, anchor->anchor); if (rntuple_is_old_version(anchor->anchor)) { @@ -163,7 +165,7 @@ void init_viewer(Arena *arena, App_State &app, u16 n_cols) } } else { String8 title = str8("RNTuples"); - for (Section *sec = app.tfile_data.sections[Sec_RNTuple_Anchor].head; sec; sec = sec->next) { + for (Section *sec = tfile_data.sections[Sec_RNTuple_Anchor].head; sec; sec = sec->next) { const RNTuple_Anchor_Info *anchor = (const RNTuple_Anchor_Info *)sec->info; String8 s = push_str8f(scratch.arena, " \"%s;%hu\",", anchor->name, anchor->cycle); title = str8_concat(scratch.arena, title, s); @@ -210,13 +212,13 @@ void viewer_jump_to(App_State &app, u64 addr) internal Page_Info_Node *viewer_jump_to_page(App_State &app, u64 page_idx) { - if (app.rndata.n_pages == 0) + if (app.fdata->rndata.n_pages == 0) return nullptr; - page_idx = (page_idx + app.rndata.n_pages) % app.rndata.n_pages; + page_idx = (page_idx + app.fdata->rndata.n_pages) % app.fdata->rndata.n_pages; #if 1 // @Speed - Page_Info_Node *page = app.rndata.pages; + Page_Info_Node *page = app.fdata->rndata.pages; for (u64 i = 0; i < page_idx; ++i) { page = page->next; assert(page); @@ -226,9 +228,9 @@ Page_Info_Node *viewer_jump_to_page(App_State &app, u64 page_idx) // Find the page_idx-th page. We could just iterate n times over the pages list, // but skimming through the clusters first should be faster in most cases. Page_Info_Node *page = nullptr; - for (u64 i = 0; i < app.rndata.n_clusters - 1; ++i) { - const Cluster_Info &cluster = app.rndata.clusters[i]; - const Cluster_Info &next_cluster = app.rndata.clusters[i]; + for (u64 i = 0; i < app.fdata->rndata.n_clusters - 1; ++i) { + const Cluster_Info &cluster = app.fdata->rndata.clusters[i]; + const Cluster_Info &next_cluster = app.fdata->rndata.clusters[i]; if (cluster.first_page_idx <= page_idx && page_idx < next_cluster.first_page_idx) { u64 idx_in_cluster = page_idx - cluster.first_page_idx; page = cluster.first_page; @@ -240,7 +242,7 @@ Page_Info_Node *viewer_jump_to_page(App_State &app, u64 page_idx) } if (!page) { // page was not in the first N - 1 clusters, so it must be in the last one. - const Cluster_Info &cluster = app.rndata.clusters[app.rndata.n_clusters - 1]; + const Cluster_Info &cluster = app.fdata->rndata.clusters[app.fdata->rndata.n_clusters - 1]; assert(page_idx >= cluster.first_page_idx); u64 idx_in_cluster = page_idx - cluster.first_page_idx; page = cluster.first_page; @@ -259,11 +261,11 @@ Page_Info_Node *viewer_jump_to_page(App_State &app, u64 page_idx) internal void viewer_jump_to_cluster(App_State &app, u64 cluster_idx) { - if (app.rndata.n_clusters == 0) + if (app.fdata->rndata.n_clusters == 0) return; - cluster_idx = (cluster_idx + app.rndata.n_clusters) % app.rndata.n_clusters; + cluster_idx = (cluster_idx + app.fdata->rndata.n_clusters) % app.fdata->rndata.n_clusters; - Cluster_Info &cluster = app.rndata.clusters[cluster_idx]; + Cluster_Info &cluster = app.fdata->rndata.clusters[cluster_idx]; Page_Info_Node *page = cluster.first_page; assert(page); @@ -275,12 +277,12 @@ void viewer_jump_to_cluster(App_State &app, u64 cluster_idx) internal void viewer_jump_to_page_list(App_State &app, u64 page_list_idx) { - if (app.rndata.n_cluster_groups == 0) + if (app.fdata->rndata.n_cluster_groups == 0) return; - page_list_idx = (page_list_idx + app.rndata.n_cluster_groups) % app.rndata.n_cluster_groups; + page_list_idx = (page_list_idx + app.fdata->rndata.n_cluster_groups) % app.fdata->rndata.n_cluster_groups; - Cluster_Group_Info &cg_info = app.rndata.cluster_groups[page_list_idx]; + Cluster_Group_Info &cg_info = app.fdata->rndata.cluster_groups[page_list_idx]; app.viewer.latest_section_gone_to[Sec_Page_List] = page_list_idx; viewer_jump_to(app, cg_info.rng_page_list.start); @@ -295,7 +297,7 @@ void viewer_jump_to_section(App_State &app, Section_Id id, u64 &sec_idx) return; } - const Sections §ions = app.tfile_data.sections[id]; + const Sections §ions = app.fdata->tfile_data.sections[id]; if (sections.count == 0) return; @@ -414,7 +416,7 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms) // Unique sections: just display a button that jumps to the start of it and show their size for (u32 i = 1; i < Sec_COUNT; ++i) { - if (!app.tfile_data.sections[i].head) + if (!app.fdata->tfile_data.sections[i].head) continue; // TODO: handle pages like other sections @@ -429,10 +431,10 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms) viewer_jump_to_section(app, static_cast<Section_Id>(i), app.viewer.latest_section_gone_to[i]); ImGui::SameLine(); - ImGui::Text("%s", to_pretty_size(scratch.arena, app.tfile_data.sections[i].tot_size).c()); - if (app.tfile_data.sections[i].count > 1) { + ImGui::Text("%s", to_pretty_size(scratch.arena, app.fdata->tfile_data.sections[i].tot_size).c()); + if (app.fdata->tfile_data.sections[i].count > 1) { // } else { - // ImGui::Text("%s (%u)", to_pretty_size(scratch.arena, app.tfile_data.sections[i].tot_size).c(), app.tfile_data.sections[i].count); + // ImGui::Text("%s (%u)", to_pretty_size(scratch.arena, app.fdata->tfile_data.sections[i].tot_size).c(), app.fdata->tfile_data.sections[i].count); ImGui::SameLine(); i64 sec_to_go_to = app.viewer.latest_section_gone_to[i]; ImGui::PushItemWidth(120.f); @@ -445,7 +447,7 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms) } ImGui::PopItemWidth(); ImGui::SameLine(); - ImGui::Text(" / %u", app.tfile_data.sections[i].count); + ImGui::Text(" / %u", app.fdata->tfile_data.sections[i].count); } } @@ -454,7 +456,7 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms) ImGui::SameLine(); if (ImGui::Button("TKey Header")) {} // TODO: jump to next key - if (app.rndata.n_pages) { + if (app.fdata->rndata.n_pages) { ImGui::ColorEdit3("_Page Start", app.viewer.col_page_start, edit_flags); ImGui::SameLine(); if (ImGui::Button("Page Start")) @@ -466,7 +468,7 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms) app.viewer.latest_page = viewer_jump_to_page(app, app.viewer.latest_section_gone_to[Sec_Page]); ImGui::SameLine(); { - const i64 step_fast_i64 = app.rndata.n_pages / 100; + const i64 step_fast_i64 = app.fdata->rndata.n_pages / 100; i64 page_to_go_to = app.viewer.latest_section_gone_to[Sec_Page]; ImGui::PushItemWidth(100.f); if (ImGui::InputScalar("##page_viewed", ImGuiDataType_S64, &page_to_go_to, &step_i64, &step_fast_i64, "%u") && @@ -479,9 +481,9 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms) ImGui::SameLine(); String8 this_page_width = app.viewer.latest_page ? push_str8f(scratch.arena, " / %" PRIu64 " (this page: %s)", - app.rndata.n_pages, to_pretty_size(scratch.arena, app.viewer.latest_page->range.len).c()) + app.fdata->rndata.n_pages, to_pretty_size(scratch.arena, app.viewer.latest_page->range.len).c()) : str8(""); - ImGui::Text("%s%s", to_pretty_size(scratch.arena, app.rndata.tot_page_comp_size).c(), this_page_width.c()); + ImGui::Text("%s%s", to_pretty_size(scratch.arena, app.fdata->rndata.tot_page_comp_size).c(), this_page_width.c()); } ImGui::ColorEdit3("_Checksum", app.viewer.col_checksum, edit_flags); @@ -492,22 +494,22 @@ void update_and_render(Arena *arena, App_State &app, f32 delta_time_ms) // ------------------------------- ImGui::Separator(); String8 root_version_str = push_str8f(scratch.arena, "%u.%u.%u", - app.tfile_data.root_version_major, - app.tfile_data.root_version_minor, - app.tfile_data.root_version_patch); + app.fdata->tfile_data.root_version_major, + app.fdata->tfile_data.root_version_minor, + app.fdata->tfile_data.root_version_patch); ImGui::Text("ROOT version: %s", root_version_str.c()); - ImGui::Text("TFile compression: %u", app.tfile_data.compression); - ImGui::Text("Num pages: %lu", app.rndata.n_pages); - ImGui::Text("Num elements: %lu", app.rndata.n_elems); - ImGui::Text("Num entries: %lu", app.rndata.n_entries); - if (app.rndata.tot_page_uncomp_size) { + ImGui::Text("TFile compression: %u", app.fdata->tfile_data.compression); + ImGui::Text("Num pages: %lu", app.fdata->rndata.n_pages); + ImGui::Text("Num elements: %lu", app.fdata->rndata.n_elems); + ImGui::Text("Num entries: %lu", app.fdata->rndata.n_entries); + if (app.fdata->rndata.tot_page_uncomp_size) { ImGui::Text("Pages uncompr. size: %s (comp.ratio = %.3f)", - to_pretty_size(scratch.arena, app.rndata.tot_page_uncomp_size).c(), - (f32)app.rndata.tot_page_comp_size / app.rndata.tot_page_uncomp_size); + to_pretty_size(scratch.arena, app.fdata->rndata.tot_page_uncomp_size).c(), + (f32)app.fdata->rndata.tot_page_comp_size / app.fdata->rndata.tot_page_uncomp_size); } { - const i64 step_fast_i64 = app.rndata.n_clusters / 100; + const i64 step_fast_i64 = app.fdata->rndata.n_clusters / 100; i64 cluster_to_highlight = app.viewer.highlighted_cluster; ImGui::PushItemWidth(100.f); if (ImGui::InputScalar("##highlighted_cluster", ImGuiDataType_S64, &cluster_to_highlight, &step_i64, &step_fast_i64, "%u") && diff --git a/src/render_term.cpp b/src/render_term.cpp index 4b52c2a..152de6d 100644 --- a/src/render_term.cpp +++ b/src/render_term.cpp @@ -55,12 +55,12 @@ String8_Node *render_legend_to_string(Arena *arena, const Term_Viewer &viewer, c range.start, range.end(), to_pretty_size(arena, range.len).c()); else if (section == Sec_Page) tail = push_str8_node(arena, tail, "%s%20s %s(%lu) [%s] \n", - color_str.c(), sec_name.c(), color_none.c(), app.rndata.n_pages, - to_pretty_size(arena, app.rndata.tot_page_comp_size).c()); + color_str.c(), sec_name.c(), color_none.c(), app.fdata->rndata.n_pages, + to_pretty_size(arena, app.fdata->rndata.tot_page_comp_size).c()); else if (section == Sec_Page_List) tail = push_str8_node(arena, tail, "%s%20s %s(%lu) [%s]\n", - color_str.c(), sec_name.c(), color_none.c(), app.rndata.n_cluster_groups, - to_pretty_size(arena, app.rndata.tot_page_list_size).c()); + color_str.c(), sec_name.c(), color_none.c(), app.fdata->rndata.n_cluster_groups, + to_pretty_size(arena, app.fdata->rndata.tot_page_list_size).c()); if (!head) { head = tail; if (prev) @@ -87,15 +87,15 @@ String8_Node *render_info_to_string(Arena *arena, Byte_Range range, const App_St " Num elements: %lu\n", ansi_color_table[ACol_None].c(), range.start, range.end(), app.inspected_file.size, - app.tfile_data.root_version_major, app.tfile_data.root_version_minor, app.tfile_data.root_version_patch, - app.tfile_data.compression, - app.rndata.n_pages, - app.rndata.n_elems); + app.fdata->tfile_data.root_version_major, app.fdata->tfile_data.root_version_minor, app.fdata->tfile_data.root_version_patch, + app.fdata->tfile_data.compression, + app.fdata->rndata.n_pages, + app.fdata->rndata.n_elems); - if (app.rndata.tot_page_uncomp_size) { + if (app.fdata->rndata.tot_page_uncomp_size) { res = push_str8_node(arena, res, " Pages uncompressed size: %s (comp.ratio = %.3f)\n", - to_pretty_size(arena, app.rndata.tot_page_uncomp_size).c(), - (f32)app.rndata.tot_page_comp_size / app.rndata.tot_page_uncomp_size); + to_pretty_size(arena, app.fdata->rndata.tot_page_uncomp_size).c(), + (f32)app.fdata->rndata.tot_page_comp_size / app.fdata->rndata.tot_page_uncomp_size); } return res; @@ -217,7 +217,9 @@ String8_Node *render_range_to_string(Arena *arena, App_State &app, u64 len, u64 defer { scratch_end(scratch); }; // Header - String8 ntpl_desc = rntuple_description(scratch.arena, ((const RNTuple_Anchor_Info *)app.tfile_data.sections[Sec_RNTuple_Anchor].head->info)->anchor); // FIXME :multiple_anchors: + // FIXME :multiple_anchors: + String8 ntpl_desc = rntuple_description(scratch.arena, + ((const RNTuple_Anchor_Info *)app.fdata->tfile_data.sections[Sec_RNTuple_Anchor].head->info)->anchor); String8_Node *result = push_str8_node(arena, nullptr, "RNTuple '%s' (%s) from file \"%s\"\n", app.ntpl_name.c(), ntpl_desc.c(), app.inspected_file.name.c()); String8_Node *result_tail = result; diff --git a/src/rntuple.cpp b/src/rntuple.cpp index dab63f2..7f68dcf 100644 --- a/src/rntuple.cpp +++ b/src/rntuple.cpp @@ -485,12 +485,13 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1) // These are supposed to never be null. If they are invalid, they must be set to `&invalid_pinfo` etc. assert(app.last_pinfo); - const RNTuple_Data &rdata = app.rndata; + const RNTuple_Data &rdata = app.fdata->rndata; + const TFile_Data &tfile_data = app.fdata->tfile_data; Section sec {}; for (u32 i = 1; i < Sec_COUNT_Regular; ++i) { - for (Section *sec = app.tfile_data.sections[i].head; sec; sec = sec->next) { + for (Section *sec = tfile_data.sections[i].head; sec; sec = sec->next) { if (sec->range.start - sec->pre_size <= off && off < sec->range.end()) { return *sec; } @@ -499,8 +500,8 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1) // Page / PageList lookup. // If we don't have a Sec_Page section it means we don't have any RNTuple, so skip it. - if (app.tfile_data.sections[Sec_Page].head) { - u64 rblob_sz = app.tfile_data.sections[Sec_Page].head->pre_size; + if (tfile_data.sections[Sec_Page].head) { + u64 rblob_sz = tfile_data.sections[Sec_Page].head->pre_size; /// Page fast lookup (relative to app.last_pinfo) { @@ -578,7 +579,7 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1) // Lookup other root objects. // @Copypasted from the fast page lookup - if (app.tfile_data.sections[Sec_Other].count > 0) { + if (tfile_data.sections[Sec_Other].count > 0) { // fast case: `off` is in the same obj as previous `off`. for (i32 i = 0; i < 2; ++i) { const Section &other_sec = *app.last_other_root_obj; @@ -594,7 +595,7 @@ Section find_section(App_State &app, u64 off, i64 hilite_cluster = -1) } // Slow linear lookup, ideally only done once per render when last_other_root_obj is invalid. - for (Section *other_sec = app.tfile_data.sections[Sec_Other].head; other_sec; other_sec = other_sec->next) { + for (Section *other_sec = tfile_data.sections[Sec_Other].head; other_sec; other_sec = other_sec->next) { if (other_sec->range.start - other_sec->pre_size <= off && off < other_sec->range.end()) { app.last_other_root_obj = other_sec; return *other_sec; diff --git a/src/rntviewer.cpp b/src/rntviewer.cpp index 61d8fbb..873363f 100644 --- a/src/rntviewer.cpp +++ b/src/rntviewer.cpp @@ -164,9 +164,13 @@ int main(int argc, char **argv) walk_tkeys_flags |= WTK_PRINT_KEYS_INFO; if (!args.dont_collect_other_root_objs) walk_tkeys_flags |= WTK_COLLECT_OTHER_ROOT_OBJS; - b8 success = get_tfile_data(arena, app.inspected_file, walk_tkeys_flags, app.ntpl_name, app.tfile_data); + app.walk_tkeys_flags = walk_tkeys_flags; + app.extended_info = args.extended_info; + + app.fdata = arena_push<Loaded_File_Data>(arena); + b8 success = get_tfile_data(arena, app.inspected_file, walk_tkeys_flags, app.ntpl_name, app.fdata->tfile_data); if (args.only_print_rntuple_names) { - for (Section *sec = app.tfile_data.sections[Sec_RNTuple_Anchor].head; sec; sec = sec->next) { + for (Section *sec = app.fdata->tfile_data.sections[Sec_RNTuple_Anchor].head; sec; sec = sec->next) { const RNTuple_Anchor_Info *info = (const RNTuple_Anchor_Info *)sec->info; printf("%s at 0x%" PRIX64 "\n", info->name.c(), info->offset_in_file); } @@ -174,9 +178,9 @@ int main(int argc, char **argv) } if (success) - app.rndata = get_rntuple_data(arena, app.inspected_file, app.tfile_data, args.extended_info); + app.fdata->rndata = get_rntuple_data(arena, app.inspected_file, app.fdata->tfile_data, args.extended_info); - compute_tot_sections_size(app.tfile_data.sections); + compute_tot_sections_size(app.fdata->tfile_data.sections); if (args.print_to_terminal) { u64 nbytes_displayed = args.nbytes_displayed;