tiny.tldr.parallel
Defined in tiny.tldr.
API (13)
Actions
Public operations.
BackgroundFailureSlotsWorkerArenaPool.allocatorWorkerArenaPool.deinitWorkerArenaPool.initchooseWorkersforChunksforItemsoverlapAvailablerangeStartsortItems
Types and contracts
Public types and contracts.
Values and defaults
Public values and defaults.
Source
Source: lib/tldr/src/parallel.zig
zig
const std = @import("std");const allocators = @import("alloc");const alloc_arena = @import("alloc_arena");const sys = @import("sys");const Allocator = std.mem.Allocator;const Arena = alloc_arena.Arena;pub const max_workers = 64;pub const WorkerArenaPool = struct { backing_owner: ?*allocators.LockedAllocator = null, arenas: []Arena = &.{}, pub fn init(storage: Allocator, worker_count: usize) !WorkerArenaPool { std.debug.assert(worker_count <= max_workers); const count = @max(worker_count, 1); std.debug.assert(count >= 1); std.debug.assert(count <= max_workers); const backing_owner = try storage.create(allocators.LockedAllocator); errdefer storage.destroy(backing_owner); backing_owner.* = allocators.LockedAllocator.init(storage); const arenas = try storage.alloc(Arena, count); for (arenas) |*arena| arena.* = Arena.init(backing_owner.allocator()); return .{ .backing_owner = backing_owner, .arenas = arenas }; } pub fn deinit(self: *WorkerArenaPool) void { std.debug.assert(self.backing_owner != null); std.debug.assert(self.arenas.len >= 1); const backing_owner = self.backing_owner.?; const storage = backing_owner.child; for (self.arenas) |*arena| arena.deinit(); storage.free(self.arenas); storage.destroy(backing_owner); self.* = .{}; } pub fn allocator(self: *WorkerArenaPool, worker: usize) Allocator { std.debug.assert(self.backing_owner != null); std.debug.assert(worker < self.arenas.len); return self.arenas[worker].allocator(); }};pub fn FailureSlots(comptime Failure: type) type { return struct { items: []Failure = &.{}, empty: Failure, const Self = @This(); pub fn init(storage: Allocator, slot_count: usize, empty: Failure) !Self { const count = @max(slot_count, 1); const items = try storage.alloc(Failure, count); for (items) |*item| item.* = empty; return .{ .items = items, .empty = empty }; } pub fn deinit(self: *Self, storage: Allocator) void { storage.free(self.items); self.* = .{ .empty = self.empty }; } pub fn record(self: *Self, worker: usize, failure: Failure) void { self.items[worker] = failure; } pub fn earliest( self: *const Self, comptime found: fn (Failure) bool, comptime before: fn (Failure, Failure) bool, ) ?Failure { var best: ?Failure = null; for (self.items) |item| { if (!found(item)) continue; if (best == null or before(item, best.?)) best = item; } return best; } };}const ChunkCallback = *const fn (*anyopaque, usize, usize, usize) void;const Job = struct { total: usize = 0, slots: usize = 0, context: *anyopaque = undefined, callback: ChunkCallback = undefined, background: bool = false, next_slot: usize = 0, pending: usize = 0, prev: ?*Job = null, next: ?*Job = null,};const Claim = struct { job: *Job, slot: usize,};const JobQueue = struct { head: ?*Job = null, tail: ?*Job = null, fn append(self: *JobQueue, job: *Job) void { job.prev = self.tail; job.next = null; if (self.tail) |tail| { tail.next = job; } else { self.head = job; } self.tail = job; } fn remove(self: *JobQueue, job: *Job) void { if (job.prev) |prev| { prev.next = job.next; } else { self.head = job.next; } if (job.next) |next| { next.prev = job.prev; } else { self.tail = job.prev; } job.prev = null; job.next = null; }};const WorkerPool = struct { mutex: sys.thread.Mutex = .{}, ready: sys.thread.Condition = .{}, done: sys.thread.Condition = .{}, worker_count: usize = 0, spawn_failed: bool = false, foreground: JobQueue = .{}, background: JobQueue = .{}, fn ensureStarted(self: *WorkerPool, desired_workers: usize) bool { if (desired_workers == 0) return false; self.mutex.lock(); defer self.mutex.unlock(); const desired = @min(desired_workers, max_workers - 1); while (self.worker_count < desired and !self.spawn_failed) { const handle = sys.thread.spawn(workerLoop, .{self}) catch { self.spawn_failed = true; break; }; self.worker_count += 1; handle.detach(); } return self.worker_count != 0; } fn submit(self: *WorkerPool, job: *Job, desired_workers: usize, reserved_slots: usize) bool { std.debug.assert(job.slots > reserved_slots); if (!self.ensureStarted(desired_workers)) return false; self.mutex.lock(); job.next_slot = reserved_slots; job.pending = job.slots; self.queueFor(job).append(job); self.ready.broadcast(); self.mutex.unlock(); return true; } fn queueFor(self: *WorkerPool, job: *Job) *JobQueue { return if (job.background) &self.background else &self.foreground; } fn claimAnyLocked(self: *WorkerPool) ?Claim { const job = self.foreground.head orelse self.background.head orelse return null; return self.claimFromLocked(job); } fn claimFromLocked(self: *WorkerPool, job: *Job) Claim { const slot = job.next_slot; job.next_slot += 1; if (job.next_slot == job.slots) self.queueFor(job).remove(job); return .{ .job = job, .slot = slot }; } fn runClaim(claim: Claim) void { const job = claim.job; const start = rangeStart(job.total, job.slots, claim.slot); const end = rangeStart(job.total, job.slots, claim.slot + 1); job.callback(job.context, claim.slot, start, end); } fn finishLocked(self: *WorkerPool, job: *Job) void { job.pending -= 1; if (job.pending == 0) self.done.broadcast(); } fn workerLoop(self: *WorkerPool) void { self.mutex.lock(); while (true) { if (self.claimAnyLocked()) |claim| { self.mutex.unlock(); runClaim(claim); self.mutex.lock(); self.finishLocked(claim.job); } else { self.ready.wait(&self.mutex); } } } fn wait(self: *WorkerPool, job: *Job) void { self.mutex.lock(); while (job.pending != 0) { if (job.next_slot < job.slots) { const claim = self.claimFromLocked(job); self.mutex.unlock(); runClaim(claim); self.mutex.lock(); self.finishLocked(job); } else { self.done.wait(&self.mutex); } } self.mutex.unlock(); } fn completeReserved(self: *WorkerPool, job: *Job) void { runClaim(.{ .job = job, .slot = 0 }); self.mutex.lock(); self.finishLocked(job); self.mutex.unlock(); self.wait(job); }};var global_worker_pool = WorkerPool{};pub fn overlapAvailable() bool { return sys.thread.threadsSupported() and sys.thread.cpuCount() > 1;}pub fn chooseWorkers(total: usize, requested: usize) usize { if (total <= 1 or !sys.thread.threadsSupported()) return 1; const available = sys.thread.cpuCount(); const ceiling = if (requested == 0) available else @min(available, requested); return @max(1, @min(@min(ceiling, total), max_workers));}pub fn rangeStart(total: usize, workers: usize, worker: usize) usize { const base = total / workers; const remainder = total % workers; return worker * base + @min(worker, remainder);}fn ChunkCallbackType( comptime Context: type, comptime body: fn (Context, usize, usize, usize) void,) type { return struct { fn run_opaque(opaque_context: *anyopaque, worker: usize, start: usize, end: usize) void { const typed_context: *Context = @ptrCast(@alignCast(opaque_context)); body(typed_context.*, worker, start, end); } };}pub fn forChunks( total: usize, requested_workers: usize, context: anytype, comptime body: fn (@TypeOf(context), usize, usize, usize) void,) void { const workers = chooseWorkers(total, requested_workers); if (workers <= 1) { body(context, 0, 0, total); return; } const Context: type = @TypeOf(context); const Callback: type = ChunkCallbackType(Context, body); var context_storage = context; var job = Job{ .total = total, .slots = workers, .context = @ptrCast(&context_storage), .callback = Callback.run_opaque, }; if (global_worker_pool.submit(&job, workers - 1, 1)) { global_worker_pool.completeReserved(&job); return; } var worker: usize = 0; while (worker < workers) : (worker += 1) { body( context, worker, rangeStart(total, workers, worker), rangeStart(total, workers, worker + 1), ); }}fn ItemStateType(comptime Context: type) type { return struct { user: Context, next: std.atomic.Value(usize) = std.atomic.Value(usize).init(0), total: usize, };}fn ItemCallbackType( comptime Context: type, comptime State: type, comptime body: fn (Context, usize, usize) void,) type { return struct { fn run(state: *State, worker: usize, start: usize, end: usize) void { _ = start; _ = end; while (true) { const item = state.next.fetchAdd(1, .monotonic); if (item >= state.total) break; body(state.user, worker, item); } } };}pub fn forItems( total: usize, requested_workers: usize, context: anytype, comptime body: fn (@TypeOf(context), usize, usize) void,) void { const workers = chooseWorkers(total, requested_workers); if (workers <= 1) { var item: usize = 0; while (item < total) : (item += 1) body(context, 0, item); return; } const Context: type = @TypeOf(context); const State: type = ItemStateType(Context); const Callback: type = ItemCallbackType(Context, State, body); var state = State{ .user = context, .total = total }; forChunks(workers, workers, &state, Callback.run);}pub fn Background( comptime Context: type, comptime body: fn (Context, usize) void,) type { return struct { job: Job = .{ .background = true }, context: Context = undefined, submitted: bool = false, const Self = @This(); pub fn submit(self: *Self, total: usize, requested_workers: usize, context: Context) void { std.debug.assert(!self.submitted); if (total == 0) return; self.context = context; self.job.total = total; self.job.slots = total; self.job.context = @ptrCast(self); self.job.callback = runOpaque; if (sys.thread.threadsSupported()) { const available = sys.thread.cpuCount(); const ceiling = if (requested_workers == 0) available else @min(available, requested_workers); const desired = @max(1, @min(@min(ceiling, total), max_workers)); if (global_worker_pool.submit(&self.job, desired, 0)) { self.submitted = true; return; } } var item: usize = 0; while (item < total) : (item += 1) body(context, item); } pub fn wait(self: *Self) void { if (!self.submitted) return; global_worker_pool.wait(&self.job); self.submitted = false; } fn runOpaque(opaque_context: *anyopaque, slot: usize, start: usize, end: usize) void { _ = start; _ = end; const self: *Self = @ptrCast(@alignCast(opaque_context)); body(self.context, slot); } };}fn SortChunkStateType(comptime T: type, comptime Context: type) type { return struct { items: []T, chunk: usize, user: Context, };}fn SortMergeStateType(comptime T: type, comptime Context: type) type { return struct { source: []T, target: []T, width: usize, user: Context, };}fn SortCallbacksType( comptime T: type, comptime Context: type, comptime SortState: type, comptime MergeState: type, comptime less: fn (Context, T, T) bool,) type { return struct { fn sort_chunk(state: *SortState, worker: usize, index: usize) void { _ = worker; const low = index * state.chunk; if (low >= state.items.len) return; const high = @min(low + state.chunk, state.items.len); std.sort.pdq(T, state.items[low..high], state.user, less); } fn merge_segment(state: *MergeState, worker: usize, index: usize) void { _ = worker; const low = index * 2 * state.width; if (low >= state.source.len) return; const middle = @min(low + state.width, state.source.len); const high = @min(low + 2 * state.width, state.source.len); merge_runs( state.user, state.source[low..middle], state.source[middle..high], state.target[low..high], ); } fn merge_runs(user: Context, left: []const T, right: []const T, out: []T) void { var left_index: usize = 0; var right_index: usize = 0; var out_index: usize = 0; while (left_index < left.len and right_index < right.len) : (out_index += 1) { if (less(user, right[right_index], left[left_index])) { out[out_index] = right[right_index]; right_index += 1; } else { out[out_index] = left[left_index]; left_index += 1; } } if (left_index < left.len) { @memcpy(out[out_index..], left[left_index..]); } else if (right_index < right.len) { @memcpy(out[out_index..], right[right_index..]); } } };}pub fn sortItems( comptime T: type, items: []T, context: anytype, comptime less: fn (@TypeOf(context), T, T) bool, scratch: []T, requested_workers: usize,) void { const workers = chooseWorkers(items.len, requested_workers); if (workers <= 1 or items.len < 2) { std.sort.pdq(T, items, context, less); return; } std.debug.assert(scratch.len >= items.len); const Context: type = @TypeOf(context); const SortState: type = SortChunkStateType(T, Context); const MergeState: type = SortMergeStateType(T, Context); const Callbacks: type = SortCallbacksType(T, Context, SortState, MergeState, less); const total = items.len; const chunk = (total + workers - 1) / workers; var sort_state = SortState{ .items = items, .chunk = chunk, .user = context }; forItems(workers, workers, &sort_state, Callbacks.sort_chunk); var source = items; var target = scratch[0..total]; var width = chunk; while (width < total) : (width *= 2) { const segments = (total + 2 * width - 1) / (2 * width); var merge_state = MergeState{ .source = source, .target = target, .width = width, .user = context, }; forItems(segments, workers, &merge_state, Callbacks.merge_segment); const swapped = source; source = target; target = swapped; } if (source.ptr != items.ptr) @memcpy(items, source);}fn lessUsize(_: void, left: usize, right: usize) bool { return left < right;}const U8HitsContext = struct { hits: []u8,};const U16HitsContext = struct { hits: []u16,};const SumContext = struct { sum: *usize,};const TestFailure = struct { found: bool = false, index: usize = 0,};const WorkerArenaPoolAllocationFailures = struct { fn run(storage: Allocator) !void { var pool = try WorkerArenaPool.init(storage, 4); defer pool.deinit(); _ = try pool.allocator(3).alloc(u8, 128); }};fn count_u8_chunks(context: U8HitsContext, _: usize, start: usize, end: usize) void { var index = start; while (index < end) : (index += 1) context.hits[index] += 1;}fn count_u16_chunks(context: U16HitsContext, _: usize, start: usize, end: usize) void { var index = start; while (index < end) : (index += 1) context.hits[index] += 1;}fn count_u8_item(context: U8HitsContext, _: usize, item: usize) void { context.hits[item] += 1;}fn count_u8_background_item(context: U8HitsContext, item: usize) void { context.hits[item] += 1;}fn failure_found(failure: TestFailure) bool { return failure.found;}fn failure_before(left: TestFailure, right: TestFailure) bool { return left.index < right.index;}const TestBackground = Background(U8HitsContext, count_u8_background_item);const chained_background_total = 128;const nested_parallel_inner_total = 64;const ChainedBackgroundContext = struct { hits: []u8, second: *TestBackground, second_hits: []u8,};fn start_chained_background(context: ChainedBackgroundContext, item: usize) void { context.hits[item] += 1; if (item == 0) { context.second.submit(chained_background_total, 2, .{ .hits = context.second_hits }); }}const ChainedBackground = Background(ChainedBackgroundContext, start_chained_background);fn count_nested_chunks(context: U8HitsContext, _: usize, start: usize, end: usize) void { var chunk = start; while (chunk < end) : (chunk += 1) { const offset = chunk * nested_parallel_inner_total; forItems(nested_parallel_inner_total, 2, U8HitsContext{ .hits = context.hits[offset..][0..nested_parallel_inner_total], }, count_u8_item); }}fn sum_chunk(context: SumContext, _: usize, start: usize, end: usize) void { context.sum.* += end - start;}test "parallel sort matches serial sort for total orders" { const allocator = std.testing.allocator; var prng = std.Random.DefaultPrng.init(0x74696e79736f7274); const random = prng.random(); for ([_]usize{ 0, 1, 2, 63, 4096, 40_001 }) |count| { const items = try allocator.alloc(usize, count); defer allocator.free(items); const expected = try allocator.alloc(usize, count); defer allocator.free(expected); const scratch = try allocator.alloc(usize, count); defer allocator.free(scratch); for (items, 0..) |*item, index| { item.* = random.uintLessThan(usize, 1 << 40) * 100_000 + index; } @memcpy(expected, items); std.sort.pdq(usize, expected, {}, lessUsize); sortItems(usize, items, {}, lessUsize, scratch, 8); try std.testing.expectEqualSlices(usize, expected, items); }}test "worker arena pool routes worker allocations through bounded caller storage" { var storage_bytes: [4096]u8 = undefined; var storage = std.heap.FixedBufferAllocator.init(&storage_bytes); var pool = try WorkerArenaPool.init(storage.allocator(), 4); defer pool.deinit(); var worker: usize = 0; while (worker < 4) : (worker += 1) { const bytes = try pool.allocator(worker).alloc(u8, 32); @memset(bytes, @intCast(worker + 1)); try std.testing.expect(storage.ownsSlice(bytes)); try std.testing.expectEqual(@as(u8, @intCast(worker + 1)), bytes[0]); } try std.testing.expectError( error.OutOfMemory, pool.allocator(0).alloc(u8, storage_bytes.len), );}test "worker arena pool cleans every caller storage allocation failure" { try std.testing.checkAllAllocationFailures( std.testing.allocator, WorkerArenaPoolAllocationFailures.run, .{}, );}test "forChunks covers every index exactly once" { const total = 10_000; var hits = @as([total]u8, @splat(0)); forChunks(total, 8, U8HitsContext{ .hits = &hits }, count_u8_chunks); for (hits) |hit| try std.testing.expectEqual(@as(u8, 1), hit);}test "forItems covers every item exactly once" { const total = 10_000; var hits = @as([total]u8, @splat(0)); forItems(total, 8, U8HitsContext{ .hits = &hits }, count_u8_item); for (hits) |hit| try std.testing.expectEqual(@as(u8, 1), hit);}test "failure slots merge earliest recorded failure" { var slots = try FailureSlots(TestFailure).init(std.testing.allocator, 4, .{}); defer slots.deinit(std.testing.allocator); slots.record(2, .{ .found = true, .index = 40 }); slots.record(1, .{ .found = true, .index = 11 }); const earliest = slots.earliest(failure_found, failure_before) orelse return error.MissingFailure; try std.testing.expectEqual(@as(usize, 11), earliest.index);}test "forChunks handles repeated pooled calls" { const total = 4096; const rounds = 8; var hits = @as([total]u16, @splat(0)); var round: usize = 0; while (round < rounds) : (round += 1) { forChunks(total, 8, U16HitsContext{ .hits = &hits }, count_u16_chunks); } for (hits) |hit| try std.testing.expectEqual(@as(u16, rounds), hit);}test "background job covers every item exactly once" { const total = 512; var hits = @as([total]u8, @splat(0)); var prefetch = TestBackground{}; prefetch.submit(total, 4, .{ .hits = &hits }); prefetch.wait(); for (hits) |hit| try std.testing.expectEqual(@as(u8, 1), hit);}test "background job runs alongside foreground chunk jobs" { const background_total = 256; const foreground_total = 4096; var background_hits = @as([background_total]u8, @splat(0)); var foreground_hits = @as([foreground_total]u8, @splat(0)); var prefetch = TestBackground{}; prefetch.submit(background_total, 2, .{ .hits = &background_hits }); var round: usize = 0; while (round < 4) : (round += 1) { forChunks(foreground_total, 8, U8HitsContext{ .hits = &foreground_hits }, count_u8_chunks); } prefetch.wait(); for (background_hits) |hit| try std.testing.expectEqual(@as(u8, 1), hit); for (foreground_hits) |hit| try std.testing.expectEqual(@as(u8, 4), hit);}test "background job may chain a following background job" { var first_hits = @as([1]u8, @splat(0)); var second_hits = @as([chained_background_total]u8, @splat(0)); var second = TestBackground{}; var first = ChainedBackground{}; first.submit(1, 2, .{ .hits = first_hits[0..1], .second = &second, .second_hits = &second_hits, }); first.wait(); second.wait(); try std.testing.expectEqual(@as(u8, 1), first_hits[0]); for (second_hits) |hit| try std.testing.expectEqual(@as(u8, 1), hit);}test "background job with zero items completes without submission" { var prefetch = TestBackground{}; prefetch.submit(0, 4, .{ .hits = &.{} }); prefetch.wait(); prefetch.wait();}test "nested parallel sections complete without stalling the pool" { const outer_chunks = 4; var hits = @as([(outer_chunks * nested_parallel_inner_total)]u8, @splat(0)); forChunks(outer_chunks, outer_chunks, U8HitsContext{ .hits = &hits }, count_nested_chunks); for (hits) |hit| try std.testing.expectEqual(@as(u8, 1), hit);}test "forChunks single worker runs inline over full range" { const total = 256; var sum: usize = 0; forChunks(total, 1, SumContext{ .sum = &sum }, sum_chunk); try std.testing.expectEqual(@as(usize, total), sum);}test "rangeStart partitions contiguously and totals correctly" { const total = 1003; const workers = 7; try std.testing.expectEqual(@as(usize, 0), rangeStart(total, workers, 0)); try std.testing.expectEqual(@as(usize, total), rangeStart(total, workers, workers)); var worker: usize = 0; while (worker < workers) : (worker += 1) { try std.testing.expect( rangeStart(total, workers, worker) <= rangeStart(total, workers, worker + 1), ); }}Source: lib/tldr/src/root.zig:60
zig
pub const parallel = @import("parallel.zig");Complete caller list for parallel.chooseWorkers
20 direct callers.
lib.tldr.src.formats.elf.archive.prefetch.prepareSummaries[function] — private source atlib/tldr/src/formats/elf/archive/prefetch.zig:169in nearest public ownerlib.tldr.src.formats.elf.archive.prefetchlib.tldr.src.formats.elf.archive.select.parseSelectedObjects[function] — private source atlib/tldr/src/formats/elf/archive/select.zig:389in nearest public ownerlib.tldr.src.formats.elf.archive.selecttiny.tldr.formats.elf.ehframe.Scan.prepare[method] atlib/tldr/src/formats/elf/ehframe/scan.zig:61tiny.tldr.formats.elf.ifunc.Collector.init[function] atlib/tldr/src/formats/elf/ifunc.zig:56tiny.tldr.formats.elf.image.symbols.appendExecutable[function] atlib/tldr/src/formats/elf/image/symbols.zig:54lib.tldr.src.formats.elf.layout.collect.assignChains[function] — private source atlib/tldr/src/formats/elf/layout/collect.zig:430in nearest public ownertiny.tldr.formats.elf.layout.collectlib.tldr.src.formats.elf.layout.collect.classify[function] — private source atlib/tldr/src/formats/elf/layout/collect.zig:174in nearest public ownertiny.tldr.formats.elf.layout.collectlib.tldr.src.formats.elf.link.requireResolvedRelocationSymbols[function] — private source atlib/tldr/src/formats/elf/link.zig:504in nearest public ownerlib.tldr.src.formats.elf.linklib.tldr.src.formats.elf.link.requireSupportedRelocations[function] — private source atlib/tldr/src/formats/elf/link.zig:410in nearest public ownerlib.tldr.src.formats.elf.linklib.tldr.src.formats.elf.merge.string.String.materialize[method] — private source atlib/tldr/src/formats/elf/merge/string.zig:95in nearest public ownerlib.tldr.src.formats.elf.merge.stringtiny.tldr.formats.elf.payload.copyAllocSections[function] atlib/tldr/src/formats/elf/payload.zig:183lib.tldr.src.formats.elf.payload.copyAllocSectionsParallelBySection[function] — private source atlib/tldr/src/formats/elf/payload.zig:218in nearest public ownertiny.tldr.formats.elf.payloadlib.tldr.src.formats.elf.relocation.application.materializeWorkers[function] — private source atlib/tldr/src/formats/elf/relocation/application.zig:970in nearest public ownertiny.tldr.formats.elf.relocation.applicationlib.tldr.src.formats.elf.relocation.application.relocationWorkers[function] — private source atlib/tldr/src/formats/elf/relocation/application.zig:754in nearest public ownertiny.tldr.formats.elf.relocation.applicationtiny.tldr.formats.elf.relocation.decode.parseRelocationsBySection[function] atlib/tldr/src/formats/elf/relocation/decode.zig:205tiny.tldr.formats.elf.symbol_table.collectGlobalSymbols[function] atlib/tldr/src/formats/elf/symbol.zig:20lib.tldr.src.incremental.format.validateRecords[function] — private source atlib/tldr/src/incremental/format.zig:312in nearest public ownerlib.tldr.src.incremental.formattiny.tldr.parallel.forChunks[function] atlib/tldr/src/parallel.zig:271tiny.tldr.parallel.forItems[function] atlib/tldr/src/parallel.zig:335tiny.tldr.parallel.sortItems[function] atlib/tldr/src/parallel.zig:475
Complete caller list for parallel.forChunks
9 direct callers.
lib.tldr.src.formats.elf.image.symbols.appendExecutableParallel[function] — private source atlib/tldr/src/formats/elf/image/symbols.zig:98in nearest public ownertiny.tldr.formats.elf.image.symbolslib.tldr.src.formats.elf.payload.copyBytes[function] — private source atlib/tldr/src/formats/elf/payload.zig:104in nearest public ownertiny.tldr.formats.elf.payloadtiny.tldr.formats.elf.relocation.decode.parseRelocationsBySection[function] atlib/tldr/src/formats/elf/relocation/decode.zig:205tiny.tldr.parallel.forItems[function] atlib/tldr/src/parallel.zig:335lib.tldr.src.parallel.test_background_job_runs_alongside_foreground_chunk_jobs[function] — test source atlib/tldr/src/parallel.zig:703in nearest public ownertiny.tldr.parallellib.tldr.src.parallel.test_forChunks_covers_every_index_exactly_once[function] — test source atlib/tldr/src/parallel.zig:658in nearest public ownertiny.tldr.parallellib.tldr.src.parallel.test_forChunks_handles_repeated_pooled_calls[function] — test source atlib/tldr/src/parallel.zig:683in nearest public ownertiny.tldr.parallellib.tldr.src.parallel.test_forChunks_single_worker_runs_inline_over_full_range[function] — test source atlib/tldr/src/parallel.zig:754in nearest public ownertiny.tldr.parallellib.tldr.src.parallel.test_nested_parallel_sections_complete_without_stalling_the_pool[function] — test source atlib/tldr/src/parallel.zig:747in nearest public ownertiny.tldr.parallel
Complete caller list for parallel.forItems
19 direct callers.
lib.tldr.src.formats.elf.archive.prefetch.prepareSummaries[function] — private source atlib/tldr/src/formats/elf/archive/prefetch.zig:169in nearest public ownerlib.tldr.src.formats.elf.archive.prefetchlib.tldr.src.formats.elf.archive.select.parseSelectedObjects[function] — private source atlib/tldr/src/formats/elf/archive/select.zig:389in nearest public ownerlib.tldr.src.formats.elf.archive.selecttiny.tldr.formats.elf.ehframe.Scan.prepare[method] atlib/tldr/src/formats/elf/ehframe/scan.zig:61tiny.tldr.formats.elf.ifunc.Collector.init[function] atlib/tldr/src/formats/elf/ifunc.zig:56lib.tldr.src.formats.elf.layout.collect.assignChains[function] — private source atlib/tldr/src/formats/elf/layout/collect.zig:430in nearest public ownertiny.tldr.formats.elf.layout.collectlib.tldr.src.formats.elf.layout.collect.classify[function] — private source atlib/tldr/src/formats/elf/layout/collect.zig:174in nearest public ownertiny.tldr.formats.elf.layout.collectlib.tldr.src.formats.elf.link.requireResolvedRelocationSymbols[function] — private source atlib/tldr/src/formats/elf/link.zig:504in nearest public ownerlib.tldr.src.formats.elf.linklib.tldr.src.formats.elf.link.requireSupportedRelocations[function] — private source atlib/tldr/src/formats/elf/link.zig:410in nearest public ownerlib.tldr.src.formats.elf.linklib.tldr.src.formats.elf.merge.string.String.materialize[method] — private source atlib/tldr/src/formats/elf/merge/string.zig:95in nearest public ownerlib.tldr.src.formats.elf.merge.stringlib.tldr.src.formats.elf.payload.copyAllocSectionsParallel[function] — private source atlib/tldr/src/formats/elf/payload.zig:269in nearest public ownertiny.tldr.formats.elf.payloadlib.tldr.src.formats.elf.payload.copyAllocSectionsParallelBySection[function] — private source atlib/tldr/src/formats/elf/payload.zig:218in nearest public ownertiny.tldr.formats.elf.payloadlib.tldr.src.formats.elf.relink.DirectRelocationContext.addProvenInputs[method] — private source atlib/tldr/src/formats/elf/relink.zig:907in nearest public ownertiny.tldr.formats.elf.relinklib.tldr.src.formats.elf.relocation.application.applyJobsParallel[function] — private source atlib/tldr/src/formats/elf/relocation/application.zig:772in nearest public ownertiny.tldr.formats.elf.relocation.applicationtiny.tldr.formats.elf.relocation.application.materialize[function] atlib/tldr/src/formats/elf/relocation/application.zig:896lib.tldr.src.formats.elf.symbol.collectGlobalSymbolRefsParallel[function] — private source atlib/tldr/src/formats/elf/symbol.zig:102in nearest public ownertiny.tldr.formats.elf.symbol_tablelib.tldr.src.incremental.format.validateRecords[function] — private source atlib/tldr/src/incremental/format.zig:312in nearest public ownerlib.tldr.src.incremental.formatlib.tldr.src.parallel.count_nested_chunks[function] — private source atlib/tldr/src/parallel.zig:593in nearest public ownertiny.tldr.paralleltiny.tldr.parallel.sortItems[function] atlib/tldr/src/parallel.zig:475lib.tldr.src.parallel.test_forItems_covers_every_item_exactly_once[function] — test source atlib/tldr/src/parallel.zig:665in nearest public ownertiny.tldr.parallel
Audit
| Definitions | 14 |
|---|---|
| Public names | 14 |
| Members | 2 |
| Version | 26.7.0 |
| Revision | daab053ee433 |