diff options
| author | Stefan Boberg <[email protected]> | 2026-04-20 21:50:41 +0200 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2026-04-20 21:50:41 +0200 |
| commit | 2dfb5da16b97a6c12e01977af5b5188522178a4e (patch) | |
| tree | 428aa0aa8e6079c64438931e0fd4f828c613c94d /src/zen/zen.cpp | |
| parent | Add CompactString utility type (#990) (diff) | |
| download | archived-zen-2dfb5da16b97a6c12e01977af5b5188522178a4e.tar.xz archived-zen-2dfb5da16b97a6c12e01977af5b5188522178a4e.zip | |
zen trace analysis support (#945)
Integrates the **tourist** trace analysis library and builds a full `zen trace` command suite for working with Unreal Engine `.utrace` files.
### Trace analysis library (`thirdparty/tourist/`)
- Adds the tourist library as a third-party dependency with three modules: **foundation** (platform primitives, memory, scheduling), **trace** (UE Trace protocol decoding), and **analysis** (event dispatching and analyzer framework).
- Cross-platform support for Windows, Linux, and macOS.
### `zen trace` CLI commands (`src/zen/cmds/`, `src/zen/trace/`)
- **`zen trace analyze`** — Summarize a `.utrace` file: session metadata, thread inventory, command line + build configuration, CPU profiling scopes, timing, event rates, log messages, and (with symbols) memory allocation metrics including live-allocs dumps, callstack-keyed aggregation, and allocation churn. Optional HTML output for memory reports.
- **`zen trace inspect`** — Dump the event schema (declared types, fields, sizes) from a trace file.
- **`zen trace trim`** — Extract a time-window from a trace into a new `.utrace` file.
- **`zen trace serve`** — Launch a local HTTP server hosting an interactive trace viewer; opens in the default browser.
### Symbolication (`src/zen/trace/symbol_resolver.*`, `thirdparty/raw_pdb/`)
- Pluggable resolver with multiple backends: `pdb` (in-tree raw_pdb), `dbghelp` (Windows), `llvm-symbolizer` (all platforms), `atos` (macOS). An `auto` backend picks the best available tool per platform.
- Microsoft Symbol Server support: downloads PDBs on demand using a redirect-aware HTTP client.
- Local PDB cache keyed by image GUID preserves symbols across binary recompilation.
- Callstack trimming heuristic strips UE internal noise from reports.
- Binary analysis cache (`.ucache_z`) avoids re-resolving the same trace.
### Interactive trace viewer (`src/zen/frontend/html/`, `src/zen/trace/trace_viewer_service.*`)
- Timeline: scope-level detail, horizontal zoom/pan, vertical scrolling, viewport-driven loading with pre-computed LOD for responsive navigation of large traces.
- Thread grouping (collapsible sidebar sections) synthesized from name suffixes, natural sort order, visual distinction between lane threads and OS threads.
- Bookmark and region annotations; region categories with per-category toggles; bookmark marker toggle in the toolbar.
- Filterable Logs tab showing captured `UE_LOG` output.
- Stats tab with per-scope aggregate statistics.
- Memory tab with interactive allocation analysis and an allocation size histogram.
- CsvProfiler event parsing and chart UI.
### Other in-branch supporting changes
- **Cross-platform browser launcher** (`browser_launcher.{h,cpp}`) used by `trace serve`.
- **`ReciprocalU64`** fast 64-bit integer division (zencore/intmath) for trace analyzers.
- **`parallelsort`** cross-platform parallel sort helper (zenutil).
- Frontend zip build rule so the viewer's HTML assets are bundled into `zen.exe`.
- `/Zo` flag for better optimized debug info on Windows release builds.
- `trace-tests.cpp` in the `zen-test` harness (harness itself landed on main via #985).
Diffstat (limited to 'src/zen/zen.cpp')
| -rw-r--r-- | src/zen/zen.cpp | 68 |
1 files changed, 45 insertions, 23 deletions
diff --git a/src/zen/zen.cpp b/src/zen/zen.cpp index 984e8589b..02695419e 100644 --- a/src/zen/zen.cpp +++ b/src/zen/zen.cpp @@ -21,13 +21,13 @@ #include "cmds/service_cmd.h" #include "cmds/status_cmd.h" #include "cmds/top_cmd.h" -#include "cmds/trace_cmd.h" #include "cmds/ui_cmd.h" #include "cmds/up_cmd.h" #include "cmds/version_cmd.h" #include "cmds/vfs_cmd.h" #include "cmds/wipe_cmd.h" #include "cmds/workspaces_cmd.h" +#include "trace/trace_cmd.h" #include <zencore/callstack.h> #include <zencore/config.h> @@ -270,20 +270,34 @@ ZenCmdWithSubCommands::PrintHelp() Options().set_width(TuiConsoleColumns(80)); printf("%s\n", Options().help(Groups).c_str()); - // Append subcommand listing. + // Append subcommand listing. When a subcommand has aliases, display them as + // "name|alias1|alias2" in the left column so callers discover the alternate spellings. + auto FormatSubCmdName = [](ZenSubCmdBase& SubCmd) { + std::string Name(SubCmd.SubOptions().program()); + for (const std::string& Alias : SubCmd.Aliases()) + { + Name.push_back('|'); + Name.append(Alias); + } + return Name; + }; + + std::vector<std::string> FormattedNames; + FormattedNames.reserve(m_SubCommands.size()); size_t MaxNameLen = 0; for (ZenSubCmdBase* SubCmd : m_SubCommands) { - MaxNameLen = std::max(MaxNameLen, SubCmd->SubOptions().program().size()); + FormattedNames.push_back(FormatSubCmdName(*SubCmd)); + MaxNameLen = std::max(MaxNameLen, FormattedNames.back().size()); } printf("subcommands:\n"); - for (ZenSubCmdBase* SubCmd : m_SubCommands) + for (size_t i = 0; i < m_SubCommands.size(); ++i) { printf(" %-*s %s\n", static_cast<int>(MaxNameLen), - SubCmd->SubOptions().program().c_str(), - std::string(SubCmd->Description()).c_str()); + FormattedNames[i].c_str(), + std::string(m_SubCommands[i]->Description()).c_str()); } printf("\nFor global options run: zen --help\n"); } @@ -308,16 +322,33 @@ ZenCmdWithSubCommands::PrintSubCommandHelp(cxxopts::Options& SubCmdOptions) void ZenCmdWithSubCommands::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) { - std::vector<cxxopts::Options*> SubOptionPtrs; - SubOptionPtrs.reserve(m_SubCommands.size()); - for (ZenSubCmdBase* SubCmd : m_SubCommands) - { - SubOptionPtrs.push_back(&SubCmd->SubOptions()); - } - + ZenSubCmdBase* MatchedSubCmd = nullptr; cxxopts::Options* MatchedSubOption = nullptr; std::vector<char*> SubCommandArguments; - int ParentArgc = GetSubCommand(Options(), argc, argv, SubOptionPtrs, MatchedSubOption, SubCommandArguments); + int ParentArgc = argc; + for (int i = 1; i < argc; ++i) + { + std::string_view Arg(argv[i]); + for (ZenSubCmdBase* SubCmd : m_SubCommands) + { + const bool NameMatch = SubCmd->SubOptions().program() == Arg; + const bool AliasMatch = + !NameMatch && std::find(SubCmd->Aliases().begin(), SubCmd->Aliases().end(), Arg) != SubCmd->Aliases().end(); + if (NameMatch || AliasMatch) + { + MatchedSubCmd = SubCmd; + MatchedSubOption = &SubCmd->SubOptions(); + break; + } + } + if (MatchedSubCmd != nullptr) + { + SubCommandArguments.push_back(argv[0]); + std::copy(&argv[i + 1], &argv[argc], std::back_inserter(SubCommandArguments)); + ParentArgc = i + 1; + break; + } + } // Intercept --help/-h in the parent arg range before calling ParseOptions so // we can append subcommand information to the output. When a subcommand was @@ -344,15 +375,6 @@ ZenCmdWithSubCommands::Run(const ZenCliOptions& GlobalOptions, int argc, char** throw OptionParseException("No subcommand specified", {}); } - ZenSubCmdBase* MatchedSubCmd = nullptr; - for (ZenSubCmdBase* SubCmd : m_SubCommands) - { - if (&SubCmd->SubOptions() == MatchedSubOption) - { - MatchedSubCmd = SubCmd; - break; - } - } ZEN_ASSERT(MatchedSubCmd != nullptr); // Intercept --help/-h in the subcommand args so we can show combined help |