tiny.accy.artifact
Defined in tiny.accy.
API (78)
Actions
Public operations.
ArtifactJob.artifactPlanArtifactJob.copyArtifactPlanArtifactJob.copyKernelSummariesArtifactJob.deinitArtifactJob.fingerprint: A 64-bit hash of the plan's target profile, kind, format, slots, input and output ids, kernels and totals.ArtifactJob.initArtifactJob.kernelCountArtifactJob.kernelSummaryArtifactJob.kernelSummaryForWorkInputJob.createInputJob.destroyInputJob.plans: Returns pointers into this job's own fields: the program root, the target profile, and each restored plan.artifactPayloadByteCountartifactPlanFingerprintbuildKernelCallRegistryIndexcopyKernelSummarycreateArtifactJobFromTargetJobcreateBackendArtifactPlancreateBackendArtifactPlanFromPreparedModule: Rebuilds the plans inside the caller'sworkspacefrom the prepared module's stage records.createBackendArtifactPlanFromTargetJobcreateBackendMemoryPlandefaultArtifactFormatdeinitKernelCallRegistryIndexdeinitKernelCallShapeProfileduplicateKernelCallShapeProfilefindPipelinekernelCallRegistryFingerprintkernelCallShapeProfileEqlkernelSourcekernelSummariesEquallaunchGeometriesEquallaunchResourceClassNamelaunchResourcePlanFingerprintsummarizePlannedKernel
Types and contracts
Public types and contracts.
ArtifactJob: A heap-allocated holder of one artifact plan, the compiled kernels and the plan that describes them.ArtifactPlanOptionsBackendArtifactPlanBackendArtifactPlanSourceElementCountArgumentInputJob: Short-lived compile state rebuilt from the dispatch, memory, kernel, and target results of one finished preparation: the schedule plan, the buffer, memory-space and layout plans, the kernel outlines, the generated kernel programs, and the target settings.KernelCallArtifact: Records one prebuilt kernel in a registry, found by the triple of target name, for example "accy.kernel.linalg.matmul5x7x34x2f32", itsversion, and its artifact format, so compiled programs can call it by name.KernelCallDerivedLaunchKernelCallDerivedLaunchAxisKernelCallLaunchKernelCallPipeline: An ordered list of stages under one target name and version, so a caller describes a multi-kernel computation and hands it to the loader and launcher.KernelCallRegistryKernelCallRegistryIndexKernelCallRegistryIndexSlotKernelCallShapeProfileKernelCallShapeProfileBoundsKernelCallShapeProfileDimensionKernelSourceKernelSummariesKernelSummaryLaunchReductionKindLaunchResourceCandidateLaunchResourceClassLaunchResourcePlanLaunchTileKindLaunchTilePlanOwnedKernelCallPipelinePipelineIntermediatePipelineRuntimeScalarBoundPipelineScalarDerivationPipelineStagePipelineValueRefPlannedKernelPlannedKernelCompileContractPlannedKernelCompileLaunchPlannedKernelCompilePayloadPlannedKernelSourcePlannedSlot
Namespaces
Public namespaces.
fingerprintpipelineplansummarywire: A byte encoding for a table of prebuilt kernels and the chains of kernels that call them, with a writer that produces the bytes and a reader that checks them and builds the table again.
Values and defaults
Public values and defaults.
Source
Source: lib/accy/src/artifact/input.zig:27
zig
/// Short-lived compile state rebuilt from the dispatch, memory, kernel, and/// target results of one finished preparation: the schedule plan, the buffer,/// memory-space and layout plans, the kernel outlines, the generated kernel/// programs, and the target settings. A compiler of device code uses this to/// recover the plans of a finished compile inside memory the caller provides./// `create` allocates the job and all of its contents inside the caller's/// `workspace`, and a workspace that runs out gives `error.WorkExhausted`. The/// job requires each stage record to match: the target record must hold exactly/// one program root (`error.InvalidStageRoots`), and the dispatch, memory, and/// kernel records must decode to that same program/// (`error.IncompatibleStageImages`). The job keeps no pointer to the prepared/// module, no stage-record key, and no mutable semantic module. The job works/// out each kernel's legality for the target again from the restored plans and/// keeps that result with the rest. `destroy` releases the job's contents, and/// the workspace itself stays with the caller.pub const InputJob = struct { fixed: fixed.Tracked, context: ?*ir.Context = null, decoded: ?choir.bytecode.DecodedModule = null, target: ?records.codec.Decoded(records.target.Record) = null, schedule: ?preparation.schedule.SchedulePlanAnalysis = null, buffers: ?preparation.bufferization.BufferPlanAnalysis = null, spaces: ?preparation.memory.MemorySpacePlanAnalysis = null, layouts: ?preparation.layout.LayoutPlanAnalysis = null, outlines: ?preparation.kernelization.product.KernelOutlinePlanAnalysis = null, generated: ?preparation.kernelization.KernelizationAnalysis = null, legal: ?preparation.backend.BackendLegalizationAnalysis = null, pub fn create( workspace: []u8, prepared: *const Prepared, comptime configuration: Configuration, ) !*InputJob { return initialize(workspace, prepared, configuration) catch |err| { return if (err == error.OutOfMemory) error.WorkExhausted else err; }; } fn initialize( workspace: []u8, prepared: *const Prepared, comptime configuration: Configuration, ) !*InputJob { var initial = fixed.Tracked.init(workspace); const self = try initial.allocator().create(InputJob); self.* = .{ .fixed = initial }; errdefer self.destroy(); const allocator = self.fixed.allocator(); self.context = try ir.Context.create(allocator, configuration.context); const context = self.context.?; (try choir.product.recipe.decode(prepared.stage(.target).inputs().policy)).restore(context); try configuration.register(context); const image = try open(prepared, allocator, .target, configuration); defer image.destroy(); const root = image.root(0) orelse return error.InvalidStageRoots; if (image.root(1) != null) return error.InvalidStageRoots; self.decoded = try choir.bytecode.decodeModule(allocator, context, root.bytes); self.target = try records.codec.decode(allocator, records.target.Record, .target, image.stage()); clearTargetAttributes(self.decoded.?.module); inline for (.{ .dispatch, .memory, .kernel }) |stage| { try self.requireSameProgram(prepared, stage, configuration); } var references = try References.init(allocator, self.decoded.?.module, configuration.image.entities); defer references.deinit(); try self.restoreDispatch(prepared, &references, configuration); try self.restoreMemory(prepared, &references, configuration); try self.restoreKernel(prepared, &references, configuration); try self.restoreTarget(configuration); return self; } pub fn destroy(self: *InputJob) void { const allocator = self.fixed.allocator(); if (self.legal) |*value| value.deinit(); if (self.generated) |*value| value.deinit(); if (self.outlines) |*value| value.deinit(); if (self.layouts) |*value| value.deinit(); if (self.spaces) |*value| value.deinit(); if (self.buffers) |*value| value.deinit(); if (self.schedule) |*value| value.deinit(); if (self.target) |*value| value.deinit(); if (self.decoded) |*value| value.deinit(); if (self.context) |context| { context.deinit(allocator); allocator.destroy(context); } } /// Returns pointers into this job's own fields: the program root, the /// target profile, and each restored plan. A caller passes the returned /// plans to the artifact compiler. The pointers stay valid until `destroy` /// runs or the caller writes over the workspace. pub fn plans(self: *const InputJob) plan.PlanInputs { return .{ .root = self.decoded.?.module, .profile = self.target.?.value.profile, .schedule = &self.schedule.?, .buffers = &self.buffers.?, .spaces = &self.spaces.?, .layouts = &self.layouts.?, .outlines = &self.outlines.?, .generated = &self.generated.?, .legal = &self.legal.?, .target = &self.target.?.value, }; } fn requireSameProgram( self: *InputJob, prepared: *const Prepared, comptime stage: publication.Stage, comptime configuration: Configuration, ) !void { const allocator = self.fixed.allocator(); const image = try open(prepared, allocator, stage, configuration); defer image.destroy(); if (image.root(1) != null) return error.InvalidStageRoots; var context = try ir.Context.init(allocator, configuration.context); defer context.deinit(allocator); (try choir.product.recipe.decode(prepared.stage(stage).inputs().policy)).restore(&context); try configuration.register(&context); const root = image.root(0) orelse return error.InvalidStageRoots; var decoded = try choir.bytecode.decodeModule(allocator, &context, root.bytes); defer decoded.deinit(); clearTargetAttributes(decoded.module); choir.bytecode.qualification.compare(allocator, decoded.module, self.decoded.?.module, decoded.resources, self.decoded.?.resources, configuration.codec) catch |err| { return if (err == error.UnencodableProduct) error.IncompatibleStageImages else err; }; } fn restoreDispatch(self: *InputJob, prepared: *const Prepared, refs: *const References, comptime configuration: Configuration) !void { const allocator = self.fixed.allocator(); const image = try open(prepared, allocator, .dispatch, configuration); defer image.destroy(); var record = try records.codec.decode(allocator, records.dispatch.Record, .dispatch, image.stage()); defer record.deinit(); self.schedule = preparation.schedule.SchedulePlanAnalysis.init(allocator); const output = &self.schedule.?; copyCounters(output, record.value.schedule); for (record.value.schedule.work_items, 0..) |item, index| { const value = try project(preparation.schedule.ScheduleWorkItem, allocator, item, refs); try output.work_items.append(allocator, value); try output.root_to_item.putNoClobber(value.root, index); } } fn restoreMemory(self: *InputJob, prepared: *const Prepared, refs: *const References, comptime configuration: Configuration) !void { const allocator = self.fixed.allocator(); const image = try open(prepared, allocator, .memory, configuration); defer image.destroy(); var record = try records.codec.decode(allocator, records.memory.Record, .memory, image.stage()); defer record.deinit(); self.buffers = preparation.bufferization.BufferPlanAnalysis.init(allocator); self.spaces = preparation.memory.MemorySpacePlanAnalysis.init(allocator); self.layouts = preparation.layout.LayoutPlanAnalysis.init(allocator); const buffers = &self.buffers.?; const spaces = &self.spaces.?; const layouts = &self.layouts.?; copyCounters(buffers, record.value.buffers); copyCounters(spaces, record.value.spaces); copyCounters(layouts, record.value.layouts); for (record.value.buffers.slots) |item| { const value = try project(preparation.bufferization.BufferSlot, allocator, item, refs); try buffers.slots.append(allocator, value); } for (record.value.bindings) |binding| { const value = try refs.value(binding.value); try buffers.value_to_slot.putNoClobber(value, binding.slot_id); } for (record.value.buffers.elisions, 0..) |item, index| { const value = try project(preparation.bufferization.FusionElision, allocator, item, refs); try buffers.elisions.append(allocator, value); try buffers.value_to_elision.putNoClobber(value.value, index); } for (record.value.spaces.assignments, 0..) |item, index| { const value = try project(preparation.memory.MemorySpaceAssignment, allocator, item, refs); try spaces.assignments.append(allocator, value); try spaces.slot_to_assignment.putNoClobber(value.slot_id, index); } for (record.value.layouts.assignments, 0..) |item, index| { const value = try project(preparation.layout.LayoutAssignment, allocator, item, refs); try layouts.assignments.append(allocator, value); try layouts.slot_to_assignment.putNoClobber(value.slot_id, index); } } fn restoreKernel(self: *InputJob, prepared: *const Prepared, refs: *const References, comptime configuration: Configuration) !void { const allocator = self.fixed.allocator(); const image = try open(prepared, allocator, .kernel, configuration); defer image.destroy(); var record = try records.codec.decode(allocator, records.kernel.Record, .kernel, image.stage()); defer record.deinit(); self.outlines = preparation.kernelization.product.KernelOutlinePlanAnalysis.init(allocator); const output = &self.outlines.?; copyCounters(output, record.value.outlines); for (record.value.outlines.kernels) |item| { const value = try project(preparation.kernelization.product.KernelOutline, allocator, item, refs); try output.kernels.append(allocator, value); try output.work_to_kernel.putNoClobber(value.work_item_id, value.id); } } fn restoreTarget(self: *InputJob, comptime configuration: Configuration) !void { const allocator = self.fixed.allocator(); const source = self.target.?.value; const context = self.context.?; const root = self.decoded.?.module; if (source.profile) |profile| try preparation.setBackendTargetProfile(context, root, profile); if (source.generated_scan_schedules) |value| { try root.setAttr(preparation.target.generated_scan_schedule_attr_name, try context.getStringAttr(value)); } if (source.generated_row_pipeline_schedules) |value| { try root.setAttr(preparation.target.generated_row_pipeline_schedule_attr_name, try context.getStringAttr(value)); } self.generated = try preparation.kernelization.KernelizationAnalysis.init(allocator, configuration.context); const output = &self.generated.?; try output.reserveKernelCapacity(source.kernels.len); for (source.kernels, 0..) |item, index| { var value = try preparation.publication.restoreKernel(allocator, item.lowered, compilationConfiguration(configuration)); errdefer value.deinit(allocator); try output.work_to_kernel.putNoClobber(value.work_item_id, index); output.kernels.appendAssumeCapacity(value); } self.legal = preparation.backend.BackendLegalizationAnalysis.init(allocator, source.profile); const legal = &self.legal.?; for (self.outlines.?.kernels.items) |outline| { const result = try preparation.backend.legalizeKernel(outline, &self.buffers.?, source.profile); try legal.kernels.append(allocator, result); if (result.isLegal()) { legal.legal_kernel_count += 1; legal.total_static_bytes = try std.math.add(u64, legal.total_static_bytes, result.static_bytes); } else legal.illegal_kernel_count += 1; } }};Source: lib/accy/src/artifact/job.zig:22
zig
/// A heap-allocated holder of one artifact plan, the compiled kernels and the/// plan that describes them. A caller holds one of these between compiling a/// prepared program to device code and copying that code into a runnable/// program. `init` takes ownership of the plan and allocates the holder with/// the given allocator, and `deinit` frees the plan and then the holder. The/// holder lives only as long as the compile that made it and is never stored as/// a stage record. The holder answers kernel counts and per-kernel summaries by/// index or by work item, and it copies the plan or the summaries out for a/// caller to keep.pub const ArtifactJob = struct { allocator: std.mem.Allocator, artifact_plan: BackendArtifactPlan, pub fn init( allocator: std.mem.Allocator, artifact_plan: BackendArtifactPlan, ) !*ArtifactJob { const artifact_job = try allocator.create(ArtifactJob); errdefer allocator.destroy(artifact_job); artifact_job.* = .{ .allocator = allocator, .artifact_plan = artifact_plan, }; return artifact_job; } pub fn deinit(self: *ArtifactJob) void { self.artifact_plan.deinit(); const allocator = self.allocator; allocator.destroy(self); } /// A 64-bit hash of the plan's target profile, kind, format, slots, input /// and output ids, kernels and totals. A caller shows this number in /// reports or stamps it beside compiled output as a label, and no identity /// check or reuse decision compares it. pub fn fingerprint(self: *const ArtifactJob) u64 { return fingerprint_mod.artifactPlan(&self.artifact_plan); } pub fn kernelCount(self: *const ArtifactJob) usize { return self.artifact_plan.kernelCount(); } pub fn kernelSummary(self: *const ArtifactJob, kernel_index: usize) gpu.BackendError!artifact.KernelSummary { if (kernel_index >= self.artifact_plan.kernels.items.len) return error.InvalidArtifact; return try artifact.summarizePlannedKernel(self.artifact_plan.kernels.items[kernel_index]); } pub fn kernelSummaryForWork(self: *const ArtifactJob, work_item_id: usize) gpu.BackendError!artifact.KernelSummary { for (self.artifact_plan.kernels.items) |kernel| { if (kernel.work_item_id == work_item_id) return try artifact.summarizePlannedKernel(kernel); } return error.InvalidArtifact; } pub fn artifactPlan(self: *const ArtifactJob) *const BackendArtifactPlan { return &self.artifact_plan; } pub fn copyKernelSummaries(self: *const ArtifactJob, result_allocator: std.mem.Allocator) gpu.BackendError!artifact.KernelSummaries { const items = result_allocator.alloc(artifact.KernelSummary, self.artifact_plan.kernels.items.len) catch return error.OutOfMemory; var copied: usize = 0; errdefer { for (items[0..copied]) |summary| { result_allocator.free(summary.entry_name); } result_allocator.free(items); } for (items, self.artifact_plan.kernels.items) |*item, kernel| { item.* = try artifact.copyKernelSummary(result_allocator, try artifact.summarizePlannedKernel(kernel)); copied += 1; } return .{ .allocator = result_allocator, .items = items, }; } pub fn copyArtifactPlan(self: *const ArtifactJob, allocator: std.mem.Allocator) gpu.BackendError!BackendArtifactPlan { return try self.artifact_plan.copy(allocator); }};Source: lib/accy/src/artifact/job.zig:99
zig
pub fn createArtifactJobFromTargetJob( allocator: std.mem.Allocator, handle: gpu.BackendHandle, target_module: *target.TargetJob, options: ArtifactPlanOptions,) !*ArtifactJob { var artifact_plan = try plan.createBackendArtifactPlanFromTargetJob( allocator, handle, target_module, options, ); var plan_owned = true; errdefer if (plan_owned) artifact_plan.deinit(); const artifact_job = try ArtifactJob.init( allocator, artifact_plan, ); plan_owned = false; return artifact_job;}Source: lib/accy/src/artifact/root.zig
zig
pub const fingerprint = @import("fingerprint.zig");const model = @import("model/root.zig");pub const pipeline = model.pipeline;pub const plan = @import("plan.zig");pub const summary = @import("summary.zig");pub const wire = model.wire;const job = @import("job.zig");pub const product_name = "accy.artifact";pub const ArtifactPlanOptions = model.ArtifactPlanOptions;pub const BackendArtifactPlan = plan.BackendArtifactPlan;pub const ElementCountArgument = model.ElementCountArgument;pub const KernelCallArtifact = model.KernelCallArtifact;pub const KernelCallDerivedLaunch = model.KernelCallDerivedLaunch;pub const KernelCallPipeline = model.KernelCallPipeline;pub const OwnedKernelCallPipeline = model.OwnedKernelCallPipeline;pub const PipelineIntermediate = model.PipelineIntermediate;pub const PipelineRuntimeScalarBound = model.PipelineRuntimeScalarBound;pub const PipelineScalarDerivation = model.PipelineScalarDerivation;pub const PipelineStage = model.PipelineStage;pub const PipelineValueRef = model.PipelineValueRef;pub const findPipeline = model.findPipeline;pub const KernelCallDerivedLaunchAxis = model.KernelCallDerivedLaunchAxis;pub const KernelCallLaunch = model.KernelCallLaunch;pub const KernelCallRegistry = model.KernelCallRegistry;pub const KernelCallRegistryIndex = model.KernelCallRegistryIndex;pub const KernelCallRegistryIndexSlot = model.KernelCallRegistryIndexSlot;pub const KernelCallShapeProfile = model.KernelCallShapeProfile;pub const KernelCallShapeProfileBounds = model.KernelCallShapeProfileBounds;pub const KernelCallShapeProfileDimension = model.KernelCallShapeProfileDimension;pub const LaunchResourceCandidate = plan.LaunchResourceCandidate;pub const LaunchResourceClass = plan.LaunchResourceClass;pub const LaunchResourcePlan = plan.LaunchResourcePlan;pub const LaunchReductionKind = plan.LaunchReductionKind;pub const LaunchTileKind = plan.LaunchTileKind;pub const LaunchTilePlan = plan.LaunchTilePlan;pub const PlannedKernel = plan.PlannedKernel;pub const PlannedKernelCompileContract = plan.PlannedKernelCompileContract;pub const PlannedKernelCompileLaunch = plan.PlannedKernelCompileLaunch;pub const PlannedKernelCompilePayload = plan.PlannedKernelCompilePayload;pub const PlannedKernelSource = plan.PlannedKernelSource;pub const PlannedSlot = plan.PlannedSlot;pub const KernelSource = summary.KernelSource;pub const KernelSummary = summary.KernelSummary;pub const KernelSummaries = summary.KernelSummaries;pub const artifactPayloadByteCount = summary.artifactPayloadByteCount;pub const copyKernelSummary = summary.copyKernelSummary;pub const kernelSource = summary.kernelSource;pub const kernelSummariesEqual = summary.kernelSummariesEqual;pub const launchGeometriesEqual = summary.launchGeometriesEqual;pub const launchResourceClassName = summary.launchResourceClassName;pub const summarizePlannedKernel = summary.summarizePlannedKernel;pub const BackendArtifactPlanSource = plan.BackendArtifactPlanSource;pub const createBackendArtifactPlan = plan.createBackendArtifactPlan;pub const createBackendArtifactPlanFromTargetJob = plan.createBackendArtifactPlanFromTargetJob;pub const buildKernelCallRegistryIndex = model.buildKernelCallRegistryIndex;pub const createBackendMemoryPlan = plan.createBackendMemoryPlan;pub const defaultArtifactFormat = model.defaultArtifactFormat;pub const deinitKernelCallShapeProfile = model.deinitKernelCallShapeProfile;pub const deinitKernelCallRegistryIndex = model.deinitKernelCallRegistryIndex;pub const duplicateKernelCallShapeProfile = model.duplicateKernelCallShapeProfile;pub const artifactPlanFingerprint = fingerprint.artifactPlan;pub const kernelCallShapeProfileEql = model.kernelCallShapeProfileEql;pub const kernelCallRegistryFingerprint = fingerprint.kernelCallRegistry;pub const launchResourcePlanFingerprint = fingerprint.launchResourcePlan;pub const ArtifactJob = job.ArtifactJob;pub const createArtifactJobFromTargetJob = job.createArtifactJobFromTargetJob;pub const InputJob = @import("input.zig").InputJob;pub const createBackendArtifactPlanFromPreparedModule = plan.createBackendArtifactPlanFromPreparedModule;Source: lib/accy/src/root.zig:83
zig
pub const artifact = @import("artifact/root.zig");Audit
| Definitions | 17 |
|---|---|
| Public names | 17 |
| Members | 13 |
| Version | 26.7.0 |
| Revision | daab053ee433 |