Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 8 additions & 41 deletions src/bound_law.jl
Original file line number Diff line number Diff line change
Expand Up @@ -75,23 +75,6 @@ function MutableRelationStorage(storage; generation, status = nothing,
validated_generations, Int(slot))
end

@kernel function _initialize_allocated_storage_kernel!(destination, value)
index = @index(Global, Linear)
index <= length(destination) && (@inbounds destination[index] = value)
end

function _allocate_array(backend, ::Type{T}, shape::Tuple) where {T}
return KernelAbstractions.allocate(backend, T, shape)
end

function _initialize_allocated_storage!(backend, destination, value)
isempty(destination) && return destination
kernel = _initialize_allocated_storage_kernel!(backend)
kernel(destination, value; ndrange = length(destination))
KernelAbstractions.synchronize(backend)
return destination
end

function _copy_allocated_array(backend, source::AbstractArray)
destination = _allocate_array(backend, eltype(source), size(source))
copyto!(destination, source)
Expand Down Expand Up @@ -302,19 +285,6 @@ function _collect_allocation_schema(law::LocalLaw, collection::Collection)
return first(schemas)
end

function _filled_int32_storage(backend, length::Int, value::Int32)
storage = _allocate_array(backend, Int32, (length,))
return _initialize_allocated_storage!(backend, storage, value)
end

function _filled_uint64_storage(backend, length::Int, value::UInt64)
storage = _allocate_array(backend, UInt64, (length,))
return _initialize_allocated_storage!(backend, storage, value)
end

_zeroed_int32_storage(backend, length::Int) =
_filled_int32_storage(backend, length, Int32(0))

function _collection_allocation(
law::LocalLaw, collection::Collection, request::Allocate, backend,
)
Expand All @@ -325,17 +295,14 @@ function _collection_allocation(
))
schema = _collect_allocation_schema(law, collection)
capacity = Int(collection.capacity)
records = _allocate_compacted_records(backend, eltype(collection), capacity)
count = _zeroed_int32_storage(backend, 1)
segment_starts = schema.grouped ? (
_filled_int32_storage(backend, schema.groups + 1, Int32(1))
) : nothing
source_item = _zeroed_int32_storage(backend, capacity)
source_lane = _zeroed_int32_storage(backend, capacity)
source_position = schema.persistent_source_positions ?
_zeroed_int32_storage(backend, schema.source_position_count) : nothing
return CompactedStorage(_CONSTRUCTION_TOKEN, records, count,
segment_starts, source_item, source_lane, source_position)
return CompactedStorage(
backend,
eltype(collection),
capacity;
group_count = schema.grouped ? schema.groups : nothing,
source_items = schema.source_position_count,
source_position = schema.persistent_source_positions,
)
end

function _append_fold_state_requirements!(fields, law::OrderedFold)
Expand Down
46 changes: 41 additions & 5 deletions src/compacted.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,36 @@ struct _PersistentSourcePosition end

const _COMPACTED_MAX_ORDINAL = Int32(typemax(Int32) - 1)

@kernel function _initialize_allocated_storage_kernel!(destination, value)
index = @index(Global, Linear)
index <= length(destination) && (@inbounds destination[index] = value)
end

function _allocate_array(backend, ::Type{T}, shape::Tuple) where {T}
return KernelAbstractions.allocate(backend, T, shape)
end

function _initialize_allocated_storage!(backend, destination, value)
isempty(destination) && return destination
kernel = _initialize_allocated_storage_kernel!(backend)
kernel(destination, value; ndrange = length(destination))
KernelAbstractions.synchronize(backend)
return destination
end

function _filled_int32_storage(backend, length::Int, value::Int32)
storage = _allocate_array(backend, Int32, (length,))
return _initialize_allocated_storage!(backend, storage, value)
end

function _filled_uint64_storage(backend, length::Int, value::UInt64)
storage = _allocate_array(backend, UInt64, (length,))
return _initialize_allocated_storage!(backend, storage, value)
end

_zeroed_int32_storage(backend, length::Int) =
_filled_int32_storage(backend, length, Int32(0))

"""
BoundedGroupView{K,T}

Expand Down Expand Up @@ -108,6 +138,12 @@ either `nothing` or a device `Int32[G+1]` directory, and `source_item` plus
`source_lane` retain provenance. `source_position` is present only when a
typed downstream request demands that projection. This value is not an
`AbstractArray`; its inactive record tail has no value semantics.

`CompactedStorage(backend, T, capacity; group_count=nothing,
source_items=capacity, source_position=false)` constructs a logically empty
store. The count and provenance arrays start at zero and a grouped directory
starts at one. Construction is a cold, synchronized storage operation; no
initialization work survives into planning or execution.
"""
struct CompactedStorage{R, C, S, I, L, P}
records::R
Expand Down Expand Up @@ -218,13 +254,13 @@ function CompactedStorage(
group_count === nothing || (group_count isa Integer && !(group_count isa Bool) &&
group_count >= 0) || throw(ArgumentError(
"group_count must be a nonnegative integer or nothing"))
count = KernelAbstractions.allocate(backend, Int32, (1,))
count = _zeroed_int32_storage(backend, 1)
segments = group_count === nothing ? nothing :
KernelAbstractions.allocate(backend, Int32, (Int(group_count) + 1,))
source_item = KernelAbstractions.allocate(backend, Int32, (Int(capacity),))
source_lane = KernelAbstractions.allocate(backend, Int32, (Int(capacity),))
_filled_int32_storage(backend, Int(group_count) + 1, Int32(1))
source_item = _zeroed_int32_storage(backend, Int(capacity))
source_lane = _zeroed_int32_storage(backend, Int(capacity))
projection = source_position ?
KernelAbstractions.allocate(backend, Int32, (Int(source_items),)) : nothing
_zeroed_int32_storage(backend, Int(source_items)) : nothing
return CompactedStorage(_CONSTRUCTION_TOKEN,
_allocate_compacted_records(backend, T, Int(capacity)), count, segments,
source_item, source_lane, projection)
Expand Down
18 changes: 18 additions & 0 deletions test/metal/localmath_authoring.jl
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,24 @@ struct LocalMathMetalNode end
@test Array(LocalMath.storage(rejected_fold, fold_output)) ==
Float32[-1, -1]

fresh = LocalMath.CompactedStorage(
backend, Int32, 3;
group_count = 2, source_items = 6, source_position = true)
@test Array(fresh.count) == Int32[0]
@test Array(fresh.segment_starts) == Int32[1, 1, 1]
@test Array(fresh.source_item) == zeros(Int32, 3)
@test Array(fresh.source_lane) == zeros(Int32, 3)
@test Array(fresh.source_position) == zeros(Int32, 6)
empty_fresh = LocalMath.CompactedStorage(
backend, Int32, 0;
group_count = 0, source_items = 0, source_position = true)
@test Array(empty_fresh.count) == Int32[0]
@test Array(empty_fresh.segment_starts) == Int32[1]
@test isempty(empty_fresh.records)
@test isempty(empty_fresh.source_item)
@test isempty(empty_fresh.source_lane)
@test isempty(empty_fresh.source_position)

records = LocalMath.Collection(Int32, 3)
collected = LocalMath.@localmath item ∈ source begin
records[item] = bounded_collect(Int32(item); maximum = 1,
Expand Down
20 changes: 16 additions & 4 deletions test/test_stage_collection_binding.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,23 @@ end
@testset "Collection and OrderedFold structural Stage boundary" begin
backend = KernelAbstractions.CPU()
allocated = LMCB.CompactedStorage(
backend, Int32, 4; group_count = 2, source_position = true)
backend, Int32, 4;
group_count = 2, source_items = 6, source_position = true)
@test length(allocated.records) == 4
@test length(allocated.count) == 1
@test length(allocated.segment_starts) == 3
@test length(allocated.source_position) == 4
@test allocated.count == Int32[0]
@test allocated.segment_starts == Int32[1, 1, 1]
@test allocated.source_item == zeros(Int32, 4)
@test allocated.source_lane == zeros(Int32, 4)
@test allocated.source_position == zeros(Int32, 6)
empty_allocated = LMCB.CompactedStorage(
backend, Int32, 0;
group_count = 0, source_items = 0, source_position = true)
@test isempty(empty_allocated.records)
@test empty_allocated.count == Int32[0]
@test empty_allocated.segment_starts == Int32[1]
@test isempty(empty_allocated.source_item)
@test isempty(empty_allocated.source_lane)
@test isempty(empty_allocated.source_position)
nodes = LMCB.Space(SCBNode, 3)

collection = LMCB.Collection(Int32, 4)
Expand Down
12 changes: 12 additions & 0 deletions test/test_storage_authoring.jl
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,19 @@ end
@test size(collection_storage.count) == (1,)
@test size(collection_storage.segment_starts) == (3,)
@test collection_storage.segment_starts == ones(Int32, 3)
@test collection_storage.count == Int32[0]
@test collection_storage.source_item == zeros(Int32, 3)
@test collection_storage.source_lane == zeros(Int32, 3)
@test collection_storage.source_position === nothing
direct_collection_storage = LMA.CompactedStorage(
backend, Int32, 3; group_count = 2)
@test direct_collection_storage.count == collection_storage.count
@test direct_collection_storage.segment_starts ==
collection_storage.segment_starts
@test direct_collection_storage.source_item ==
collection_storage.source_item
@test direct_collection_storage.source_lane ==
collection_storage.source_lane
prepared_collection = LMA.prepare(
LMA.plan(collection_bound; backend))
wait(LMA.execute!(prepared_collection))
Expand Down