Skip to content

SKEEP-005: schedules — structured concurrency for compute, parallel SDPA, compile-lane metadata - #1262

Merged
michalharakal merged 4 commits into
developfrom
feature/skeep-005-schedules
Sep 4, 2026
Merged

michalharakal merged 4 commits into
developfrom
feature/skeep-005-schedules

Conversation

@michalharakal

Copy link
Copy Markdown
Contributor

Summary

SKEEP-005 — structured concurrency as a schedule on the execution context, in the spirit of Halide's algorithm/schedule split. The DSL describes what a network computes; a Schedule decides how independent work is mapped onto cores. No schedule vocabulary enters network {}; results are bit-identical to the sequential path; a request that cannot be honoured is visibly downgraded (trace event), never silently approximated.

Design record: docs/modules/skeep/pages/005-schedules-structured-concurrency.adoc (rendered in the Antora site under SKEEP → 005).

Engine (skainet-lang-core, skainet-backend-cpu)

  • sk.ainet.context.schedule.Schedule — dependency-free contract (forRange(n, grain) { start, end -> }, Sequential, tasksFor/chunkFor), ScheduleHint + SCHEDULE_ATTRIBUTE_KEY.
  • ExecutionContext.schedule (default Sequential) and withSchedule(...); ScheduledExecutionContext rebuilds ops on the same seam as withTensorDataFactory.
  • TraceEvent.ScheduleDowngraded / ScheduleRegion (Perfetto + Android sinks).
  • JVM CoroutineSchedule (runBlocking + coroutineScope, caller runs the first chunk, nested regions inline, fail-one-cancels-all, hardware(), dedicated()); platformDefaultSchedule() = hardware on the JVM, Sequential elsewhere.
  • parallelChunks and the Panama Q4_K / Q5_K / FP32 kernels take the schedule (additive SPI overloads); DirectCpuExecutionContext(schedule = …) secondary constructor, DefaultCpuOps*(dataFactory, schedule).
  • First consumer: scaledDotProductAttention parallel over (batch, head) with SDPA_PARALLEL_MIN_WORK keeping tiny decode calls inline.

Compile lane (skainet-lang-dag, skainet-compile-opt, skainet-compile-hlo)

  • dag { schedule(parallel("heads")) { … } } / op(…, schedule = …) → node attribute skainet.schedule.
  • ScheduleAnnotationPass validates dims per op, stamps GraphNode.metadata, rejects with diagnostics; wired as a core pass.
  • StableHLO module header gains skainet.schedule = {…} beside skainet.tensor_layouts. IREE consumption is out of scope.

Thread-safety prerequisites

  • KernelDispatch / KernelRegistry: volatile immutable snapshots, synchronized registration (JvmSynchronized optional-expectation annotation for common code).

Docs

  • Explanation Algorithm and schedule, tutorial Schedule getting started backed by the executable ScheduleDemo sample (SamplesTest asserts bit-identity across schedules), dsl-principles table row, CHANGELOG.

Numbers (i7-9750H 6c/12t, JDK 25)

SdpaScheduleBench, hardware vs sequential: 3.4–4.8× on prefill shapes (seqQ 64), 2.0–2.7× on single-query decode; e.g. 32 heads × 4096 keys × 64 queries 2,859 ms → 836 ms. Downstream (SKaiNET-transformers per-head attention on this API): attn.fused_compute 8.99 s → 2.59 s at 512 ctx, Daily-StandAPP 3B decode 1.9 → 3.0 tok/s with byte-identical greedy output.

Verification

  • scripts/pr-gate.sh full: all legs passed (JVM, apiCheck, JS/Wasm browser, linuxX64, assemble, Java consumer, tool tests, Android host).
  • API dumps refreshed for lang-core, backend-cpu, lang-dag, compile-opt, compile-hlo, compile-dag — additive only, no removed lines.
  • Antora site builds without errors.

Related

🤖 Generated with Claude Code

michalharakal and others added 4 commits September 3, 2026 22:28
…SDPA

Compute-level half of the Halide-style algorithm/schedule split.

- skainet-lang-core: `sk.ainet.context.schedule.Schedule` (non-suspending,
  dependency-free; `forRange` contract: disjoint ranges, no allocation through
  a context in bodies, nested regions inline, first failure cancels siblings)
  with `Schedule.Sequential`; `ScheduleHint` + `SCHEDULE_ATTRIBUTE_KEY` for the
  compile lane; `ExecutionContext.schedule` / `withSchedule` (default emits
  `TraceEvent.ScheduleDowngraded` — an unhonoured request is visible, never
  silent); `ScheduledExecutionContext` decorator mirroring
  `ScopedExecutionContext`; `TraceEvent.ScheduleRegion`.
- skainet-backend-api: registries safe for concurrent reads (volatile
  snapshots, serialized writes via an optional-expectation `JvmSynchronized`);
  schedule-aware overloads on the Q4_K/Q5_K kernel SPIs.
- skainet-backend-cpu: `CoroutineSchedule` (structured `coroutineScope`,
  caller runs the first chunk, nested regions inline, `dedicated()` pool);
  `parallelChunks(outputDim, schedule)` replaces the runBlocking island;
  ops carry the schedule (`DefaultCpuOpsBase(dataFactory, schedule)`),
  `platformDefaultSchedule()` (JVM: hardware coroutines, others: Sequential),
  `DirectCpuExecutionContext(schedule = …)` + `withSchedule`;
  `scaledDotProductAttention` runs its (batch, head) units on the schedule
  with per-task scratch — bit-identical to the sequential loop, tiny calls
  stay inline (`SDPA_PARALLEL_MIN_WORK`).
- Tests: ScheduledExecutionContextTest, KernelDispatchConcurrencyTest,
  CoroutineScheduleTest, DirectCpuExecutionContextScheduleTest,
  SdpaScheduleParityTest (common) + SdpaCoroutineParityTest; JMH
  SdpaScheduleBench. API dumps refreshed (additive).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018sqoaGs5M7C5uVw6cpzAnH
…eHLO header

- skainet-lang-dag: `op(..., schedule = parallel("rows"))`, `schedule(hint) { … }`
  ambient block (new `DagBuilder.withAttributes`), `GraphNodeDefinition.scheduleHint()`
  — same channel as `DtypePolicyDsl`.
- skainet-compile-opt: `ScheduleAnnotationPass` validates requested dims per op
  (sdpa: batch/heads, matmul: rows, conv: batch/out_channels), stamps the
  normalized hint into `GraphNode.metadata`, rejects unknown dims with a
  diagnostic (never silently), optional per-op defaults; idempotent.
- skainet-compile-hlo: `HloGenerator` runs the pass as a core pass with a
  target; `StableHloConverter` emits `skainet.schedule = {<node> = {parallel_dims
  = [...], parallelism = N}}` in the module header beside `skainet.tensor_layouts`.
  No per-op emitter; IREE-side consumption is out of scope.
- Tests: ScheduleDslTest, ScheduleAnnotationPassTest, ScheduleModuleAttributeTest.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018sqoaGs5M7C5uVw6cpzAnH
…torial with executable sample

- SKEEP-005 (Status: Implemented) in docs/modules/skeep, registered in nav and the
  Current Proposals table; references #1259/#1260 (fixed) and #1261 (observed).
- explanation/schedules.adoc: principle, the Schedule contract, where it hangs,
  what runs where per platform, how to see which schedule ran, the compile lane.
  dsl-principles.adoc gains the "Schedule" row in "Who answers which question".
- tutorials/schedule-getting-started.adoc backed by ScheduleDemo.kt in the
  executable samples (SamplesTest asserts bit-identity and the recorded region).
- CHANGELOG Unreleased entry.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018sqoaGs5M7C5uVw6cpzAnH
- SKEEP-005 page gains a Measurements section: SdpaScheduleBench (hardware
  schedule 3.4-4.8x on prefill shapes, 2.0-2.7x on single-query decode) and
  the downstream transformers profile (attn.fused_compute 8.99 s -> 2.59 s,
  decode 7.7 -> 9.7 tok/s, greedy tokens identical).
- skainet-compile-dag API dump: the two default members ExecutionContext
  gained (schedule, withSchedule) surface on GraphExecutionContext; additive.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018sqoaGs5M7C5uVw6cpzAnH
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown

📖 Documentation Preview

The documentation has been built successfully for this PR.

Generated Files:

  • Operator documentation: docs/modules/operators/_generated_/
  • JSON schema output: operators.json

Artifacts:

  • Download the documentation-preview-1262 artifact to view the complete documentation locally.

This comment will be updated automatically when the PR is updated.

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