Skip to content

Make the job the cache identity - #308

Closed
AntonOresten wants to merge 2 commits into
ao/code-ptx-sassfrom
ao/cached-results
Closed

AntonOresten wants to merge 2 commits into
ao/code-ptx-sassfrom
ao/cached-results

Conversation

@AntonOresten

Copy link
Copy Markdown
Collaborator

This follows up on the work queued in #302: a single value, TileJob, now identifies a compilation throughout inference, codegen, caching, launch, and reflection.

Previously, “which compilation?” was represented three incompatible ways:

  • (f, tt) in the compilation hook
  • CGOpts during codegen
  • TileCacheKey in the cache

These representations did not round-trip cleanly.

Design

  • TileJob contains a source MethodInstance, world age, and TileConfig.
  • TileConfig contains the target (SM architecture and bytecode version), parameters (compiler hints and const-seeded argument types), and kernel name.

Inference uses a single :cuTile CompilerCaching owner. Since cuTile inference depends on neither the target nor compiler hints, configurations of the same kernel share one inferred CodeInstance. Constant arguments remain separate const-seeded entries.

This removes the per-hint re-inference previously investigated in #95 and JuliaGPU/GPUCompiler.jl#917.

Codegen results are stored on the CodeInstance in CompilerCaching.results, keyed by TileConfig. Because the world age is represented by the selected CodeInstance rather than the config, unrelated world-age bumps do not rerun Tile IR generation or tileiras.

compile_or_lookup(job) is the cached entry point. It resolves a targetless job before lookup, ensuring the cache identity always includes the architecture of the stored CUBIN. compile(job) remains the uncached codegen path used by reflection and the compilation hook.

CUBINs continue to persist through the object cache added in #307. assemble calls ObjCache.get! using the same key fields and schema, and the cross-process cache harness has been ported to the job API.

Reflection now accepts jobs directly through both IO and stdout forms:

code_typed(job)
code_structured(job)
code_tiled(job)
code_ptx(job)
code_sass(job)

Removed

  • TileCacheKey
  • The version and hint pack/unpack codec
  • ensure_compiled
  • The cached emit_*! pipeline

CompilerCaching workaround

get_inferred currently reads the typed const-seeded entry directly.

CompilerCaching.get_source(ci, argtypes) selects the first CachedResult on a CodeInstance regardless of its result type. That is ambiguous here because inference results and TileResults share the same CodeInstance.

Tracked upstream as maleadt/CompilerCaching.jl#30. The workaround can be removed once CompilerCaching provides result-type-scoped source lookup.

Stacked on #302; the base is ao/code-ptx-sass, and only the final commit is new.

The suite is green against registry CompilerCaching 0.4.6. Locally, the updated branch passes 2,885 tests with one expected broken test on CompilerCaching 0.4.7.

AntonOresten and others added 2 commits September 6, 2026 16:13
A cuTile compilation is a `TileJob`: a MethodInstance and world, and a
`TileConfig` (target architecture and bytecode version, hints, const-seeded
argument types, kernel name). The job keys the results cache, is what the
`@device_code_*` hook reports, and is what the reflection entry points take.

Inference is partitioned by a single owner, `:cuTile`. cuTile's inference depends
on neither the target nor the hints — the interpreter takes only a world — so
every configuration of a kernel shares one CodeInstance, with const-seeded
arguments as `const_entries` on it; a Symbol is interned, so the owner is
identity-stable for Julia's inference engine. Codegen results (`CuTileResults`:
CUBIN and per-context kernels) are stored on that CodeInstance per config, so
they survive world bumps and persist into package images with it.
`compile_or_lookup(job)` runs `compile(job)` on a miss, under a lock.

This replaces cuTile's own cache layer — `TileCacheKey`, the `CacheView`
results plumbing, `ensure_compiled` and the cached `emit_*!` chain — and with it
the per-hint re-inference that layer caused. Reflection and launches now share
one inference partition, so `@device_code_typed` no longer re-infers.

`get_inferred` reads its const-specialized entry directly: CompilerCaching's
`get_source(ci, argtypes)` takes the first `CachedResult` on the CodeInstance
whatever its results type, and `TileResults` is attached to the same one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNHajvrhhKBBUF7w6cDiKr
@maleadt

maleadt commented Sep 8, 2026

Copy link
Copy Markdown
Member

#311

@maleadt maleadt closed this Sep 8, 2026
@AntonOresten
AntonOresten deleted the ao/cached-results branch September 8, 2026 16:23
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.

2 participants