dataframe-operations-2.4.0.0: Column operations, expression DSL, and statistics for the dataframe ecosystem.
Safe HaskellNone
LanguageHaskell2010

DataFrame.Operations.JoinPar

Description

Parallel chunked-probe join kernels. The build side is indexed once into a shared, read-only CompactIndex (open-addressing, from DataFrame.Operations.Join); the probe side is split into caps contiguous row ranges and probed in parallel by forkIO workers (no sparks). Each worker makes two passes over its range — a count pass to size its slice, then a fill pass — and writes into the single shared output buffers at a precomputed prefix-sum offset. Because ranges are contiguous and laid out in range order, the produced (probeIxs, buildIxs) vectors are bit-for-bit identical to the sequential hashInnerKernel / hashLeftKernel: probe rows appear in original order and, within a probe row, build matches in ciSortedIndices order.

This is the parallel==sequential correctness gate (see testsOperationsParallelJoin.hs). A sequential fallback is used when there is a single capability or the probe side is below parJoinThreshold; the caller (innerJoin / leftJoin) decides via shouldParallelizeJoin.

Synopsis

Documentation

parInnerProbe :: Vector Int -> (Int -> (Int, Int)) -> Vector Int -> IO (Vector Int, Vector Int) Source #

Parallel inner-join probe. parInnerProbe sortedIdxs lookup probeHashes returns (probeIxs, buildIxs) identical to a sequential probe of the same index. The build index must already be constructed from the build side.

parLeftProbe :: Vector Int -> (Int -> (Int, Int)) -> Vector Int -> IO (Vector Int, Vector Int) Source #

Parallel left-join probe. Like parInnerProbe but every probe row emits at least one output row; unmatched rows carry a -1 sentinel in the build column.

shouldParallelizeJoin :: Int -> Int -> Bool Source #

Whether a join should take the parallel probe path: more than one capability, a probe side of at least parJoinThreshold rows, and a build side of at least parBuildThreshold rows (a small/hot index is faster probed sequentially).

shouldParallelizeSmallBuildProbe :: Int -> Bool Source #

Whether a small-build join (build below parBuildThreshold, so radix partitioning / sort-merge is not used) should take the parallel probe path: a very large probe side (at least parProbeThreshold) and more than one capability. The shared build index is read-only across threads, so probing it in parallel needs no synchronization. Independent of build size on purpose: the build is already tiny; the cost is the 1e7-row probe hashing, which parallelizes cleanly.

parJoinThreshold :: Int Source #

Below this many probe rows the fork/coordination overhead is not worth it; the caller uses its sequential ST kernel instead.

parBuildThreshold :: Int Source #

Below this many build rows the shared CompactIndex is small and hot, so the sequential hash probe is already memory-bound-fast and the fork overhead loses (measured: a 1e4-row Text-key build probed by 1e7 rows is slower in parallel). Parallelism only pays once the build index is large enough to spill cache — exactly the regime where sort-merge used to be chosen.

parProbeThreshold :: Int Source #

Above this many probe rows the probe-side row hashing and table lookups dominate the join, so partitioning the probe across cores wins even when the build side is small and cache-resident (the regime shouldParallelizeJoin deliberately leaves sequential). Sized at 1e6: below it the per-question gain is swamped by forkIOcoordination overhead, so smallmedium-inner joins stay sequential (measured). This is the small-build large-probe lever closing the medium-factor 1e7 join (1e7 probe x ~1e4 build).