Skip to main content

Crate shuyi_alloc_count

Crate shuyi_alloc_count 

Source
Expand description

Shuyi Engine’s heap counter (ADR-0046 §9): CountingAlloc, a global allocator around another that counts what is asked of it, and with the global feature, the global module: the one counting allocator of every debug build of a game on shuyi-app and of its tool program.

What it counts:

  • the bytes asked for, each Layout’s size: never the inner allocator’s own overhead, so a reading is what the program asked for, the same on every machine;
  • live bytes, allocated and not yet freed, and their peak, the most at once since the start or a CountingAlloc::reset_peak;
  • calls to alloc, alloc_zeroed and realloc, taken: each read (CountingAlloc::take_allocs) gives the calls since the last.

A global allocator counts the whole process: every thread’s allocations count, not only the game’s.

Debug builds count; release builds don’t. shuyi-app and shuyi-cli turn on global, so a game’s debug build and its tool program’s run on global’s counter, and App puts its counts in each frame’s record (shuyi_ui::perf::FrameRecord::heap). A game with a #[global_allocator] of its own opts out, since a binary has one: in its .cargo/config.toml,

[build]
rustflags = ["--cfg", "shuyi_no_heap_count"]

Without std the crate is no_std: a console’s backend wraps the SDK’s own allocator in a CountingAlloc.

Memory tags (ADR-0046 §6) say what the bytes are for. A CountingAlloc::with_tags also counts each block under the tag current on its thread when it was allocated: the frame’s phase (update, draw, …), the game’s span, or the asset kind being decoded, the innermost one entered winning (tags). Its rows give each tag’s live bytes and blocks, the bytes ever allocated under it and its peak (TagCounts). Tags come from a process-wide table of 256: tag 0 is other, what is allocated outside any tag, and tag 255 overflow, which every name past the 254th shares (tags::overflowed counts them). A realloc moves its block to the current tag, so a list that grows in update counts in update.

The cost: each block carries its tag in a header in front of it, of its alignment or 8 bytes if that is more (Tagged), and each call counts twice. The global counter has tags, in debug builds only; a CountingAlloc::new has none, and no header.

Modules§

global
The one counting allocator of a debug build (the global feature): a #[global_allocator] crate::CountingAlloc::with_tags over std::alloc::System, and reading and rows, which read it. What it counts goes under the tags the program enters (crate::tags): shuyi-app and shuyi-cli enter the frame’s phases, the game’s spans and each asset kind’s decode.
tags
Memory tags (ADR-0046 §6): what a CountingAlloc::with_tags counts each block under. A tag is a number, 0 to 255, for a name in a process-wide table: the frame’s phase, the game’s span, or the asset kind being decoded. Code tags what it allocates by entering a tag around it, and the innermost tag entered wins:

Structs§

CountingAlloc
A global allocator around inner that counts what is asked of it: the bytes live, their peak, and the calls to alloc, alloc_zeroed and realloc. It counts each Layout’s size, never the inner allocator’s own overhead.
Counts
What a CountingAlloc counted, read at once (CountingAlloc::counts). Build it with Counts::new (ADR-0039).
TagCounts
One memory tag’s counts in a CountingAlloc::with_tags (CountingAlloc::rows), in bytes asked for. Build it with TagCounts::new (ADR-0039).
Tagged
What a CountingAlloc::with_tags counts by tag: for each of the TAGS, its live bytes and blocks, the bytes ever allocated under it, and the peak of its live bytes.
Untagged
What a CountingAlloc::new counts by tag: nothing, and no header in front of a block.