cuSBF
Loading...
Searching...
No Matches
Namespaces | Classes | Concepts | Typedefs | Enumerations | Functions | Variables
cusbf::detail Namespace Reference

Namespaces

namespace  xxhash
 XXHash_64 implementation from.
 

Classes

struct  BitwiseOr
 Device functor for bitwise OR reduction (CUB WarpReduce). More...
 
class  ChunkStreamPair
 Two non-blocking CUDA streams for overlapping chunk H2D and kernel work. More...
 
struct  cuda_free_memory
 Driver-reported free device memory (bytes available for new allocations). More...
 
struct  DensePackedKmerInput
 Device-side view of a dense packed symbol sequence. More...
 
class  FastxBufferReader
 FASTA/FASTQ parser over a contiguous in-memory buffer. More...
 
class  FastxFileBuffer
 Read-only contiguous file payload for in-memory FASTX parsing. More...
 
class  FastxPinnedSequenceBuffer
 Page-locked host buffer for fused FASTX normalize + H2D staging. More...
 
class  FastxPipelineReleaseGuard
 
class  FastxPipelineState
 
class  FastxReader
 Streaming FASTA/FASTQ parser. More...
 
struct  FastxRecord
 A single sequence record extracted from a FASTA/FASTQ stream. More...
 
class  GzIstream
 std::istream adapter for GzStreambuf. More...
 
class  GzStreambuf
 std::streambuf over a gzip file (zlib gzread). More...
 
class  QueryLayout
 
struct  QueryLayoutRecord
 
struct  SaltLiteral
 
struct  SaltLiteral< 0 >
 
struct  SaltLiteral< 1 >
 
struct  SaltLiteral< 10 >
 
struct  SaltLiteral< 11 >
 
struct  SaltLiteral< 12 >
 
struct  SaltLiteral< 13 >
 
struct  SaltLiteral< 14 >
 
struct  SaltLiteral< 15 >
 
struct  SaltLiteral< 2 >
 
struct  SaltLiteral< 3 >
 
struct  SaltLiteral< 4 >
 
struct  SaltLiteral< 5 >
 
struct  SaltLiteral< 6 >
 
struct  SaltLiteral< 7 >
 
struct  SaltLiteral< 8 >
 
struct  SaltLiteral< 9 >
 
struct  SequenceKmerInput
 Device-side view of an encoded sequence for k-mer / s-mer counting. More...
 

Concepts

concept  cusbf_result_like
 
concept  fastx_dispatch_handler
 Handler invoked by dispatch_fastx_file with either reader type and a dispatch path.
 

Typedefs

template<typename Handler >
using fastx_dispatch_handler_result_t = std::invoke_result_t< Handler &, FastxReader &, fastx_dispatch_path >
 Return type of a fastx_dispatch_handler when invoked with a stream reader.
 

Enumerations

enum class  fastx_chunk_mode { insert , query }
 FASTX mode used to size GPU staging buffers. More...
 
enum class  fastx_dispatch_path { single_chunk_stream , single_chunk_mmap , chunked_mmap , chunked_stream }
 How a FASTX file is read and chunked for GPU processing. More...
 
enum class  FastxFormat : uint8_t { unknown , fasta , fastq }
 Detected file format for a FASTA/FASTQ stream. More...
 

Functions

template<typename T >
consteval uint64_t validByteCount ()
 
template<typename T >
consteval bool separatorPositionAlwaysEncodesInvalid (char *input, uint64_t separatorPosition, uint64_t index)
 Recursively tests whether placing the separator byte at any position in an input of valid bytes always results in an invalid encoding.
 
template<typename T >
consteval bool separatorByteAlwaysEncodesInvalid ()
 Tests that for every position in the input, placing the separator byte at that position always results in an invalid encoding.
 
template<typename Config >
__global__ void count_positive_kmers_per_record_kernel (const uint8_t *hits, const QueryLayoutRecord *records, uint64_t *positive_kmers_out, uint64_t record_count)
 Per-record kernel: sums hits[hit_offset ..] for each QueryLayoutRecord.
 
template<typename Config >
uint64_t count_positive_kmers_total (device_span< const uint8_t > hits, cuda::stream_ref stream)
 Device-wide count of set bits in a per-k-mer hit buffer.
 
template<typename Config >
Result< voidcount_positive_kmers_per_record (device_span< const uint8_t > hits, device_span< const QueryLayoutRecord > records, device_span< uint64_t > positive_kmers_out, cuda::stream_ref stream)
 Fills positive_kmers_out with per-record positive k-mer counts.
 
template<typename Config >
constexpr uint64_t dense_packed_symbols_per_word ()
 Encoded symbols stored in each uint64_t word for Config.
 
template<typename Config >
constexpr uint64_t dense_packed_word_count (uint64_t num_symbols)
 Returns the number of uint64_t words required for num_symbols encoded symbols.
 
template<typename Config >
constexpr uint64_t dense_packed_kmer_count (uint64_t num_symbols)
 Returns the number of k-mer windows in a dense packed symbol sequence.
 
template<typename Config >
__device__ __forceinline__ uint8_t dense_packed_symbol_at (const uint64_t *words, uint64_t symbol_index)
 Decodes one packed symbol at global index symbol_index.
 
template<typename Config >
__device__ __forceinline__ uint8_t dense_packed_symbol_at_local (const uint64_t *word_tile, uint64_t first_word_index, uint64_t symbol_index)
 Decodes one packed symbol from a block-local word tile.
 
template<typename Config >
__device__ __forceinline__ bool prepare_dense_packed_tiles (const uint64_t *words, uint64_t block_start_kmer, uint64_t block_kmers, uint64_t *word_tile, uint8_t *sequence_tile)
 Fills sequence_tile with encoded symbols for k-mers starting at block_start_kmer.
 
template<typename Config >
__global__ void pack_dense_sequence_kernel (const char *sequence, uint64_t num_symbols, uint64_t *words)
 Packs an encoded byte sequence into dense symbolBits-wide uint64_t words.
 
Result< cuda_free_memoryquery_cuda_free_memory ()
 Queries current device free memory via cudaMemGetInfo.
 
constexpr size_t fastx_chunk_slack_bytes () noexcept
 Reserved device memory left for allocator and kernel temporaries.
 
uint64_t fastx_file_bytes (const std::filesystem::path &path)
 
template<typename Config >
constexpr uint64_t fastx_record_symbol_count (uint64_t bases) noexcept
 
template<typename Config >
constexpr uint64_t fastx_record_kmer_count (uint64_t bases) noexcept
 
template<typename Config >
constexpr uint64_t estimate_normalized_sequence_bytes (uint64_t raw_bytes, uint64_t record_count) noexcept
 Upper bound on normalized sequence bytes for a raw host chunk.
 
template<typename Config >
constexpr uint64_t estimate_insert_staging_bytes (uint64_t raw_bytes, uint64_t record_count) noexcept
 Peak device bytes for insert staging (d_sequence_) for a host chunk.
 
template<typename Config >
constexpr uint64_t estimate_query_staging_bytes (uint64_t raw_bytes, uint64_t record_count) noexcept
 Peak device bytes for query staging (d_sequence_ + d_resultBuffer_).
 
template<typename Config >
constexpr size_t fastx_staging_budget_bytes (double fill_fraction, size_t free_bytes) noexcept
 Device staging byte budget derived from free VRAM and fill_fraction.
 
template<typename Config >
constexpr bool fastx_chunk_reached_staging_budget (fastx_chunk_mode mode, size_t staging_budget_bytes, uint64_t raw_bytes, uint64_t record_count) noexcept
 Whether estimated device staging meets or exceeds staging_budget_bytes.
 
constexpr size_t fastx_pipelined_chunk_budget (fastx_chunk_mode mode, size_t staging_budget_bytes) noexcept
 Per-chunk flush budget for dual-stream ping-pong (two device sequence buffers).
 
template<typename Config >
bool fastx_chunk_should_flush (fastx_chunk_mode mode, size_t gpu_staging_budget_bytes, size_t host_chunk_max_bytes, uint64_t raw_chunk_bytes, uint64_t record_count) noexcept
 Whether a host chunk should flush based on GPU staging and host byte limits.
 
template<typename Config >
bool fastx_file_fits_gpu_staging (const std::filesystem::path &path, fastx_chunk_mode mode, double fill_fraction)
 Whether the entire uncompressed file fits in one GPU staging pass.
 
template<typename Config >
Result< voidvalidate_fastx_staging_fits (fastx_chunk_mode mode, double fill_fraction, uint64_t raw_bytes, uint64_t record_count, std::string_view source_name)
 
template<typename FastxReaderType >
Result< boolcollect_next_fastx_record (FastxReaderType &reader, FastxRecord &record, DenseRecordBatchBuilder &chunk)
 Appends the next FASTX record from reader into chunk.
 
constexpr bool fastx_is_single_chunk_path (fastx_dispatch_path path) noexcept
 True for fastx_dispatch_path::single_chunk_stream or fastx_dispatch_path::single_chunk_mmap.
 
constexpr bool fastx_uses_mmap_reader (fastx_dispatch_path path) noexcept
 True when dispatch uses FastxBufferReader over an mmap'd file.
 
template<typename Config >
bool fastx_fits_single_gpu_chunk (fastx_chunk_mode mode, double fill_fraction, uint64_t file_bytes)
 Whether the entire file fits in a single GPU staging chunk at fill_fraction.
 
uint64_t fastx_single_chunk_stream_max_bytes ()
 Max raw file size for fastx_dispatch_path::single_chunk_stream (istream, no mmap).
 
template<typename Config >
fastx_dispatch_path select_fastx_dispatch_path_for_file_bytes (uint64_t file_bytes, fastx_chunk_mode mode, double fill_fraction, bool file_fits_in_memory)
 Selects mmap vs stream and single- vs multi-chunk processing from file size.
 
template<typename Config >
fastx_dispatch_path select_fastx_dispatch_path (const std::filesystem::path &path, fastx_chunk_mode mode, double fill_fraction)
 Selects mmap vs stream and single- vs multi-chunk processing for a path.
 
template<typename Config , fastx_dispatch_handler Handler>
fastx_dispatch_handler_result_t< Handlerdispatch_fastx_file (const std::filesystem::path &path, fastx_chunk_mode mode, double fill_fraction, Handler &&handler)
 Opens a FASTX path and invokes handler with a reader and dispatch path.
 
bool fastx_file_supports_memory_map (const std::filesystem::path &path)
 True when path is not gzip-compressed (mmap path is usable).
 
size_t parse_host_chunk_max_bytes (const char *env_name)
 
size_t fastx_host_chunk_max_bytes ()
 Optional host assembly byte cap before flush (debug / low-RAM safety valve).
 
constexpr bool fastx_chunk_reached_host_byte_limit (size_t host_chunk_max_bytes, uint64_t raw_chunk_bytes) noexcept
 True when raw_chunk_bytes reaches the optional host assembly cap.
 
size_t fastx_host_ram_slack_bytes ()
 
size_t query_available_host_bytes ()
 Available physical RAM (bytes) for mmap budgeting.
 
uint64_t fastx_memory_map_max_bytes ()
 Upper bound on file bytes that may be mmap'd (env cap and available RAM minus slack).
 
bool fastx_file_fits_in_memory (const std::filesystem::path &path)
 True when uncompressed path size is within fastx_memory_map_max_bytes.
 
template<typename Config , typename FastxReaderType , typename Adapter >
Result< typename Adapter::report_type > run_fastx_pipeline (FastxReaderType &reader, std::string_view source_name, double fill_fraction, cuda::stream_ref stream, fastx_dispatch_path dispatch_path, FastxPipelineState &state, Adapter &&adapter)
 
template<uint64_t Index>
__host__ __device__ __forceinline__ constexpr uint64_t multiplicativeSaltLiteral ()
 Compile-time multiplicative salt for Bloom hash index Index.
 
template<typename Config , typename Fn , uint64_t... HashIndices>
__host__ __device__ __forceinline__ void forEachHashIndexImpl (Fn &&fn, std::index_sequence< HashIndices... >)
 Unrolled invocation of fn for each Bloom hash index in Config.
 
template<typename Config , typename Fn >
__host__ __device__ __forceinline__ void forEachHashIndex (Fn &&fn)
 Invokes fn once per Bloom hash index (compile-time unrolled).
 
template<typename Config , uint64_t Length>
__host__ __device__ __forceinline__ constexpr uint64_t packedWindowMask ()
 Bit mask retaining the low Length symbols of a packed k-mer.
 
template<typename Config , uint64_t WindowLength, uint64_t K>
__host__ __device__ __forceinline__ constexpr uint64_t extractPackedSubwindow (uint64_t packed_kmer, uint64_t start)
 Extracts an m-mer or s-mer subwindow from a packed k-mer at start.
 
__device__ __forceinline__ void atomicOrWord (uint64_t *ptr, uint64_t value)
 64-bit atomic OR used for sectorized Bloom inserts.
 
uint64_t parse_env_mebibytes (std::string_view value)
 Parses a decimal mebibyte count from value.
 
std::string_view getenv_value (const char *env_name)
 Reads env_name via getenv, or an empty view when unset.
 
template<typename Config >
constexpr uint64_t dense_packed_insert_word_tile_capacity ()
 Maximum uint64_t words loaded for a dense-packed insert block tile.
 
template<typename Config >
constexpr uint64_t dense_packed_query_word_tile_capacity ()
 Maximum uint64_t words loaded for a dense-packed query block tile.
 
template<typename Config , uint32_t k_stride>
__device__ __forceinline__ void contains_kmers_from_symbol_tile (const uint8_t *sequence_tile, uint64_t block_start_kmer, uint64_t block_kmers, bool block_all_valid, device_span< const filter_block< Config > > shards, device_span< uint8_t > output)
 Shared query path after a block symbol tile has been prepared.
 
template<typename Config , uint32_t warps_per_block>
__device__ __forceinline__ void insert_kmers_from_symbol_tile (const uint8_t *sequence_tile, uint64_t block_start_kmer, uint64_t block_kmers, bool block_all_valid, device_span< filter_block< Config > > shards, cub::WarpReduce< uint64_t >::TempStorage reduce_storage[warps_per_block][4])
 Shared insert path after a block symbol tile has been prepared.
 
template<typename Config >
__global__ void contains_sequence_kmers_kernel (SequenceKmerInput< Config > input, device_span< const filter_block< Config > > shards, device_span< uint8_t > output)
 Query kernel: one byte per k-mer (1 = present, 0 = absent or invalid).
 
template<typename Config >
__global__ void insert_sequence_kmers_kernel (SequenceKmerInput< Config > input, device_span< filter_block< Config > > shards)
 Insert kernel: sectorized Bloom updates grouped by minimizer shard.
 
template<typename Config >
__global__ void contains_dense_packed_kmers_kernel (DensePackedKmerInput< Config > input, device_span< const filter_block< Config > > shards, device_span< uint8_t > output)
 Query kernel for a dense packed symbol buffer (DensePackedKmerInput).
 
template<typename Config >
__global__ void insert_dense_packed_kmers_kernel (DensePackedKmerInput< Config > input, device_span< filter_block< Config > > shards)
 Insert kernel for a dense packed symbol buffer (DensePackedKmerInput).
 
template<typename Config >
constexpr __host__ __device__ uint64_t record_symbol_count (uint64_t bases) noexcept
 
template<typename Config >
constexpr __host__ __device__ uint64_t record_kmer_count (uint64_t bases) noexcept
 
template<typename Config >
__device__ __forceinline__ uint64_t packed_kmer_minimizer_hash (uint64_t packed_kmer)
 Minimum minimizer hash over all m-mers in a packed k-mer.
 
template<typename Config >
__device__ __forceinline__ uint64_t packed_kmer_smer_hash (uint64_t packed_kmer, uint64_t start)
 Bloom hash for the s-mer at start within a packed k-mer.
 
template<typename Config >
__device__ __forceinline__ void load_shard_words4 (const filter_block< Config > *shards, uint64_t shard_index, uint64_t *w)
 Loads four 64-bit shard words with 256-bit (sm_100+) or 128-bit vector loads.
 
template<typename Config , uint64_t K>
__device__ __forceinline__ uint64_t pack_kmer_from_tile (const uint8_t *tile, uint64_t start)
 Packs K encoded symbols from a shared-memory tile starting at start.
 
template<typename Config , uint64_t K>
__device__ __forceinline__ uint64_t advance_packed_kmer (uint64_t packed, uint8_t new_base)
 Slides a packed k-mer window by one encoded base.
 
template<typename Config >
__device__ __forceinline__ bool kmer_is_valid (const uint8_t *tile, uint64_t start)
 True when no symbol in the k-mer window is the alphabet invalid sentinel.
 
template<typename Config >
__device__ __forceinline__ bool prepare_sequence_hash_tiles (const char *sequence, uint64_t block_start_kmer, uint64_t block_kmers, uint8_t *sequence_tile)
 Encodes a block's sequence slice into sequence_tile and reports global validity.
 
template<uint32_t k_stride, typename Config >
__device__ __forceinline__ uint32_t build_stride_kmer_valid_mask (uint64_t thread_offset, uint64_t block_kmers, bool block_all_valid, const uint8_t *sequence_tile)
 Builds the per-thread validity bitmask for strided query kernels.
 
template<typename T >
T try_unwrap_success (Result< T > &result)
 
void try_unwrap_success (Result< void > &result)
 
cuda::std::unexpected< Errorpropagate_error (const Error &error)
 Copies error for propagation (avoids moving out of expected::error()).
 
void trimTrailingCarriageReturn (std::string &line)
 Removes a trailing carriage return from line if present (Windows line endings).
 
uint32_t fastx_column_at (std::string_view line, size_t byte_index)
 1-based column at byte_index within line (clamped to the line end).
 
uint32_t fastx_quality_excess_column (uint64_t quality_length, uint64_t expected_length, std::string_view line)
 1-based column of the first quality byte that exceeds expected_length.
 
uint32_t fastx_quality_short_column (std::string_view line)
 1-based column where a quality run ends too short (position after the last byte).
 
Result< std::unique_ptr< std::istream > > openFastxFile (const std::filesystem::path &path)
 Opens a FASTA/FASTQ file for reading.
 
bool isGzipFile (const std::filesystem::path &path)
 True when path begins with the gzip magic bytes (0x1F, 0x8B).
 
constexpr __host__ __device__ __forceinline__ uint64_t hash64 (uint64_t key)
 Fast 64-bit integer hash (non-cryptographic).
 
constexpr __host__ __device__ __forceinline__ uint64_t minimizer_hash64 (uint64_t key)
 Fast 64-bit hash sufficient for uniform minimizer selection.
 
template<typename T >
__device__ __forceinline__ void load256BitGlobalNC (const T *ptr, T *out)
 Loads 256 bits from global memory using the non-coherent cache path.
 
__device__ __forceinline__ void load256BitGlobalNC (const uint64_t *ptr, uint64_t &out0, uint64_t &out1, uint64_t &out2, uint64_t &out3)
 Loads four uint64_t words via ld.global.nc.v4.u64 (sm_100+ only).
 
__device__ __forceinline__ void load128BitGlobalNC (const uint64_t *ptr, uint64_t &out0, uint64_t &out1)
 Loads 128 bits from global memory using the non-coherent cache path.
 
__device__ __forceinline__ uint64_t warpReduceOr (uint32_t peers, uint64_t value)
 OR-reduce a uint64_t across the lanes in a peer mask.
 
template<typename Kernel >
uint64_t maxOccupancyGridSize (int32_t blockSize, Kernel kernel, uint64_t dynamicSMemSize)
 Calculates the maximum occupancy grid size for a kernel.
 

Variables

constexpr size_t kDefaultFastxHostRamSlackBytes = 4u << 30
 Default headroom left for the OS and other processes when sizing mmap.
 
constexpr uint32_t kContainsSequenceStride = 4
 K-mers processed per query thread per inner loop iteration.
 
constexpr uint64_t kInvalidHash = std::numeric_limits<uint64_t>::max()
 Sentinel hash value indicating "no valid minimizer found".
 

Typedef Documentation

◆ fastx_dispatch_handler_result_t

Return type of a fastx_dispatch_handler when invoked with a stream reader.

Definition at line 136 of file fastx_dispatch.hpp.

Enumeration Type Documentation

◆ fastx_chunk_mode

FASTX mode used to size GPU staging buffers.

Enumerator
insert 
query 

Definition at line 24 of file fastx_chunk.cuh.

◆ fastx_dispatch_path

How a FASTX file is read and chunked for GPU processing.

Enumerator
single_chunk_stream 

Whole file in one GPU chunk, stream via istream (no mmap).

single_chunk_mmap 

Whole file in one GPU chunk, mmap'd when it fits in host RAM.

chunked_mmap 

Multiple GPU chunks, file mmap'd when it fits in host RAM.

chunked_stream 

Multiple GPU chunks, stream via istream (gzip or larger than RAM).

Definition at line 29 of file fastx_dispatch.hpp.

29 {
38};
@ chunked_mmap
Multiple GPU chunks, file mmap'd when it fits in host RAM.
@ single_chunk_mmap
Whole file in one GPU chunk, mmap'd when it fits in host RAM.
@ chunked_stream
Multiple GPU chunks, stream via istream (gzip or larger than RAM).
@ single_chunk_stream
Whole file in one GPU chunk, stream via istream (no mmap).

◆ FastxFormat

Detected file format for a FASTA/FASTQ stream.

Enumerator
unknown 

Format not yet determined from the first header.

fasta 

FASTA (> headers).

fastq 

FASTQ (@ headers).

Definition at line 243 of file Fastx.hpp.

243 : uint8_t {
245 unknown,
247 fasta,
249 fastq,
250};
@ fasta
FASTA (> headers).
@ fastq
FASTQ (@ headers).
@ unknown
Format not yet determined from the first header.

Function Documentation

◆ advance_packed_kmer()

template<typename Config , uint64_t K>
__device__ __forceinline__ uint64_t cusbf::detail::advance_packed_kmer ( uint64_t  packed,
uint8_t  new_base 
)

Slides a packed k-mer window by one encoded base.

Definition at line 86 of file sequence_kmer.cuh.

86 {
87 return ((packed << Config::symbolBits) | (new_base & Config::symbolMask)) &
88 packedWindowMask<Config, K>();
89}
Here is the call graph for this function:

◆ atomicOrWord()

__device__ __forceinline__ void cusbf::detail::atomicOrWord ( uint64_t ptr,
uint64_t  value 
)

64-bit atomic OR used for sectorized Bloom inserts.

Definition at line 137 of file filter_common.cuh.

137 {
138 atomicOr(reinterpret_cast<unsigned long long*>(ptr), static_cast<unsigned long long>(value));
139}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ build_stride_kmer_valid_mask()

template<uint32_t k_stride, typename Config >
__device__ __forceinline__ uint32_t cusbf::detail::build_stride_kmer_valid_mask ( uint64_t  thread_offset,
uint64_t  block_kmers,
bool  block_all_valid,
const uint8_t sequence_tile 
)

Builds the per-thread validity bitmask for strided query kernels.

Definition at line 129 of file sequence_kmer.cuh.

134 {
135 uint32_t kmer_valid_mask = 0;
136 _Pragma("unroll")
137 for (uint32_t s = 0; s < k_stride; ++s) {
138 if ((thread_offset + s) < block_kmers) {
139 kmer_valid_mask |= (1u << s);
140 }
141 }
142
143 if (!block_all_valid) {
144 _Pragma("unroll")
145 for (uint32_t s = 0; s < k_stride; ++s) {
146 if (!(kmer_valid_mask & (1u << s))) {
147 continue;
148 }
149 const uint64_t local_idx = thread_offset + s;
150 if (!kmer_is_valid<Config>(sequence_tile, local_idx)) {
151 kmer_valid_mask &= ~(1u << s);
152 }
153 }
154 }
155 return kmer_valid_mask;
156}
Here is the call graph for this function:

◆ collect_next_fastx_record()

Result< bool > cusbf::detail::collect_next_fastx_record ( FastxReaderType reader,
FastxRecord record,
DenseRecordBatchBuilder chunk 
)
inline

Appends the next FASTX record from reader into chunk.

Definition at line 13 of file fastx_dense_batch.hpp.

17 {
18 if constexpr (std::is_same_v<std::decay_t<FastxReaderType>, FastxBufferReader>) {
19 const auto range = CUSBF_TRY(
20 reader.appendNextRecord(record, chunk.sequence_buffer(), chunk.external_sequence_slot())
21 );
22 if (!range) {
23 return false;
24 }
25 chunk.push_range(*range);
26 return true;
27 }
28
29 const bool has_record = CUSBF_TRY(reader.nextRecord(record));
30 if (!has_record) {
31 return false;
32 }
33 chunk.appendRecord(record.sequence);
34 return true;
35}
std::string_view & external_sequence_slot() noexcept
Definition Fastx.hpp:88
void push_range(RecordRange range)
Records a range already present in sequence_view.
Definition Fastx.hpp:80
void appendRecord(std::string_view record_sequence)
Appends one record payload and records its byte range.
Definition Fastx.hpp:68
std::string & sequence_buffer() noexcept
Definition Fastx.hpp:84
FASTA/FASTQ parser over a contiguous in-memory buffer.
#define CUSBF_TRY(expr)
Propagates a cusbf::Result failure from the enclosing function (GNU statement expression).
Definition error.hpp:246
std::string sequence
Concatenated sequence lines (qualities skipped for FASTQ).
Definition Fastx.hpp:257
Here is the call graph for this function:
Here is the caller graph for this function:

◆ contains_dense_packed_kmers_kernel()

template<typename Config >
__global__ void cusbf::detail::contains_dense_packed_kmers_kernel ( DensePackedKmerInput< Config input,
device_span< const filter_block< Config > >  shards,
device_span< uint8_t output 
)

Query kernel for a dense packed symbol buffer (DensePackedKmerInput).

Definition at line 248 of file kernels.cuh.

252 {
253 constexpr uint32_t k_stride = kContainsSequenceStride;
254 constexpr uint64_t sequence_tile_bases = Config::cudaBlockSize * k_stride + Config::k - 1;
255 constexpr uint64_t word_tile_capacity = dense_packed_query_word_tile_capacity<Config>();
256
257 __shared__ uint64_t word_tile[word_tile_capacity];
258 __shared__ uint8_t sequence_tile[sequence_tile_bases];
259
260 const uint64_t num_kmers = input.kmerCount();
261 const uint64_t block_start_kmer =
262 static_cast<uint64_t>(blockIdx.x) * Config::cudaBlockSize * k_stride;
263 if (block_start_kmer >= num_kmers) {
264 return;
265 }
266
267 const uint64_t block_kmers =
268 min(Config::cudaBlockSize * k_stride, num_kmers - block_start_kmer);
269
270 const bool block_all_valid = prepare_dense_packed_tiles<Config>(
271 input.words.data(), block_start_kmer, block_kmers, word_tile, sequence_tile
272 );
273
274 contains_kmers_from_symbol_tile<Config, k_stride>(
275 sequence_tile, block_start_kmer, block_kmers, block_all_valid, shards, output
276 );
277}
constexpr uint32_t kContainsSequenceStride
K-mers processed per query thread per inner loop iteration.
device_span< const uint64_t > words
Dense packed words (device memory).
constexpr __host__ __device__ uint64_t kmerCount() const
Number of k-mer windows in this sequence.
Here is the call graph for this function:

◆ contains_kmers_from_symbol_tile()

template<typename Config , uint32_t k_stride>
__device__ __forceinline__ void cusbf::detail::contains_kmers_from_symbol_tile ( const uint8_t sequence_tile,
uint64_t  block_start_kmer,
uint64_t  block_kmers,
bool  block_all_valid,
device_span< const filter_block< Config > >  shards,
device_span< uint8_t output 
)

Shared query path after a block symbol tile has been prepared.

Used by both byte-sequence and dense-packed symbol kernels.

Definition at line 41 of file kernels.cuh.

48 {
49 const uint64_t thread_offset = static_cast<uint64_t>(threadIdx.x) * k_stride;
50 if (thread_offset >= block_kmers) {
51 return;
52 }
53
54 const uint32_t kmer_valid_mask = build_stride_kmer_valid_mask<k_stride, Config>(
55 thread_offset, block_kmers, block_all_valid, sequence_tile
56 );
57
58 uint64_t packed_kmer = pack_kmer_from_tile<Config, Config::k>(sequence_tile, thread_offset);
60
61 for (uint32_t s = 0; s < k_stride; ++s) {
62 const uint64_t local_idx = thread_offset + s;
63 if (local_idx >= block_kmers) {
64 break;
65 }
66
67 const uint64_t kmer_index = block_start_kmer + local_idx;
68
69 if (s > 0) {
70 packed_kmer = advance_packed_kmer<Config, Config::k>(
71 packed_kmer, sequence_tile[local_idx + Config::k - 1]
72 );
73 }
74
75 if (!(kmer_valid_mask & (1u << s))) {
76 output[kmer_index] = 0;
77 continue;
78 }
79
80 const uint64_t minimizer_hash = packed_kmer_minimizer_hash<Config>(packed_kmer);
81
82 const auto shard_idx =
83 static_cast<uint32_t>(filter_ref<Config>::shard_index(minimizer_hash, shards.size()));
84 const uint32_t peers = __match_any_sync(0xFFFFFFFFu, shard_idx);
85 const int leader = __ffs(static_cast<int>(peers)) - 1;
86
87 uint64_t w[4];
88 if (static_cast<int>(threadIdx.x & 31u) == leader) {
89 load_shard_words4<Config>(shards.data(), shard_idx, w);
90 }
91 w[0] = __shfl_sync(peers, w[0], leader);
92 w[1] = __shfl_sync(peers, w[1], leader);
93 w[2] = __shfl_sync(peers, w[2], leader);
94 w[3] = __shfl_sync(peers, w[3], leader);
95
96 const bool present = ref.sectorized_contains_packed_kmer(packed_kmer, w);
97 output[kmer_index] = present;
98 }
99}
Non-owning device reference to sectorized filter storage.
static __device__ bool sectorized_contains_packed_kmer(uint64_t packed_kmer, const uint64_t *shard_words)
Tests sectorized membership for a packed k-mer against shard words.
Here is the call graph for this function:

◆ contains_sequence_kmers_kernel()

template<typename Config >
__global__ void cusbf::detail::contains_sequence_kmers_kernel ( SequenceKmerInput< Config input,
device_span< const filter_block< Config > >  shards,
device_span< uint8_t output 
)

Query kernel: one byte per k-mer (1 = present, 0 = absent or invalid).

Threads stride kContainsSequenceStride k-mers, warps sharing a shard load it once.

Definition at line 180 of file kernels.cuh.

184 {
185 constexpr uint32_t k_stride = kContainsSequenceStride;
186 constexpr uint64_t sequence_tile_bases = Config::cudaBlockSize * k_stride + Config::k - 1;
187
188 __shared__ uint8_t sequence_tile[sequence_tile_bases];
189
190 const uint64_t num_kmers = input.kmerCount();
191 const uint64_t block_start_kmer =
192 static_cast<uint64_t>(blockIdx.x) * Config::cudaBlockSize * k_stride;
193 if (block_start_kmer >= num_kmers) {
194 return;
195 }
196
197 const uint64_t block_kmers =
198 min(Config::cudaBlockSize * k_stride, num_kmers - block_start_kmer);
199
200 const bool block_all_valid = prepare_sequence_hash_tiles<Config>(
201 input.sequence.data(), block_start_kmer, block_kmers, sequence_tile
202 );
203
204 contains_kmers_from_symbol_tile<Config, k_stride>(
205 sequence_tile, block_start_kmer, block_kmers, block_all_valid, shards, output
206 );
207}
constexpr __host__ __device__ uint64_t kmerCount() const
Number of k-mer windows in sequence.
device_span< const char > sequence
Encoded sequence bytes (Config::symbolWidth per symbol).
Here is the call graph for this function:

◆ count_positive_kmers_per_record()

template<typename Config >
Result< void > cusbf::detail::count_positive_kmers_per_record ( device_span< const uint8_t hits,
device_span< const QueryLayoutRecord records,
device_span< uint64_t positive_kmers_out,
cuda::stream_ref  stream 
)
inline

Fills positive_kmers_out with per-record positive k-mer counts.

positive_kmers_out must hold at least records.size() elements.

Definition at line 70 of file count_positive_kmers.cuh.

75 {
76 if (records.empty()) {
77 return {};
78 }
79 if (positive_kmers_out.size() < records.size()) {
80 return Err(Error::invalid_argument("positive k-mer output buffer is too small"));
81 }
82
83 const uint32_t block_size = 256;
84 const uint32_t grid_size = cuda::ceil_div(records.size(), static_cast<uint64_t>(block_size));
85 count_positive_kmers_per_record_kernel<Config><<<grid_size, block_size, 0, stream.get()>>>(
86 hits.data(), records.data(), positive_kmers_out.data(), records.size()
87 );
88 CUSBF_CUDA_TRY(cudaGetLastError());
89 return {};
90}
#define CUSBF_CUDA_TRY(expr)
Propagates a CUDA error wrapped in cusbf::Result<void>.
Definition error.hpp:269
Here is the call graph for this function:

◆ count_positive_kmers_per_record_kernel()

template<typename Config >
__global__ void cusbf::detail::count_positive_kmers_per_record_kernel ( const uint8_t hits,
const QueryLayoutRecord records,
uint64_t positive_kmers_out,
uint64_t  record_count 
)

Per-record kernel: sums hits[hit_offset ..] for each QueryLayoutRecord.

Definition at line 22 of file count_positive_kmers.cuh.

27 {
28 const uint64_t record_index = static_cast<uint64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
29 if (record_index >= record_count) {
30 return;
31 }
32
33 const QueryLayoutRecord& record = records[record_index];
34 if (record.hit_count == 0) {
35 positive_kmers_out[record_index] = 0;
36 return;
37 }
38
39 uint64_t positive = 0;
40 const uint64_t begin = record.hit_offset;
41 for (uint64_t i = 0; i < record.hit_count; ++i) {
42 positive += hits[begin + i];
43 }
44 positive_kmers_out[record_index] = positive;
45}
Here is the call graph for this function:

◆ count_positive_kmers_total()

template<typename Config >
uint64_t cusbf::detail::count_positive_kmers_total ( device_span< const uint8_t hits,
cuda::stream_ref  stream 
)
inline

Device-wide count of set bits in a per-k-mer hit buffer.

Definition at line 50 of file count_positive_kmers.cuh.

50 {
51 if (hits.empty()) {
52 return 0;
53 }
54
55 const auto execution = thrust::cuda::par.on(stream.get());
56 return static_cast<uint64_t>(thrust::count(
57 execution,
58 thrust::device_pointer_cast(hits.data()),
59 thrust::device_pointer_cast(hits.data()) + hits.size(),
60 uint8_t{1}
61 ));
62}
Here is the call graph for this function:

◆ dense_packed_insert_word_tile_capacity()

template<typename Config >
constexpr uint64_t cusbf::detail::dense_packed_insert_word_tile_capacity ( )
constexpr

Maximum uint64_t words loaded for a dense-packed insert block tile.

Definition at line 22 of file kernels.cuh.

22 {
23 constexpr uint64_t tile_symbols = Config::cudaBlockSize + Config::k - 1;
24 return cuda::ceil_div(tile_symbols, dense_packed_symbols_per_word<Config>());
25}
Here is the call graph for this function:

◆ dense_packed_kmer_count()

template<typename Config >
constexpr uint64_t cusbf::detail::dense_packed_kmer_count ( uint64_t  num_symbols)
constexpr

Returns the number of k-mer windows in a dense packed symbol sequence.

Definition at line 26 of file dense_packed.cuh.

26 {
27 return num_symbols < Config::k ? 0 : (num_symbols - Config::k + 1);
28}

◆ dense_packed_query_word_tile_capacity()

template<typename Config >
constexpr uint64_t cusbf::detail::dense_packed_query_word_tile_capacity ( )
constexpr

Maximum uint64_t words loaded for a dense-packed query block tile.

Definition at line 29 of file kernels.cuh.

29 {
30 constexpr uint64_t tile_symbols =
31 Config::cudaBlockSize * kContainsSequenceStride + Config::k - 1;
32 return cuda::ceil_div(tile_symbols, dense_packed_symbols_per_word<Config>());
33}
Here is the call graph for this function:

◆ dense_packed_symbol_at()

template<typename Config >
__device__ __forceinline__ uint8_t cusbf::detail::dense_packed_symbol_at ( const uint64_t words,
uint64_t  symbol_index 
)

Decodes one packed symbol at global index symbol_index.

Definition at line 59 of file dense_packed.cuh.

59 {
60 constexpr uint64_t symbols_per_word = dense_packed_symbols_per_word<Config>();
61 const uint64_t word_index = symbol_index / symbols_per_word;
62 const auto bit_offset =
63 static_cast<unsigned>((symbol_index % symbols_per_word) * Config::symbolBits);
64 return static_cast<uint8_t>((words[word_index] >> bit_offset) & Config::symbolMask);
65}
Here is the call graph for this function:

◆ dense_packed_symbol_at_local()

template<typename Config >
__device__ __forceinline__ uint8_t cusbf::detail::dense_packed_symbol_at_local ( const uint64_t word_tile,
uint64_t  first_word_index,
uint64_t  symbol_index 
)

Decodes one packed symbol from a block-local word tile.

Definition at line 69 of file dense_packed.cuh.

73 {
74 constexpr uint64_t symbols_per_word = dense_packed_symbols_per_word<Config>();
75 const uint64_t local_word = (symbol_index / symbols_per_word) - first_word_index;
76 const auto bit_offset =
77 static_cast<unsigned>((symbol_index % symbols_per_word) * Config::symbolBits);
78 return static_cast<uint8_t>((word_tile[local_word] >> bit_offset) & Config::symbolMask);
79}
Here is the call graph for this function:

◆ dense_packed_symbols_per_word()

template<typename Config >
constexpr uint64_t cusbf::detail::dense_packed_symbols_per_word ( )
constexpr

Encoded symbols stored in each uint64_t word for Config.

Definition at line 14 of file dense_packed.cuh.

14 {
15 return 64 / Config::symbolBits;
16}

◆ dense_packed_word_count()

template<typename Config >
constexpr uint64_t cusbf::detail::dense_packed_word_count ( uint64_t  num_symbols)
constexpr

Returns the number of uint64_t words required for num_symbols encoded symbols.

Definition at line 20 of file dense_packed.cuh.

20 {
21 return cuda::ceil_div(num_symbols, dense_packed_symbols_per_word<Config>());
22}
Here is the call graph for this function:

◆ dispatch_fastx_file()

template<typename Config , fastx_dispatch_handler Handler>
fastx_dispatch_handler_result_t< Handler > cusbf::detail::dispatch_fastx_file ( const std::filesystem::path &  path,
fastx_chunk_mode  mode,
double  fill_fraction,
Handler &&  handler 
)

Opens a FASTX path and invokes handler with a reader and dispatch path.

handler receives the reader and how the file was opened. Small files use fastx_dispatch_path::single_chunk_stream, GPU-sized inputs use fastx_dispatch_path::single_chunk_mmap, larger inputs use pipelined mmap or stream.

Definition at line 159 of file fastx_dispatch.hpp.

164 {
165 const std::string path_string = path.string();
166 const std::string_view path_view{path_string};
167 const fastx_dispatch_path dispatch_path =
168 select_fastx_dispatch_path<Config>(path, mode, fill_fraction);
169
170 if (fastx_uses_mmap_reader(dispatch_path)) {
171 const auto buffer = FastxFileBuffer::load(path);
172 if (!buffer) {
173 return Err(buffer.error());
174 }
175 FastxBufferReader reader((*buffer)->data(), path_view);
176 return handler(reader, dispatch_path);
177 }
178
179 const auto input = openFastxFile(path);
180 if (!input) {
181 return Err(input.error());
182 }
183 FastxReader reader(**input, path_view);
184 return handler(reader, dispatch_path);
185}
Result< std::unique_ptr< std::istream > > openFastxFile(const std::filesystem::path &path)
Opens a FASTA/FASTQ file for reading.
Definition Fastx.hpp:470
cuda::std::unexpected< Error > Err(Error error)
Failure return; converts to any Result<T> via cuda::std::unexpected.
Definition error.hpp:219
Here is the call graph for this function:

◆ estimate_insert_staging_bytes()

template<typename Config >
constexpr uint64_t cusbf::detail::estimate_insert_staging_bytes ( uint64_t  raw_bytes,
uint64_t  record_count 
)
constexprnoexcept

Peak device bytes for insert staging (d_sequence_) for a host chunk.

Definition at line 82 of file fastx_chunk.cuh.

82 {
83 return estimate_normalized_sequence_bytes<Config>(raw_bytes, record_count);
84}
Here is the call graph for this function:

◆ estimate_normalized_sequence_bytes()

template<typename Config >
constexpr uint64_t cusbf::detail::estimate_normalized_sequence_bytes ( uint64_t  raw_bytes,
uint64_t  record_count 
)
constexprnoexcept

Upper bound on normalized sequence bytes for a raw host chunk.

Definition at line 75 of file fastx_chunk.cuh.

75 {
76 return raw_bytes + record_count * 2 * Config::symbolWidth;
77}
Here is the call graph for this function:

◆ estimate_query_staging_bytes()

template<typename Config >
constexpr uint64_t cusbf::detail::estimate_query_staging_bytes ( uint64_t  raw_bytes,
uint64_t  record_count 
)
constexprnoexcept

Peak device bytes for query staging (d_sequence_ + d_resultBuffer_).

Definition at line 89 of file fastx_chunk.cuh.

89 {
90 const uint64_t normalized = estimate_normalized_sequence_bytes<Config>(raw_bytes, record_count);
91 return normalized + fastx_record_kmer_count<Config>(normalized);
92}
Here is the call graph for this function:

◆ extractPackedSubwindow()

template<typename Config , uint64_t WindowLength, uint64_t K>
__host__ __device__ __forceinline__ constexpr uint64_t cusbf::detail::extractPackedSubwindow ( uint64_t  packed_kmer,
uint64_t  start 
)
constexpr

Extracts an m-mer or s-mer subwindow from a packed k-mer at start.

Definition at line 130 of file filter_common.cuh.

130 {
131 static_assert(WindowLength <= K, "WindowLength must not exceed K");
132 return (packed_kmer >> (Config::symbolBits * (K - (start + WindowLength)))) &
133 packedWindowMask<Config, WindowLength>();
134}
Here is the call graph for this function:

◆ fastx_chunk_reached_host_byte_limit()

constexpr bool cusbf::detail::fastx_chunk_reached_host_byte_limit ( size_t  host_chunk_max_bytes,
uint64_t  raw_chunk_bytes 
)
inlineconstexprnoexcept

True when raw_chunk_bytes reaches the optional host assembly cap.

Definition at line 40 of file fastx_host_limits.cuh.

43 {
44 return host_chunk_max_bytes != std::numeric_limits<size_t>::max() &&
45 raw_chunk_bytes >= host_chunk_max_bytes;
46}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fastx_chunk_reached_staging_budget()

template<typename Config >
constexpr bool cusbf::detail::fastx_chunk_reached_staging_budget ( fastx_chunk_mode  mode,
size_t  staging_budget_bytes,
uint64_t  raw_bytes,
uint64_t  record_count 
)
constexprnoexcept

Whether estimated device staging meets or exceeds staging_budget_bytes.

Definition at line 110 of file fastx_chunk.cuh.

115 {
116 if (raw_bytes == 0) {
117 return false;
118 }
119 if (staging_budget_bytes == 0) {
120 return true;
121 }
122
123 const uint64_t staging = mode == fastx_chunk_mode::insert
124 ? estimate_insert_staging_bytes<Config>(raw_bytes, record_count)
125 : estimate_query_staging_bytes<Config>(raw_bytes, record_count);
126 return staging >= staging_budget_bytes;
127}
Here is the call graph for this function:

◆ fastx_chunk_should_flush()

template<typename Config >
bool cusbf::detail::fastx_chunk_should_flush ( fastx_chunk_mode  mode,
size_t  gpu_staging_budget_bytes,
size_t  host_chunk_max_bytes,
uint64_t  raw_chunk_bytes,
uint64_t  record_count 
)
inlinenoexcept

Whether a host chunk should flush based on GPU staging and host byte limits.

Definition at line 143 of file fastx_chunk.cuh.

149 {
150 return fastx_chunk_reached_staging_budget<Config>(
151 mode, gpu_staging_budget_bytes, raw_chunk_bytes, record_count
152 ) ||
153 fastx_chunk_reached_host_byte_limit(host_chunk_max_bytes, raw_chunk_bytes);
154}
constexpr bool fastx_chunk_reached_host_byte_limit(size_t host_chunk_max_bytes, uint64_t raw_chunk_bytes) noexcept
True when raw_chunk_bytes reaches the optional host assembly cap.
Here is the call graph for this function:

◆ fastx_chunk_slack_bytes()

constexpr size_t cusbf::detail::fastx_chunk_slack_bytes ( )
constexprnoexcept

Reserved device memory left for allocator and kernel temporaries.

Definition at line 44 of file fastx_chunk.cuh.

44 {
45 return 64u << 20;
46}
Here is the caller graph for this function:

◆ fastx_column_at()

uint32_t cusbf::detail::fastx_column_at ( std::string_view  line,
size_t  byte_index 
)
inline

1-based column at byte_index within line (clamped to the line end).

Definition at line 268 of file Fastx.hpp.

268 {
269 if (line.empty()) {
270 return 1;
271 }
272 return static_cast<uint32_t>(std::min(byte_index, line.size() - 1) + 1);
273}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fastx_file_bytes()

uint64_t cusbf::detail::fastx_file_bytes ( const std::filesystem::path &  path)
inline

Definition at line 48 of file fastx_chunk.cuh.

48 {
49#if defined(__linux__)
50 const std::string path_string = path.string();
51 struct stat file_status{};
52 if (::stat(path_string.c_str(), &file_status) != 0 || file_status.st_size < 0) {
53 return 0;
54 }
55 return static_cast<uint64_t>(file_status.st_size);
56#else
57 (void)path;
58 return 0;
59#endif
60}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fastx_file_fits_gpu_staging()

template<typename Config >
bool cusbf::detail::fastx_file_fits_gpu_staging ( const std::filesystem::path &  path,
fastx_chunk_mode  mode,
double  fill_fraction 
)
inline

Whether the entire uncompressed file fits in one GPU staging pass.

Definition at line 158 of file fastx_chunk.cuh.

162 {
163 const uint64_t file_bytes = fastx_file_bytes(path);
164 if (file_bytes == 0) {
165 return true;
166 }
167
168 const auto gpu_memory = query_cuda_free_memory();
169 if (!gpu_memory) {
170 return false;
171 }
172 const size_t staging_budget_bytes =
173 fastx_staging_budget_bytes<Config>(fill_fraction, gpu_memory->free_bytes);
174 return !fastx_chunk_reached_staging_budget<Config>(mode, staging_budget_bytes, file_bytes, 1);
175}
uint64_t fastx_file_bytes(const std::filesystem::path &path)
Here is the call graph for this function:

◆ fastx_file_fits_in_memory()

bool cusbf::detail::fastx_file_fits_in_memory ( const std::filesystem::path &  path)
inline

True when uncompressed path size is within fastx_memory_map_max_bytes.

Definition at line 66 of file fastx_host_memory.cuh.

66 {
67#if defined(__linux__)
68 const std::string path_string = path.string();
69 struct stat file_status{};
70 if (::stat(path_string.c_str(), &file_status) != 0 || file_status.st_size < 0) {
71 return false;
72 }
73 const auto file_bytes = static_cast<uint64_t>(file_status.st_size);
74 return file_bytes <= fastx_memory_map_max_bytes();
75#else
76 (void)path;
77 return false;
78#endif
79}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fastx_file_supports_memory_map()

bool cusbf::detail::fastx_file_supports_memory_map ( const std::filesystem::path &  path)
inline

True when path is not gzip-compressed (mmap path is usable).

Definition at line 164 of file fastx_file_buffer.hpp.

164 {
165 return !isGzipFile(path);
166}
bool isGzipFile(const std::filesystem::path &path)
True when path begins with the gzip magic bytes (0x1F, 0x8B).
Here is the call graph for this function:

◆ fastx_fits_single_gpu_chunk()

template<typename Config >
bool cusbf::detail::fastx_fits_single_gpu_chunk ( fastx_chunk_mode  mode,
double  fill_fraction,
uint64_t  file_bytes 
)
inline

Whether the entire file fits in a single GPU staging chunk at fill_fraction.

Definition at line 56 of file fastx_dispatch.hpp.

56 {
57 if (file_bytes == 0) {
58 return true;
59 }
60
61 const auto gpu_memory = query_cuda_free_memory();
62 if (!gpu_memory) {
63 return false;
64 }
65 const size_t staging_budget_bytes =
66 fastx_staging_budget_bytes<Config>(fill_fraction, gpu_memory->free_bytes);
67 if (staging_budget_bytes == 0) {
68 return true;
69 }
70
71 return !fastx_chunk_reached_staging_budget<Config>(mode, staging_budget_bytes, file_bytes, 1);
72}
Here is the call graph for this function:

◆ fastx_host_chunk_max_bytes()

size_t cusbf::detail::fastx_host_chunk_max_bytes ( )
inline

Optional host assembly byte cap before flush (debug / low-RAM safety valve).

Returns SIZE_MAX when unset so fastx_chunk_should_flush uses GPU staging only.

Definition at line 25 of file fastx_host_limits.cuh.

25 {
26 if (const size_t override_bytes = parse_host_chunk_max_bytes("CUSBF_FASTX_MAX_HOST_CHUNK_MB");
27 override_bytes != 0) {
28 return override_bytes;
29 }
30
31 if (const size_t large_bytes = parse_host_chunk_max_bytes("CUSBF_LARGE_FASTX_HOST_CHUNK_MB");
32 large_bytes != 0) {
33 return large_bytes;
34 }
35
36 return std::numeric_limits<size_t>::max();
37}
size_t parse_host_chunk_max_bytes(const char *env_name)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fastx_host_ram_slack_bytes()

size_t cusbf::detail::fastx_host_ram_slack_bytes ( )
inline

Definition at line 22 of file fastx_host_memory.cuh.

22 {
23 const std::string_view value = getenv_value("CUSBF_FASTX_HOST_RAM_SLACK_MB");
24 if (value.empty()) {
26 }
27
28 const uint64_t mebibytes = parse_env_mebibytes(value);
29 if (mebibytes == 0) {
30 return kDefaultFastxHostRamSlackBytes;
31 }
32 return static_cast<size_t>(mebibytes) << 20;
33}
constexpr size_t kDefaultFastxHostRamSlackBytes
Default headroom left for the OS and other processes when sizing mmap.
std::string_view getenv_value(const char *env_name)
Reads env_name via getenv, or an empty view when unset.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fastx_is_single_chunk_path()

constexpr bool cusbf::detail::fastx_is_single_chunk_path ( fastx_dispatch_path  path)
constexprnoexcept

True for fastx_dispatch_path::single_chunk_stream or fastx_dispatch_path::single_chunk_mmap.

Definition at line 42 of file fastx_dispatch.hpp.

42 {
43 return path == fastx_dispatch_path::single_chunk_stream ||
44 path == fastx_dispatch_path::single_chunk_mmap;
45}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fastx_memory_map_max_bytes()

uint64_t cusbf::detail::fastx_memory_map_max_bytes ( )
inline

Upper bound on file bytes that may be mmap'd (env cap and available RAM minus slack).

Definition at line 48 of file fastx_host_memory.cuh.

48 {
49 uint64_t cap_bytes = UINT64_MAX;
50 if (const uint64_t mebibytes = parse_env_mebibytes(getenv_value("CUSBF_FASTX_MMAP_MAX_MB"));
51 mebibytes != 0) {
52 cap_bytes = mebibytes << 20;
53 }
54
55 const size_t available = query_available_host_bytes();
56 if (available == 0) {
57 return cap_bytes;
58 }
59
60 const size_t slack = fastx_host_ram_slack_bytes();
61 const size_t ram_budget = available > slack ? available - slack : size_t{0};
62 return std::min(cap_bytes, static_cast<uint64_t>(ram_budget));
63}
uint64_t parse_env_mebibytes(std::string_view value)
Parses a decimal mebibyte count from value.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fastx_pipelined_chunk_budget()

constexpr size_t cusbf::detail::fastx_pipelined_chunk_budget ( fastx_chunk_mode  mode,
size_t  staging_budget_bytes 
)
constexprnoexcept

Per-chunk flush budget for dual-stream ping-pong (two device sequence buffers).

Definition at line 131 of file fastx_chunk.cuh.

131 {
132 if (staging_budget_bytes == 0) {
133 return 0;
134 }
135 if (mode == fastx_chunk_mode::insert) {
136 return staging_budget_bytes / 2;
137 }
138 return staging_budget_bytes / 3;
139}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fastx_quality_excess_column()

uint32_t cusbf::detail::fastx_quality_excess_column ( uint64_t  quality_length,
uint64_t  expected_length,
std::string_view  line 
)
inline

1-based column of the first quality byte that exceeds expected_length.

Definition at line 276 of file Fastx.hpp.

280 {
281 const uint64_t before = quality_length - line.size();
282 const size_t byte_index = expected_length > before ? expected_length - before : line.size();
283 return fastx_column_at(line, byte_index);
284}
uint32_t fastx_column_at(std::string_view line, size_t byte_index)
1-based column at byte_index within line (clamped to the line end).
Definition Fastx.hpp:268
Here is the call graph for this function:

◆ fastx_quality_short_column()

uint32_t cusbf::detail::fastx_quality_short_column ( std::string_view  line)
inline

1-based column where a quality run ends too short (position after the last byte).

Definition at line 287 of file Fastx.hpp.

287 {
288 return static_cast<uint32_t>(line.empty() ? 1 : line.size() + 1);
289}
Here is the call graph for this function:

◆ fastx_record_kmer_count()

template<typename Config >
constexpr uint64_t cusbf::detail::fastx_record_kmer_count ( uint64_t  bases)
constexprnoexcept

Definition at line 68 of file fastx_chunk.cuh.

68 {
69 return record_kmer_count<Config>(bases);
70}
Here is the call graph for this function:

◆ fastx_record_symbol_count()

template<typename Config >
constexpr uint64_t cusbf::detail::fastx_record_symbol_count ( uint64_t  bases)
constexprnoexcept

Definition at line 63 of file fastx_chunk.cuh.

63 {
64 return record_symbol_count<Config>(bases);
65}
Here is the call graph for this function:

◆ fastx_single_chunk_stream_max_bytes()

uint64_t cusbf::detail::fastx_single_chunk_stream_max_bytes ( )
inline

Max raw file size for fastx_dispatch_path::single_chunk_stream (istream, no mmap).

Larger files that still fit one GPU chunk use fastx_dispatch_path::single_chunk_mmap.

Definition at line 77 of file fastx_dispatch.hpp.

77 {
78 constexpr uint64_t kDefaultBytes = 32u << 20;
79 const uint64_t mebibytes =
80 parse_env_mebibytes(getenv_value("CUSBF_FASTX_SINGLE_CHUNK_STREAM_MAX_MB"));
81 if (mebibytes == 0) {
82 return kDefaultBytes;
83 }
84 return mebibytes << 20;
85}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fastx_staging_budget_bytes()

template<typename Config >
constexpr size_t cusbf::detail::fastx_staging_budget_bytes ( double  fill_fraction,
size_t  free_bytes 
)
constexprnoexcept

Device staging byte budget derived from free VRAM and fill_fraction.

Definition at line 97 of file fastx_chunk.cuh.

97 {
98 if (fill_fraction <= 0.0) {
99 return 0;
100 }
101
102 const size_t available =
103 free_bytes > fastx_chunk_slack_bytes() ? free_bytes - fastx_chunk_slack_bytes() : size_t{0};
104 const double budget = static_cast<double>(available) * fill_fraction;
105 return budget <= 0.0 ? size_t{0} : static_cast<size_t>(budget);
106}
Here is the call graph for this function:

◆ fastx_uses_mmap_reader()

constexpr bool cusbf::detail::fastx_uses_mmap_reader ( fastx_dispatch_path  path)
constexprnoexcept

True when dispatch uses FastxBufferReader over an mmap'd file.

Definition at line 48 of file fastx_dispatch.hpp.

48 {
49 return path == fastx_dispatch_path::single_chunk_mmap ||
50 path == fastx_dispatch_path::chunked_mmap;
51}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ forEachHashIndex()

template<typename Config , typename Fn >
__host__ __device__ __forceinline__ void cusbf::detail::forEachHashIndex ( Fn &&  fn)

Invokes fn once per Bloom hash index (compile-time unrolled).

Definition at line 111 of file filter_common.cuh.

111 {
112 forEachHashIndexImpl<Config>(
113 static_cast<Fn&&>(fn), std::make_index_sequence<Config::hashCount>{}
114 );
115}
Here is the call graph for this function:

◆ forEachHashIndexImpl()

template<typename Config , typename Fn , uint64_t... HashIndices>
__host__ __device__ __forceinline__ void cusbf::detail::forEachHashIndexImpl ( Fn &&  fn,
std::index_sequence< HashIndices... >   
)

Unrolled invocation of fn for each Bloom hash index in Config.

Definition at line 105 of file filter_common.cuh.

105 {
106 (fn(std::integral_constant<uint64_t, HashIndices>{}), ...);
107}
Here is the call graph for this function:

◆ getenv_value()

std::string_view cusbf::detail::getenv_value ( const char env_name)
inline

Reads env_name via getenv, or an empty view when unset.

Definition at line 32 of file host_parse.hpp.

32 {
33 const char* value = std::getenv(env_name);
34 if (value == nullptr || value[0] == '\0') {
35 return {};
36 }
37 return value;
38}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ hash64()

constexpr __host__ __device__ __forceinline__ uint64_t cusbf::detail::hash64 ( uint64_t  key)
constexpr

Fast 64-bit integer hash (non-cryptographic).

One multiplicative step followed by an xorshift. Used to hash s-mer packed representations for Bloom bit-position selection.

Parameters
keyInput value.
Returns
Hashed value.

Definition at line 192 of file hashutil.cuh.

192 {
193 key *= 0x9e3779b97f4a7c15ULL;
194 key ^= key >> 33;
195 return key;
196}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ insert_dense_packed_kmers_kernel()

template<typename Config >
__global__ void cusbf::detail::insert_dense_packed_kmers_kernel ( DensePackedKmerInput< Config input,
device_span< filter_block< Config > >  shards 
)

Insert kernel for a dense packed symbol buffer (DensePackedKmerInput).

Definition at line 283 of file kernels.cuh.

286 {
287 constexpr uint64_t sequence_tile_bases = Config::cudaBlockSize + Config::k - 1;
288 constexpr uint32_t warps_per_block = Config::cudaBlockSize / 32;
289 constexpr uint64_t word_tile_capacity = dense_packed_insert_word_tile_capacity<Config>();
290
291 using WarpReduceWord = cub::WarpReduce<uint64_t>;
292
293 __shared__ uint64_t word_tile[word_tile_capacity];
294 __shared__ uint8_t sequence_tile[sequence_tile_bases];
295 __shared__ typename WarpReduceWord::TempStorage reduce_storage[warps_per_block][4];
296
297 const uint64_t num_kmers = input.kmerCount();
298 const uint64_t block_start_kmer = static_cast<uint64_t>(blockIdx.x) * Config::cudaBlockSize;
299 if (block_start_kmer >= num_kmers) {
300 return;
301 }
302
303 const uint64_t block_kmers = min(Config::cudaBlockSize, num_kmers - block_start_kmer);
304
305 const bool block_all_valid = prepare_dense_packed_tiles<Config>(
306 input.words.data(), block_start_kmer, block_kmers, word_tile, sequence_tile
307 );
308
309 insert_kmers_from_symbol_tile<Config, warps_per_block>(
310 sequence_tile, block_start_kmer, block_kmers, block_all_valid, shards, reduce_storage
311 );
312}
Here is the call graph for this function:

◆ insert_kmers_from_symbol_tile()

template<typename Config , uint32_t warps_per_block>
__device__ __forceinline__ void cusbf::detail::insert_kmers_from_symbol_tile ( const uint8_t sequence_tile,
uint64_t  block_start_kmer,
uint64_t  block_kmers,
bool  block_all_valid,
device_span< filter_block< Config > >  shards,
cub::WarpReduce< uint64_t >::TempStorage  reduce_storage[warps_per_block][4] 
)

Shared insert path after a block symbol tile has been prepared.

Used by both byte-sequence and dense-packed symbol kernels.

Definition at line 107 of file kernels.cuh.

114 {
115 constexpr uint32_t warp_size = 32;
116
117 const auto local_kmer_index = static_cast<uint64_t>(threadIdx.x);
118 const bool in_range = local_kmer_index < block_kmers;
119
120 bool active = in_range;
121 if (active && !block_all_valid) {
122 active = kmer_is_valid<Config>(sequence_tile, local_kmer_index);
123 }
124
125 uint64_t minimizer_hash = 0;
126 uint64_t word_mask0 = 0;
127 uint64_t word_mask1 = 0;
128 uint64_t word_mask2 = 0;
129 uint64_t word_mask3 = 0;
130
131 if (active) {
132 const uint64_t packed_kmer =
133 pack_kmer_from_tile<Config, Config::k>(sequence_tile, local_kmer_index);
134 minimizer_hash = packed_kmer_minimizer_hash<Config>(packed_kmer);
135
136 uint64_t h_s = packed_kmer_smer_hash<Config>(packed_kmer, 0);
138 h_s, word_mask0, word_mask1, word_mask2, word_mask3
139 );
140 _Pragma("unroll")
141 for (uint64_t smer_offset = 1; smer_offset < Config::findereSpan; ++smer_offset) {
142 h_s = packed_kmer_smer_hash<Config>(packed_kmer, smer_offset);
144 h_s, word_mask0, word_mask1, word_mask2, word_mask3
145 );
146 }
147 }
148
149 const auto shard_idx =
150 static_cast<uint32_t>(active ? (minimizer_hash & (shards.size() - 1)) : ~threadIdx.x);
151
152 const uint32_t lane = threadIdx.x & (warp_size - 1);
153 const uint32_t warp_idx = threadIdx.x / warp_size;
154 const uint32_t prev_shard_idx = __shfl_up_sync(0xffffffff, shard_idx, 1);
155 const bool run_head = (lane == 0) || (shard_idx != prev_shard_idx);
156 const BitwiseOr<uint64_t> bitwise_or{};
157
158 using WarpReduceWord = cub::WarpReduce<uint64_t>;
159 word_mask0 = WarpReduceWord(reduce_storage[warp_idx][0])
160 .HeadSegmentedReduce(word_mask0, run_head, bitwise_or);
161 word_mask1 = WarpReduceWord(reduce_storage[warp_idx][1])
162 .HeadSegmentedReduce(word_mask1, run_head, bitwise_or);
163 word_mask2 = WarpReduceWord(reduce_storage[warp_idx][2])
164 .HeadSegmentedReduce(word_mask2, run_head, bitwise_or);
165 word_mask3 = WarpReduceWord(reduce_storage[warp_idx][3])
166 .HeadSegmentedReduce(word_mask3, run_head, bitwise_or);
167
168 if (run_head && active) {
169 filter_ref<Config> ref;
170 ref.apply_word_masks(shards[shard_idx], word_mask0, word_mask1, word_mask2, word_mask3);
171 }
172}
Compile-time configuration for a cusbf::filter.
Definition config.cuh:35
One 256-bit filter block stored as an array of Config::blockWordCount words.
Here is the call graph for this function:

◆ insert_sequence_kmers_kernel()

template<typename Config >
__global__ void cusbf::detail::insert_sequence_kmers_kernel ( SequenceKmerInput< Config input,
device_span< filter_block< Config > >  shards 
)

Insert kernel: sectorized Bloom updates grouped by minimizer shard.

Warp-local segmented reduction merges consecutive k-mers targeting the same shard.

Definition at line 215 of file kernels.cuh.

218 {
219 constexpr uint64_t sequence_tile_bases = Config::cudaBlockSize + Config::k - 1;
220 constexpr uint32_t warps_per_block = Config::cudaBlockSize / 32;
221
222 using WarpReduceWord = cub::WarpReduce<uint64_t>;
223
224 __shared__ uint8_t sequence_tile[sequence_tile_bases];
225 __shared__ typename WarpReduceWord::TempStorage reduce_storage[warps_per_block][4];
226
227 const uint64_t num_kmers = input.kmerCount();
228 const uint64_t block_start_kmer = static_cast<uint64_t>(blockIdx.x) * Config::cudaBlockSize;
229 if (block_start_kmer >= num_kmers) {
230 return;
231 }
232
233 const uint64_t block_kmers = min(Config::cudaBlockSize, num_kmers - block_start_kmer);
234
235 const bool block_all_valid = prepare_sequence_hash_tiles<Config>(
236 input.sequence.data(), block_start_kmer, block_kmers, sequence_tile
237 );
238
239 insert_kmers_from_symbol_tile<Config, warps_per_block>(
240 sequence_tile, block_start_kmer, block_kmers, block_all_valid, shards, reduce_storage
241 );
242}
Here is the call graph for this function:

◆ isGzipFile()

bool cusbf::detail::isGzipFile ( const std::filesystem::path &  path)
inline

True when path begins with the gzip magic bytes (0x1F, 0x8B).

Definition at line 101 of file gzstreambuf.hpp.

101 {
102 FILE* f = std::fopen(path.string().c_str(), "rb");
103 if (!f) {
104 return false;
105 }
106 uint8_t magic[2];
107 size_t n = std::fread(magic, 1, 2, f);
108 std::fclose(f);
109 return n == 2 && magic[0] == 0x1F && magic[1] == 0x8B;
110}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ kmer_is_valid()

template<typename Config >
__device__ __forceinline__ bool cusbf::detail::kmer_is_valid ( const uint8_t tile,
uint64_t  start 
)

True when no symbol in the k-mer window is the alphabet invalid sentinel.

Definition at line 93 of file sequence_kmer.cuh.

93 {
94 _Pragma("unroll")
95 for (uint64_t i = 0; i < Config::k; ++i) {
96 if (tile[start + i] == Config::Alphabet::invalidSymbol) {
97 return false;
98 }
99 }
100 return true;
101}
Here is the call graph for this function:

◆ load128BitGlobalNC()

__device__ __forceinline__ void cusbf::detail::load128BitGlobalNC ( const uint64_t ptr,
uint64_t out0,
uint64_t out1 
)

Loads 128 bits from global memory using the non-coherent cache path.

Uses the ld.global.nc.v2.u64 instruction for uint64_t

Definition at line 74 of file helpers.cuh.

74 {
75 asm volatile("ld.global.nc.v2.u64 {%0, %1}, [%2];" : "=l"(out0), "=l"(out1) : "l"(ptr));
76}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ load256BitGlobalNC() [1/2]

template<typename T >
__device__ __forceinline__ void cusbf::detail::load256BitGlobalNC ( const T ptr,
T out 
)

Loads 256 bits from global memory using the non-coherent cache path.

This function uses inline PTX for 256-bit vectorized loads. For uint64_t: loads 4 values (v4.u64) For uint32_t: loads 8 values (v8.u32)

Note
Only available on sm_100+ architectures with PTX 8.8. Use __CUDA_ARCH__ >= 1000 guard at call sites.
Template Parameters
TElement type (uint32_t or uint64_t)
Parameters
ptrSource pointer (must be 32-byte aligned)
outOutput array (4 elements for uint64_t, 8 for uint32_t)

Definition at line 32 of file helpers.cuh.

32 {
33 static_assert(sizeof(T) == 4 || sizeof(T) == 8, "T must be uint32_t or uint64_t");
34
35 if constexpr (sizeof(T) == 8) {
36 asm volatile("ld.global.nc.v4.u64 {%0, %1, %2, %3}, [%4];"
37 : "=l"(out[0]), "=l"(out[1]), "=l"(out[2]), "=l"(out[3])
38 : "l"(ptr));
39 } else {
40 asm volatile("ld.global.nc.v8.u32 {%0, %1, %2, %3, %4, %5, %6, %7}, [%8];"
41 : "=r"(out[0]),
42 "=r"(out[1]),
43 "=r"(out[2]),
44 "=r"(out[3]),
45 "=r"(out[4]),
46 "=r"(out[5]),
47 "=r"(out[6]),
48 "=r"(out[7])
49 : "l"(ptr));
50 }
51}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ load256BitGlobalNC() [2/2]

__device__ __forceinline__ void cusbf::detail::load256BitGlobalNC ( const uint64_t ptr,
uint64_t out0,
uint64_t out1,
uint64_t out2,
uint64_t out3 
)

Loads four uint64_t words via ld.global.nc.v4.u64 (sm_100+ only).

Definition at line 54 of file helpers.cuh.

60 {
61 asm volatile("ld.global.nc.v4.u64 {%0, %1, %2, %3}, [%4];"
62 : "=l"(out0), "=l"(out1), "=l"(out2), "=l"(out3)
63 : "l"(ptr));
64}
Here is the call graph for this function:

◆ load_shard_words4()

template<typename Config >
__device__ __forceinline__ void cusbf::detail::load_shard_words4 ( const filter_block< Config > *  shards,
uint64_t  shard_index,
uint64_t w 
)

Loads four 64-bit shard words with 256-bit (sm_100+) or 128-bit vector loads.

Definition at line 64 of file sequence_kmer.cuh.

64 {
65#if __CUDA_ARCH__ >= 1000
66 load256BitGlobalNC(shards[shard_index].words, w[0], w[1], w[2], w[3]);
67#else
68 load128BitGlobalNC(shards[shard_index].words + 0, w[0], w[1]);
69 load128BitGlobalNC(shards[shard_index].words + 2, w[2], w[3]);
70#endif
71}
__device__ __forceinline__ void load128BitGlobalNC(const uint64_t *ptr, uint64_t &out0, uint64_t &out1)
Loads 128 bits from global memory using the non-coherent cache path.
Definition helpers.cuh:74
__device__ __forceinline__ void load256BitGlobalNC(const T *ptr, T *out)
Loads 256 bits from global memory using the non-coherent cache path.
Definition helpers.cuh:32
Here is the call graph for this function:

◆ maxOccupancyGridSize()

template<typename Kernel >
uint64_t cusbf::detail::maxOccupancyGridSize ( int32_t  blockSize,
Kernel  kernel,
uint64_t  dynamicSMemSize 
)

Calculates the maximum occupancy grid size for a kernel.

Template Parameters
KernelType of the kernel function.
Parameters
blockSizeBlock size (threads per block).
kernelThe kernel function.
dynamicSMemSizeDynamic shared memory size per block.
Returns
uint64_t The calculated grid size (number of blocks).

Definition at line 115 of file helpers.cuh.

115 {
116 int device = 0;
117 cudaGetDevice(&device);
118
119 int numSM = -1;
120 cudaDeviceGetAttribute(&numSM, cudaDevAttrMultiProcessorCount, device);
121
122 int maxActiveBlocksPerSM{};
123 cudaOccupancyMaxActiveBlocksPerMultiprocessor(
124 &maxActiveBlocksPerSM, kernel, blockSize, dynamicSMemSize
125 );
126
127 return maxActiveBlocksPerSM * numSM;
128}
Here is the call graph for this function:

◆ minimizer_hash64()

constexpr __host__ __device__ __forceinline__ uint64_t cusbf::detail::minimizer_hash64 ( uint64_t  key)
constexpr

Fast 64-bit hash sufficient for uniform minimizer selection.

A single Knuth multiplicative step — provides enough uniformity for shard selection without the full avalanche quality of hash64.

Parameters
keyPacked m-mer input.
Returns
Hash value used to select the minimum (minimizer).

Definition at line 207 of file hashutil.cuh.

207 {
208 return key * 0x9E3779B97F4A7C15ULL;
209}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ multiplicativeSaltLiteral()

template<uint64_t Index>
__host__ __device__ __forceinline__ constexpr uint64_t cusbf::detail::multiplicativeSaltLiteral ( )
constexpr

Compile-time multiplicative salt for Bloom hash index Index.

Definition at line 97 of file filter_common.cuh.

97 {
98 static_assert(Index < 16, "Salt index out of range");
100}
Here is the call graph for this function:

◆ openFastxFile()

Result< std::unique_ptr< std::istream > > cusbf::detail::openFastxFile ( const std::filesystem::path &  path)
inline

Opens a FASTA/FASTQ file for reading.

Parameters
pathFile path.
Returns
Open input file stream, or an I/O error.

Definition at line 470 of file Fastx.hpp.

472 {
473 if (isGzipFile(path)) {
474 return GzIstream::open(path);
475 }
476 auto input = std::make_unique<std::ifstream>(path);
477 if (!input->is_open()) {
478 return Err(Error::io(std::format("Failed to open FASTA/FASTQ file: {}", path.string())));
479 }
480 return input;
481}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pack_dense_sequence_kernel()

template<typename Config >
__global__ void cusbf::detail::pack_dense_sequence_kernel ( const char sequence,
uint64_t  num_symbols,
uint64_t words 
)

Packs an encoded byte sequence into dense symbolBits-wide uint64_t words.

One thread per output word; reads Config::symbolWidth bytes per symbol via Config::Alphabet::encode.

Definition at line 128 of file dense_packed.cuh.

128 {
129 constexpr uint64_t symbols_per_word = dense_packed_symbols_per_word<Config>();
130 const uint64_t word_index = static_cast<uint64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
131 const uint64_t num_words = dense_packed_word_count<Config>(num_symbols);
132 if (word_index >= num_words) {
133 return;
134 }
135
136 const uint64_t first_symbol = word_index * symbols_per_word;
137 uint64_t packed_word = 0;
138 for (uint64_t offset = 0; offset < symbols_per_word; ++offset) {
139 const uint64_t symbol_index = first_symbol + offset;
140 if (symbol_index >= num_symbols) {
141 break;
142 }
143 const uint8_t symbol =
144 Config::Alphabet::encode(sequence + symbol_index * Config::symbolWidth);
145 packed_word |=
146 (static_cast<uint64_t>(symbol & Config::symbolMask) << (offset * Config::symbolBits));
147 }
148 words[word_index] = packed_word;
149}
Here is the call graph for this function:

◆ pack_kmer_from_tile()

template<typename Config , uint64_t K>
__device__ __forceinline__ uint64_t cusbf::detail::pack_kmer_from_tile ( const uint8_t tile,
uint64_t  start 
)

Packs K encoded symbols from a shared-memory tile starting at start.

Definition at line 75 of file sequence_kmer.cuh.

75 {
76 uint64_t packed = 0;
77 _Pragma("unroll")
78 for (uint64_t i = 0; i < K; ++i) {
79 packed = (packed << Config::symbolBits) | (tile[start + i] & Config::symbolMask);
80 }
81 return packed;
82}
Here is the call graph for this function:

◆ packed_kmer_minimizer_hash()

template<typename Config >
__device__ __forceinline__ uint64_t cusbf::detail::packed_kmer_minimizer_hash ( uint64_t  packed_kmer)

Minimum minimizer hash over all m-mers in a packed k-mer.

Definition at line 41 of file sequence_kmer.cuh.

41 {
42 uint64_t minimizer_hash = kInvalidHash;
43 _Pragma("unroll")
44 for (uint64_t offset = 0; offset < Config::minimizerSpan; ++offset) {
45 const uint64_t packed_mmer =
46 extractPackedSubwindow<Config, Config::m, Config::k>(packed_kmer, offset);
47 minimizer_hash = min(minimizer_hash, minimizer_hash64(packed_mmer));
48 }
49 return minimizer_hash;
50}
constexpr __host__ __device__ __forceinline__ uint64_t minimizer_hash64(uint64_t key)
Fast 64-bit hash sufficient for uniform minimizer selection.
Definition hashutil.cuh:207
constexpr uint64_t kInvalidHash
Sentinel hash value indicating "no valid minimizer found".
Here is the call graph for this function:

◆ packed_kmer_smer_hash()

template<typename Config >
__device__ __forceinline__ uint64_t cusbf::detail::packed_kmer_smer_hash ( uint64_t  packed_kmer,
uint64_t  start 
)

Bloom hash for the s-mer at start within a packed k-mer.

Definition at line 55 of file sequence_kmer.cuh.

55 {
56 const uint64_t packed_smer =
57 extractPackedSubwindow<Config, Config::s, Config::k>(packed_kmer, start);
58 return hash64(packed_smer);
59}
constexpr __host__ __device__ __forceinline__ uint64_t hash64(uint64_t key)
Fast 64-bit integer hash (non-cryptographic).
Definition hashutil.cuh:192
Here is the call graph for this function:

◆ packedWindowMask()

template<typename Config , uint64_t Length>
__host__ __device__ __forceinline__ constexpr uint64_t cusbf::detail::packedWindowMask ( )
constexpr

Bit mask retaining the low Length symbols of a packed k-mer.

Definition at line 119 of file filter_common.cuh.

119 {
120 if constexpr (Length * Config::symbolBits >= 64) {
121 return std::numeric_limits<uint64_t>::max();
122 } else {
123 return (uint64_t{1} << (Config::symbolBits * Length)) - 1;
124 }
125}
Here is the call graph for this function:

◆ parse_env_mebibytes()

uint64_t cusbf::detail::parse_env_mebibytes ( std::string_view  value)
inline

Parses a decimal mebibyte count from value.

Accepts a leading decimal prefix (same spirit as strtoull). Returns 0 when value is empty or does not start with digits.

Definition at line 16 of file host_parse.hpp.

16 {
17 if (value.empty()) {
18 return 0;
19 }
20
21 uint64_t mebibytes = 0;
22 const auto* begin = value.data();
23 const auto* end = begin + value.size();
24 const auto [ptr, ec] = std::from_chars(begin, end, mebibytes);
25 if (ec != std::errc{} || ptr == begin) {
26 return 0;
27 }
28 return mebibytes;
29}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_host_chunk_max_bytes()

size_t cusbf::detail::parse_host_chunk_max_bytes ( const char env_name)
inline

Definition at line 14 of file fastx_host_limits.cuh.

14 {
15 const uint64_t mebibytes = parse_env_mebibytes(getenv_value(env_name));
16 if (mebibytes == 0) {
17 return 0;
18 }
19 return static_cast<size_t>(mebibytes) << 20;
20}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ prepare_dense_packed_tiles()

template<typename Config >
__device__ __forceinline__ bool cusbf::detail::prepare_dense_packed_tiles ( const uint64_t words,
uint64_t  block_start_kmer,
uint64_t  block_kmers,
uint64_t word_tile,
uint8_t sequence_tile 
)

Fills sequence_tile with encoded symbols for k-mers starting at block_start_kmer.

Cooperatively loads the covering uint64_t words into word_tile, then decodes symbols from shared memory to avoid repeated global loads across overlapping k-mers.

Returns
true when every symbol in the tile is valid.

Definition at line 90 of file dense_packed.cuh.

96 {
97 constexpr uint64_t symbols_per_word = dense_packed_symbols_per_word<Config>();
98 const uint64_t tile_symbols = block_kmers + Config::k - 1;
99 const uint64_t first_symbol = block_start_kmer;
100 const uint64_t last_symbol = block_start_kmer + tile_symbols - 1;
101 const uint64_t first_word = first_symbol / symbols_per_word;
102 const uint64_t last_word = last_symbol / symbols_per_word;
103 const uint64_t num_words = last_word - first_word + 1;
104
105 for (uint64_t idx = threadIdx.x; idx < num_words; idx += Config::cudaBlockSize) {
106 word_tile[idx] = words[first_word + idx];
107 }
108 __syncthreads();
109
110 bool local_invalid_symbol = false;
111 for (uint64_t idx = threadIdx.x; idx < tile_symbols; idx += Config::cudaBlockSize) {
112 const uint8_t encoded =
113 dense_packed_symbol_at_local<Config>(word_tile, first_word, first_symbol + idx);
114 sequence_tile[idx] = encoded;
115 local_invalid_symbol |= (encoded == Config::Alphabet::invalidSymbol);
116 }
117 return __syncthreads_count(local_invalid_symbol) == 0;
118}
Here is the call graph for this function:

◆ prepare_sequence_hash_tiles()

template<typename Config >
__device__ __forceinline__ bool cusbf::detail::prepare_sequence_hash_tiles ( const char sequence,
uint64_t  block_start_kmer,
uint64_t  block_kmers,
uint8_t sequence_tile 
)

Encodes a block's sequence slice into sequence_tile and reports global validity.

Returns
true when every encoded base in the tile is valid.

Definition at line 109 of file sequence_kmer.cuh.

114 {
115 const uint64_t tile_bases = block_kmers + Config::k - 1;
116
117 bool local_invalid_base = false;
118 for (uint64_t idx = threadIdx.x; idx < tile_bases; idx += Config::cudaBlockSize) {
119 const uint8_t encoded_base =
120 Config::Alphabet::encode(sequence + (block_start_kmer + idx) * Config::symbolWidth);
121 sequence_tile[idx] = encoded_base;
122 local_invalid_base |= (encoded_base == Config::Alphabet::invalidSymbol);
123 }
124 return __syncthreads_count(local_invalid_base) == 0;
125}
Here is the call graph for this function:

◆ propagate_error()

cuda::std::unexpected< Error > cusbf::detail::propagate_error ( const Error error)
inline

Copies error for propagation (avoids moving out of expected::error()).

Definition at line 212 of file error.hpp.

212 {
213 return cuda::std::unexpected<Error>(Error{error});
214}
Error payload carried in Result on failure.
Definition error.hpp:76
Here is the call graph for this function:

◆ query_available_host_bytes()

size_t cusbf::detail::query_available_host_bytes ( )
inline

Available physical RAM (bytes) for mmap budgeting.

Definition at line 36 of file fastx_host_memory.cuh.

36 {
37#if defined(__linux__)
38 const long page_size = ::sysconf(_SC_PAGESIZE);
39 const long avail_pages = ::sysconf(_SC_AVPHYS_PAGES);
40 if (page_size > 0 && avail_pages > 0) {
41 return static_cast<size_t>(page_size) * static_cast<size_t>(avail_pages);
42 }
43#endif
44 return 0;
45}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ query_cuda_free_memory()

Result< cuda_free_memory > cusbf::detail::query_cuda_free_memory ( )
inline

Queries current device free memory via cudaMemGetInfo.

Definition at line 33 of file fastx_chunk.cuh.

33 {
34 size_t free_bytes = 0;
35 size_t total_bytes = 0;
36 const cudaError_t error = cudaMemGetInfo(&free_bytes, &total_bytes);
37 if (error != cudaSuccess) {
38 return Err(Error::io(std::format("cudaMemGetInfo failed: {}", cudaGetErrorString(error))));
39 }
40 return cuda_free_memory{free_bytes};
41}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ record_kmer_count()

template<typename Config >
constexpr __host__ __device__ uint64_t cusbf::detail::record_kmer_count ( uint64_t  bases)
constexprnoexcept

Definition at line 13 of file record_math.cuh.

13 {
14 const uint64_t symbols = record_symbol_count<Config>(bases);
15 return symbols < Config::k ? 0 : symbols - Config::k + 1;
16}
Here is the call graph for this function:

◆ record_symbol_count()

template<typename Config >
constexpr __host__ __device__ uint64_t cusbf::detail::record_symbol_count ( uint64_t  bases)
constexprnoexcept

Definition at line 8 of file record_math.cuh.

8 {
9 return bases / Config::symbolWidth;
10}
Here is the call graph for this function:

◆ run_fastx_pipeline()

Result< typename Adapter::report_type > cusbf::detail::run_fastx_pipeline ( FastxReaderType reader,
std::string_view  source_name,
double  fill_fraction,
cuda::stream_ref  stream,
fastx_dispatch_path  dispatch_path,
FastxPipelineState state,
Adapter &&  adapter 
)

Definition at line 33 of file fastx_pipeline_core.cuh.

41 {
42 FastxPipelineReleaseGuard release_guard{state};
43
44 const auto gpu_memory = query_cuda_free_memory();
45 if (!gpu_memory) {
46 return Err(Error::resource(gpu_memory.error().message()));
47 }
48
49 const size_t staging_budget_bytes =
50 fastx_staging_budget_bytes<Config>(fill_fraction, gpu_memory->free_bytes);
51 const size_t host_chunk_max_bytes = fastx_host_chunk_max_bytes();
52 const uint64_t sequence_reserve_bytes =
53 fastx_uses_mmap_reader(dispatch_path) ? fastx_file_bytes(source_name) : 0;
54
55 DenseRecordBatchBuilder chunk(sequence_reserve_bytes);
56 FastxRecord record;
57
58 auto collect_all = [&](auto&& maybe_flush) -> Result<void> {
59 for (;;) {
60 const uint64_t local_index = chunk.recordCount();
61 if (!CUSBF_TRY(collect_next_fastx_record(reader, record, chunk))) {
62 break;
63 }
64 adapter.on_record_collected(record, local_index, chunk);
65 CUSBF_TRY(maybe_flush());
66 }
67 return {};
68 };
69
70 if (fastx_is_single_chunk_path(dispatch_path)) {
71 CUSBF_TRY(collect_all([&]() -> Result<void> { return {}; }));
72 CUSBF_TRY(adapter.flush_sync(chunk, stream));
73 return adapter.finish();
74 }
75
76 if (stream.get() == nullptr && adapter.supports_pipelined()) {
77 const size_t pipelined_chunk_budget =
78 fastx_pipelined_chunk_budget(adapter.chunk_mode(), staging_budget_bytes);
79 ChunkStreamPair chunk_streams;
80 size_t ping = 0;
81 bool has_inflight = false;
82
83 CUSBF_TRY(collect_all([&]() -> Result<void> {
84 if (!fastx_chunk_should_flush<Config>(
85 adapter.chunk_mode(),
86 pipelined_chunk_budget,
87 host_chunk_max_bytes,
88 chunk.raw_sequence_bytes(),
89 chunk.recordCount()
90 )) {
91 return {};
92 }
93 return adapter.flush_pipelined(chunk, chunk_streams, ping, has_inflight);
94 }));
95
96 CUSBF_TRY(adapter.flush_pipelined(chunk, chunk_streams, ping, has_inflight));
97 CUSBF_TRY(chunk_streams.sync_all());
98 CUSBF_TRY(adapter.finish_pipelined(chunk_streams, ping, has_inflight));
99 return adapter.finish();
100 }
101
102 const size_t sync_chunk_budget =
103 stream.get() == nullptr && !adapter.supports_pipelined()
104 ? fastx_pipelined_chunk_budget(adapter.chunk_mode(), staging_budget_bytes)
105 : staging_budget_bytes;
106
107 CUSBF_TRY(collect_all([&]() -> Result<void> {
108 if (!fastx_chunk_should_flush<Config>(
109 adapter.chunk_mode(),
110 sync_chunk_budget,
111 host_chunk_max_bytes,
112 chunk.raw_sequence_bytes(),
113 chunk.recordCount()
114 )) {
115 return {};
116 }
117 return adapter.flush_sync(chunk, stream);
118 }));
119
120 CUSBF_TRY(adapter.flush_sync(chunk, stream));
121 return adapter.finish();
122}
constexpr size_t fastx_pipelined_chunk_budget(fastx_chunk_mode mode, size_t staging_budget_bytes) noexcept
Per-chunk flush budget for dual-stream ping-pong (two device sequence buffers).
constexpr bool fastx_is_single_chunk_path(fastx_dispatch_path path) noexcept
True for fastx_dispatch_path::single_chunk_stream or fastx_dispatch_path::single_chunk_mmap.
Here is the call graph for this function:

◆ select_fastx_dispatch_path()

template<typename Config >
fastx_dispatch_path cusbf::detail::select_fastx_dispatch_path ( const std::filesystem::path &  path,
fastx_chunk_mode  mode,
double  fill_fraction 
)
inline

Selects mmap vs stream and single- vs multi-chunk processing for a path.

Definition at line 114 of file fastx_dispatch.hpp.

118 {
119 if (isGzipFile(path)) {
120 return fastx_dispatch_path::chunked_stream;
121 }
122
123 return select_fastx_dispatch_path_for_file_bytes<Config>(
124 fastx_file_bytes(path), mode, fill_fraction, fastx_file_fits_in_memory(path)
125 );
126}
Here is the call graph for this function:

◆ select_fastx_dispatch_path_for_file_bytes()

template<typename Config >
fastx_dispatch_path cusbf::detail::select_fastx_dispatch_path_for_file_bytes ( uint64_t  file_bytes,
fastx_chunk_mode  mode,
double  fill_fraction,
bool  file_fits_in_memory 
)
inline

Selects mmap vs stream and single- vs multi-chunk processing from file size.

Definition at line 89 of file fastx_dispatch.hpp.

94 {
95 if (file_bytes > 0 && fastx_fits_single_gpu_chunk<Config>(mode, fill_fraction, file_bytes) &&
97 return fastx_dispatch_path::single_chunk_stream;
98 }
99
100 if (file_bytes > 0 && fastx_fits_single_gpu_chunk<Config>(mode, fill_fraction, file_bytes) &&
101 file_fits_in_memory) {
102 return fastx_dispatch_path::single_chunk_mmap;
103 }
104
105 if (file_fits_in_memory) {
106 return fastx_dispatch_path::chunked_mmap;
107 }
108
109 return fastx_dispatch_path::chunked_stream;
110}
uint64_t fastx_single_chunk_stream_max_bytes()
Max raw file size for fastx_dispatch_path::single_chunk_stream (istream, no mmap).
Here is the call graph for this function:

◆ separatorByteAlwaysEncodesInvalid()

template<typename T >
consteval bool cusbf::detail::separatorByteAlwaysEncodesInvalid ( )

Tests that for every position in the input, placing the separator byte at that position always results in an invalid encoding.

This is a necessary condition for the separator to function correctly when concatenating sequences, as it prevents the creation of valid symbols that span across sequence boundaries.

Template Parameters
TAlphabet type to test.
Returns
bool True if the separator byte always produces an invalid encoding at every position, false if any position allows the separator to be part of a valid encoding.

Definition at line 67 of file Alphabet.cuh.

67 {
68 for (uint64_t separatorPosition = 0; separatorPosition < T::symbolWidth; ++separatorPosition) {
69 char input[T::symbolWidth]{};
70 if (!separatorPositionAlwaysEncodesInvalid<T>(input, separatorPosition, 0)) {
71 return false;
72 }
73 }
74 return true;
75}
Here is the call graph for this function:

◆ separatorPositionAlwaysEncodesInvalid()

template<typename T >
consteval bool cusbf::detail::separatorPositionAlwaysEncodesInvalid ( char *  input,
uint64_t  separatorPosition,
uint64_t  index 
)

Recursively tests whether placing the separator byte at any position in an input of valid bytes always results in an invalid encoding.

This ensures that the separator cannot be confused with valid symbols when concatenating sequences.

Template Parameters
TAlphabet type to test.
Parameters
inputBuffer to construct input strings for encoding. Must have length at least T::symbolWidth.
separatorPositionPosition at which to place the separator byte in the input.
indexCurrent index being set in the input. Should be called with 0 initially.
Returns
bool True if the separator byte always produces an invalid encoding, false if any combination of valid bytes with the separator produces a valid encoding.

Definition at line 37 of file Alphabet.cuh.

37 {
38 if (index == T::symbolWidth) {
39 return T::encode(input) == static_cast<uint8_t>(T::invalidSymbol);
40 }
41
42 if (index == separatorPosition) {
43 input[index] = static_cast<char>(T::separator);
44 return separatorPositionAlwaysEncodesInvalid<T>(input, separatorPosition, index + 1);
45 }
46
47 for (uint64_t byteIndex = 0; byteIndex < validByteCount<T>(); ++byteIndex) {
48 input[index] = T::validBytes[byteIndex];
49 if (!separatorPositionAlwaysEncodesInvalid<T>(input, separatorPosition, index + 1)) {
50 return false;
51 }
52 }
53 return true;
54}
Here is the call graph for this function:

◆ trimTrailingCarriageReturn()

void cusbf::detail::trimTrailingCarriageReturn ( std::string &  line)
inline

Removes a trailing carriage return from line if present (Windows line endings).

Definition at line 261 of file Fastx.hpp.

261 {
262 if (!line.empty() && line.back() == '\r') {
263 line.pop_back();
264 }
265}

◆ try_unwrap_success() [1/2]

template<typename T >
T cusbf::detail::try_unwrap_success ( Result< T > &  result)

Definition at line 203 of file error.hpp.

203 {
204 return std::move(*result);
205}
Here is the call graph for this function:

◆ try_unwrap_success() [2/2]

void cusbf::detail::try_unwrap_success ( Result< void > &  result)
inline

Definition at line 207 of file error.hpp.

207 {
208 (void)result;
209}
Here is the call graph for this function:

◆ validate_fastx_staging_fits()

template<typename Config >
Result< void > cusbf::detail::validate_fastx_staging_fits ( fastx_chunk_mode  mode,
double  fill_fraction,
uint64_t  raw_bytes,
uint64_t  record_count,
std::string_view  source_name 
)
inline
Returns
Resource error if raw_bytes / record_count exceed the GPU staging budget.

Definition at line 179 of file fastx_chunk.cuh.

185 {
186 const auto gpu_memory = query_cuda_free_memory();
187 if (!gpu_memory) {
188 return Err(gpu_memory.error());
189 }
190 const size_t staging_budget_bytes =
191 fastx_staging_budget_bytes<Config>(fill_fraction, gpu_memory->free_bytes);
192 if (!fastx_chunk_reached_staging_budget<Config>(
193 mode, staging_budget_bytes, raw_bytes, record_count
194 )) {
195 return {};
196 }
197
198 return Err(
199 Error::resource(
200 std::format(
201 "{}: FASTX input requires more GPU memory than available at fill_fraction={} "
202 "(free staging budget {} bytes)",
203 source_name,
204 fill_fraction,
205 staging_budget_bytes
206 )
207 )
208 );
209}
Result< cuda_free_memory > query_cuda_free_memory()
Queries current device free memory via cudaMemGetInfo.
Here is the call graph for this function:

◆ validByteCount()

template<typename T >
consteval uint64_t cusbf::detail::validByteCount ( )

Definition at line 14 of file Alphabet.cuh.

14 {
15 uint64_t count = 0;
16 while (T::validBytes[count] != '\0') {
17 ++count;
18 }
19 return count;
20}

◆ warpReduceOr()

__device__ __forceinline__ uint64_t cusbf::detail::warpReduceOr ( uint32_t  peers,
uint64_t  value 
)

OR-reduce a uint64_t across the lanes in a peer mask.

On sm_80+ uses __reduce_or_sync, on older architectures falls back to a shuffle-based reduction.

Definition at line 84 of file helpers.cuh.

84 {
85#if __CUDA_ARCH__ >= 800
86 auto lo = __reduce_or_sync(peers, static_cast<uint32_t>(value));
87 auto hi = __reduce_or_sync(peers, static_cast<uint32_t>(value >> 32));
88 return (static_cast<uint64_t>(hi) << 32) | lo;
89#else
90 // Shuffle-based reduction across the lanes set in `peers`.
91 uint32_t remaining = peers;
92 while (remaining) {
93 int src = __ffs(remaining) - 1;
94 uint64_t other =
95 (static_cast<uint64_t>(__shfl_sync(peers, static_cast<uint32_t>(value >> 32), src))
96 << 32) |
97 __shfl_sync(peers, static_cast<uint32_t>(value), src);
98 value |= other;
99 remaining &= remaining - 1; // clear lowest set bit
100 }
101 return value;
102#endif
103}
Here is the call graph for this function:

Variable Documentation

◆ kContainsSequenceStride

constexpr uint32_t cusbf::detail::kContainsSequenceStride = 4
inlineconstexpr

K-mers processed per query thread per inner loop iteration.

Definition at line 22 of file filter_common.cuh.

◆ kDefaultFastxHostRamSlackBytes

constexpr size_t cusbf::detail::kDefaultFastxHostRamSlackBytes = 4u << 30
inlineconstexpr

Default headroom left for the OS and other processes when sizing mmap.

Definition at line 20 of file fastx_host_memory.cuh.

◆ kInvalidHash

constexpr uint64_t cusbf::detail::kInvalidHash = std::numeric_limits<uint64_t>::max()
inlineconstexpr

Sentinel hash value indicating "no valid minimizer found".

Definition at line 25 of file filter_common.cuh.