Skip to content

[Caching] Ref 7: CPU per-task artifact cache (ORC object serialize/load) - #901

Open
hughperkins wants to merge 16 commits into
mainfrom
hp/po-7-cpu-pertask
Open

[Caching] Ref 7: CPU per-task artifact cache (ORC object serialize/load)#901
hughperkins wants to merge 16 commits into
mainfrom
hp/po-7-cpu-pertask

Conversation

@hughperkins

Copy link
Copy Markdown
Collaborator

Summary

Extends the cross-process per-task compile-cache tier (6a, #893) to the CPU backend. Ref 7 is a fill + assemble/load adapter onto 6a's existing seam: everything 6a built (per-task IR key, on-disk PerTaskArtifact store, the probe / eligibility gate / .qdc per_task_artifact_keys persistence / tasks_* observability in codegen.cpp) is backend-agnostic and reused unchanged. The only new backend payload is a host relocatable object where CUDA's is PTX. Depends on 6a (#893) and 1c (#864), both merged; 1b is not a dependency (CPU needs no relink).

  • codegen/codegen.cpp — widen the two arch == Arch::cuda gates to arch_is_cpu. CPU takes the per-task path only when the artifact tier is on (artifact_tier); with offline_cache=false it keeps its existing whole-kernel module. CUDA behavior is unchanged.
  • runtime/cpu/jit_cpu.cpp — implement JITSessionCPU::add_module_per_task (mirror of the CUDA fill site). Miss: compile the per-task module to a host object via orc::SimpleCompiler (host PIC target machine, matching KernelCodeGenCPU::optimize_module) and store {object bytes, tasks, used_tree_ids, struct_for_tls_sizes} under the IR key. Hit: wrap the cached bytes in a MemoryBuffer and add to the object layer. One JITDylib per task (CPU analog of CUDA's one-CUmodule-per-task), so per-task objects can never collide on a shared helper/global symbol — which is why CPU needs no 1b-style relink. JITModuleCPU now resolves symbols across its N dylibs.
  • runtime/cpu/kernel_launcher.cpp — take the per-task path when per_construct_artifacts is non-empty (mirror of the CUDA launcher), else the whole-kernel module.
  • runtime/program_impls/llvm/llvm_program.cpp — scope the per-task dir by host triple + CPU name (as CUDA scopes by sm_<cc>), so an NFS-shared cache on a heterogeneous cluster never serves a host object to an incompatible CPU.
  • tests/python/test_per_offload_cache.py — CPU cross-process reuse test + CPU disabled-tier test.

Note: BLS (bls_buffer, mem_access_opt) is GPU-only, so the codegen_cpu.cpp linkage question from the plan is moot on CPU — create_bls_buffer never fires there.

Test plan

Built and run on the cluster (x64, LLVM 22.1.0). All green:

  • test_per_offload_cache (cpu): 22 passed, incl. test_per_task_artifact_cache_reuses_shared_task_cross_process_cpu (a fresh process loads the unchanged task's object from disk, recompiles only the differing task, byte-identical result) and test_per_task_artifact_cache_disabled_without_offline_cache_cpu.
  • Regression through the new default path (offline_cache=True): offline_cache 26, struct_for 14, ad_basics 54 (exercises eligibility-excluded adstack tasks), atomic 35, reduction 16, element_wise 16, listgen 2 — all pass.
  • Linters: black / ruff pass; clang-format clean; no lines > 120c.
  • CI: CUDA-on build + linux/macos/win/test-gpu + pyright + clang-tidy (local build was CUDA-off; the shared codegen.cpp change is a trivial gate widening with no CUDA code touched).

Made with Cursor

Extend the cross-process per-task artifact tier (6a) to the CPU backend. On a
cache miss the per-task module is compiled to a host relocatable object via
orc::SimpleCompiler and stored (object bytes + launch metadata) under the
task's IR key; on a hit the cached object is loaded straight into the ORC
object layer. Each task gets its own JITDylib (CPU analog of CUDA's
one-CUmodule-per-task), so per-task objects never collide on shared symbols
and no relink is needed.

- codegen.cpp: widen the artifact-tier + per-task build gates to arch_is_cpu
  (CPU only when the tier is on; else keeps the whole-kernel module).
- jit_cpu.cpp: JITSessionCPU::add_module_per_task fill+load site, JITModuleCPU
  multi-dylib resolve, host PIC object compile helper.
- cpu/kernel_launcher.cpp: take the per-task path when per_construct_artifacts
  is non-empty (mirror of the CUDA launcher).
- llvm_program.cpp: scope the per-task dir by host triple+CPU (as CUDA scopes
  by sm) so an NFS-shared cache never serves an incompatible host object.
- test_per_offload_cache.py: CPU cross-process reuse + disabled-tier tests.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7653c8f540

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread quadrants/runtime/cpu/jit_cpu.cpp Outdated
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

…(codex)

A decodable .qdb record whose object bytes are malformed (e.g. disk
corruption) reaches object_layer_.add, which parses eagerly; the previous
cantFail would abort the whole process on every launch through that cache
path. Raise a catchable QD_ERROR instead (mirroring the CUDA per-task load's
QD_ERROR_IF) and drop the offending entry so a later process recompiles and
refills it. Adds PerTaskArtifactCache::erase for the invalidate step.
@hughperkins

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8153378b71

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread quadrants/codegen/codegen.cpp Outdated
… (codex)

The per-task artifact cache is no longer CUDA-only; note that it also applies
to CPU (host object payload) and that it is scoped per target device.
@hughperkins

Copy link
Copy Markdown
Collaborator Author

@codex review

Comment thread quadrants/runtime/cpu/jit_cpu.cpp

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2e9ea9a02a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread quadrants/runtime/cpu/jit_cpu.cpp
…s rejected (codex)

On the corrupt-object error path, advance module_counter_ before creating the
dylib so the lingering (empty) dylib left behind after the throw can't collide
with a later per-task/whole-module name (which would fail createJITDylib).
Also erase the on-disk entry on both the hit and miss paths (either may have
written one), so a bad freshly-compiled object never poisons the cache.
@hughperkins

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 57d654cb76

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread quadrants/runtime/cpu/jit_cpu.cpp
…te (codex)

object_layer_.add only registers a materialization unit, so it catches object
parse errors but not a corrupt relocation / bad reference, which fails later
during linking -- at launch-time lookup, where no key is available to
invalidate the record. Force materialization right after add (resolve each
task's entry symbol in its self-contained dylib) so a deferred link failure is
caught while art.key is still in scope, erased, and raised catchably instead of
poisoning every future process.
@hughperkins

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: bda3807005

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

…argon

compile_module_to_object built the TargetMachine from the host CPU *name* with
an empty feature string, which selects that CPU model's default feature set --
a superset of what the running core may actually enable -- so the emitted
per-task object could use instructions the host lacks and crash with SIGILL at
kernel launch (seen on some CI runners). Build the target machine from
detectHost()'s JITTargetMachineBuilder instead, carrying the explicit detected
host features, exactly as the whole-kernel ConcurrentIRCompiler(JTMB) path does.

Also reword the init_options per-task cache note to drop undefined jargon
(PTX / compute capability) that failed the doc-quality check.
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

# Conflicts:
#	docs/source/user_guide/init_options.md
#	quadrants/codegen/codegen.cpp
#	quadrants/runtime/program_impls/llvm/llvm_program.cpp
#	tests/python/test_per_offload_cache.py
@hughperkins

Copy link
Copy Markdown
Collaborator Author

CI was green prior to merge

@hughperkins

hughperkins commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator Author

So we have:

  • codex review ok
  • CI green
  • check doc
  • check comment/code ratio
  • run genesis benchmarks (cpu could affect them)
  • run genesis unit tests (cpu could affet them)

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

@hughperkins

Copy link
Copy Markdown
Collaborator Author

Ci ~green

Comment thread docs/source/user_guide/init_options.md Outdated
Drop the parenthetical detailing per-backend payloads and per-target scoping
from the init_options per-task cache bullet.
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Shorten the per-task cache comments to only note the non-obvious bits
(one dylib per task, forced materialization, host-feature detection);
drop restatements of the code and cross-backend history.
Comment thread tests/python/test_per_offload_cache.py Outdated
# fill it, and it is gated on `offline_cache`. Reuse is reported on `PerOffloadCacheObservations.tasks_*` (-1 when the
# tier did not run).
# task's own IR (name-free), so a later process reuses an unchanged task instead of recompiling it. CUDA and AMDGPU fill
# it with GPU code and CPU (ref 7) with a host object; it is gated on `offline_cache`. Reuse is reported on

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont mention ref 7. No-one knows what that is.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agent says:

Done in 28dfae4 -- dropped "(ref 7)" from the comment. It now reads "... and CPU with a host object; ...".

Say "offline_cache is enabled" instead of "the tier is on" so the
comments are readable without knowing the internal cache vocabulary.
Clearer name for the flag that gates the per-task artifact cache.
Clearer name for the per-task cache eligibility flag.
…tion

Rename widened the first line, so re-indent the aligned continuation.
The comment should read without knowing internal PR numbering.
@hughperkins

Copy link
Copy Markdown
Collaborator Author

running genesis unit tets. on tests0

@hughperkins

Copy link
Copy Markdown
Collaborator Author

running gen bench on bench1

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

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