Skip to content

Refactor to avoid multiple string heap allocations - #13897

Open
haydonryan wants to merge 1 commit into
uutils:mainfrom
haydonryan:main
Open

Refactor to avoid multiple string heap allocations#13897
haydonryan wants to merge 1 commit into
uutils:mainfrom
haydonryan:main

Conversation

@haydonryan

Copy link
Copy Markdown

Heya,
I'm experimenting with building llm prompts to do code review to improve size and speed and it found an interesting one pop up. Resulting change is faster, results in a slightly smaller binary and less heap allocations.

This change is already covered by integration test suite, but let me know if you want me to add unit tests.

format_tex_field escaped TeX special characters by mapping each character
through tex_mapper, collecting the results into a Vec<String>, and joining
them:

let mapped_chunks: Vec<String> = s.chars().map(tex_mapper).collect();
mapped_chunks.join("")

tex_mapper returns a String per character. Because std::String has no
small-string optimization (it is a Vec<u8>), every character produced a heap
allocation, plus one more for the Vec itself and one for the join. This
runs once per field on the ptx -T output path, so a single line with several
fields caused dozens of allocations.

Rewrote format_tex_field to push each escaped character directly into one
preallocated String, and removed tex_mapper:

let mut out = String::with_capacity(s.len());
for c in s.chars() {
    match c {
        '\\' => out.push_str("\\backslash{}"),
        '$' | '%' | '#' | '&' | '_' => {
            out.push('\\');
            out.push(c);
        }
        '}' | '{' => {
            out.push_str("$\\");
            out.push(c);
            out.push('$');
        }
        _ => out.push(c),
    }
}
out

The escaping rules are identical; only the intermediate Vec<String> and the
per-character allocations are gone. This removes roughly one allocation per
field (down from roughly one per character) and deletes a whole helper
function.

Metric Before After Change
Binary size (standalone ptx) 3,075,016 B 3,074,352 B −664 B (−0.022%)
Runtime (ms/run) 1332.5 ms 645.4 ms (20 runs) −687 ms (−48%)
Correctness (17,218,186 B output) baseline reference byte-identical pass (cmp equal)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant