Skip to content

perf(ifc): rvt-ifc writes the IFC as it builds it, after releasing the file handle (#1075) - #1291

Merged
DrunkOnJava merged 4 commits into
mainfrom
perf/1075-stream-step
Nov 3, 2026
Merged

DrunkOnJava merged 4 commits into
mainfrom
perf/1075-stream-step

Conversation

@DrunkOnJava

@DrunkOnJava DrunkOnJava commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

Summary

For #1075: rvt-ifc writes the IFC as it builds it. The STEP text was built whole in memory and then written. Now it is handed to the file every MiB, after the file handle, and the partitions it keeps inflated, are released. The bytes are the same. rvt::ifc::step_writer::write_step_to streams to any writer.

Motivation

#1075's reporter sees a 10.3 GB peak on a 438 MB model, and a 1.13 GB model running out of memory at 16 GB. The stage probe (Measure 41659406909) splits the office's memory:

  • the export peaks at 1.13 GiB;
  • the saved-graphics pass adds 0.83 GiB;
  • the handle's inflated partitions hold 362 MiB;
  • the STEP text, 68 MB, was built on top of all of it.

The reporter has been asked to run the probe on their model; this change is the part that needs no such evidence.

Changes

  • src/ifc/step_writer.rs:
    • the writer keeps its String buffer, and with a sink it hands the buffer on whenever it passes 1 MiB;
    • new write_step_to<W: io::Write>(model, options, out: W) -> io::Result<u64>; pass &mut writer to keep the writer;
    • write_step and write_step_with_options are unchanged, so the Python and wasm bindings keep the text API.
  • src/bin/rvt_ifc.rs:
    • the RevitFile is dropped before the text is written, on both paths;
    • without --observation, the text is streamed to <output>.partial and renamed to the output when whole, and the partial file is removed on an error, so a failed or killed export leaves no truncated IFC under the output's name;
    • with --observation, the witness reads the text back, so it is still built whole.
  • probes/examples/probe_1075_memory_stages.rs: the stage probe, with a last step_stream stage.
  • changelog.d/changed/1075-stream-step.md.

Testing

  • Byte identity: Measure 41671835683 against main (-f nordic=true -f r2025=true -f samples=true -f holdout=true). All 109 exports hash the same; ifc.sha256 leaves out the timestamped FILE_NAME and IfcOwnerHistory. On the 92 whose log is kept (held-out logs are scrubbed), rvt-ifc reports the same byte counts. After review and a merge of main, 41691823738 (291fbb3 against main): 92 of 92 exports byte-identical, and no .partial file left in any model's folder.
  • Memory: Measure 41671841772, the probe on the office and the 2024 samples. Streaming the office as built writes the same 67,827,037 bytes to a sink in 750 ms (after the in-memory build, so warm and without file I/O), against 1,487 ms built whole, at a 1.16 GiB peak once the handle is dropped. These peaks are the probe's stages, not a max-RSS run of rvt-ifc. At building permit the run's peak was the STEP text (1.68 GiB); it is now the saved-graphics pass (1.59 GiB). As built, the saved-graphics pass already set the peak (1.65 GiB), so it does not change.

Not changed

  • The saved-graphics pass, which decodes every door's and window's graphics before meshing any, and the export itself.
  • Python and the viewer, which still build the text.

Legal and contribution hygiene

  • Apache-2.0
  • No Autodesk proprietary source, decompiled internals or NDA material

Breaking changes

None. One public function is added.

…e file handle, and write_step_to streams the STEP text to any writer (#1075)
…when whole, releases the handle on both paths, and write_step_to takes its writer by value and counts in u64 (#1075)
@DrunkOnJava
DrunkOnJava marked this pull request as ready for review November 3, 2026 18:58
@DrunkOnJava
DrunkOnJava enabled auto-merge (squash) November 3, 2026 18:58
@DrunkOnJava
DrunkOnJava merged commit 8664b94 into main Nov 3, 2026
28 checks passed
@DrunkOnJava
DrunkOnJava deleted the perf/1075-stream-step branch November 3, 2026 19:04
@DrunkOnJava

Copy link
Copy Markdown
Owner Author

Automated Claude Code review (the maintainer's review agent; it read the code and runs 41671835683 and 41671841772): no blocking items. Fixed anyway in ea91a5c: rvt-ifc streams to a file beside the output and renames it only when whole, so a failed export leaves no truncated model.ifc; the handle is released on both paths; and write_step_to takes its writer by value and counts in u64.

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