C++ API#
-
namespace kvikio#
KvikIO namespace.
Typedefs
-
using PageAlignedBounceBufferPool = BounceBufferPool<PageAlignedAllocator>#
Bounce buffer pool using page-aligned host memory.
Use for: Host-only Direct I/O operations (no CUDA context involvement)
-
using CudaPinnedBounceBufferPool = BounceBufferPool<CudaPinnedAllocator>#
Bounce buffer pool using CUDA pinned memory.
Use for: Device I/O operations without Direct I/O Note: Not page-aligned - cannot be used with Direct I/O
-
using CudaPageAlignedPinnedBounceBufferPool = BounceBufferPool<CudaPageAlignedPinnedAllocator>#
Bounce buffer pool using page-aligned CUDA-registered pinned memory.
Use for: Device I/O operations with Direct I/O enabled Provides both page alignment (for Direct I/O) and CUDA registration (for efficient transfers)
-
using Clock = std::chrono::steady_clock#
The clock KvikIO timestamps observations with.
-
using Duration = std::chrono::nanoseconds#
A length of time, in nanoseconds.
-
using ThreadPool = BS::thread_pool#
Thread pool type used for parallel I/O operations.
Enums
-
enum class CompatMode : uint8_t#
I/O compatibility mode.
Values:
-
enumerator OFF#
Enforce cuFile I/O. GDS will be activated if the system requirements for cuFile are met and cuFile is properly configured. However, if the system is not suited for cuFile, I/O operations under the OFF option may error out.
-
enumerator ON#
Enforce POSIX I/O.
-
enumerator AUTO#
Try cuFile I/O first, and fall back to POSIX I/O if the system requirements for cuFile are not met.
-
enumerator OFF#
-
enum class IoBackend : std::uint8_t#
The I/O backend that carried out an operation.
Values:
-
enumerator POSIX#
POSIX
pread/pwrite, including the compatibility-mode path.
-
enumerator GDS#
cuFile / GPUDirect Storage.
-
enumerator MMAP#
Memory-mapped file access.
-
enumerator REMOTE_HTTP#
Remote I/O over HTTP(S), including S3.
-
enumerator REMOTE_HDFS#
Remote I/O over WebHDFS.
-
enumerator POSIX#
-
enum class TransferDirection : std::uint8_t#
The direction of an I/O operation.
Values:
-
enumerator READ#
Data moves from the file or endpoint into the buffer.
-
enumerator WRITE#
Data moves from the buffer into the file or endpoint.
-
enumerator READ#
-
enum class MemoryKind : std::uint8_t#
The kind of memory the caller’s buffer lives in.
Values:
-
enumerator HOST#
Host (CPU) memory.
-
enumerator DEVICE#
Device (GPU) memory.
-
enumerator HOST#
-
enum class ObservationKind : std::uint8_t#
What layer an observation describes.
Values:
-
enumerator LOGICAL#
One user-facing call, such as one
FileHandle::pread().
-
enumerator PHYSICAL#
One transfer occupying a thread or a connection, such as one thread-pool task.
-
enumerator LOGICAL#
-
enum class RemoteEndpointType : uint8_t#
Types of remote file endpoints supported by KvikIO.
This enum defines the different protocols and services that can be used to access remote files. It is used to specify or detect the type of remote endpoint when opening files.
Values:
-
enumerator AUTO#
Automatically detect the endpoint type from the URL. KvikIO will attempt to infer the appropriate protocol based on the URL format.
-
enumerator S3#
AWS S3 endpoint using credentials-based authentication. Requires AWS environment variables (such as AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION) to be set.
-
enumerator S3_PUBLIC#
AWS S3 endpoint for publicly accessible objects. No credentials required as the objects have public read permissions enabled. Used for open datasets and public buckets.
-
enumerator S3_PRESIGNED_URL#
AWS S3 endpoint using a presigned URL. No credentials required as authentication is embedded in the URL with time-limited access.
-
enumerator WEBHDFS#
Apache Hadoop WebHDFS (Web-based Hadoop Distributed File System) endpoint for accessing files stored in HDFS over HTTP/HTTPS.
-
enumerator HTTP#
Generic HTTP or HTTPS endpoint for accessing files from web servers. This is used for standard web resources that do not fit the other specific categories.
-
enumerator AUTO#
-
enum class RemoteIOBackend : uint8_t#
Selects the remote I/O backend.
Naming scheme is
<libcurl-API-flavor>_<execution-method>. Selection is controlled by the environment variableKVIKIO_REMOTE_IO_BACKEND.Values:
-
enumerator EASY_THREADPOOL#
Libcurl easy API running in the KvikIO thread pool. Each sub-range of a
pread()is dispatched to a worker thread that blocks incurl_easy_perform()until its transfer completes. Concurrency is bounded by the thread pool size: one busy thread per in-flight transfer.
-
enumerator MULTI_POLL#
Libcurl multi API driven by N reactor threads, each of which blocks in
curl_multi_poll(). A single reactor multiplexes many in-flight easy handles concurrently, so the number of simultaneous transfers is not bounded by the reactor count. SeeKVIKIO_REMOTE_IO_NUM_REACTORSandKVIKIO_REMOTE_IO_REACTOR_DISPATCH.
-
enumerator EASY_THREADPOOL#
-
enum class RemoteReactorDispatch : uint8_t#
How sub-ranges of a single
pread()are distributed across reactor threads when theMULTI_POLLbackend is active.Controlled by
KVIKIO_REMOTE_IO_REACTOR_DISPATCH. When only one reactor is used, both modes are equivalent.Values:
-
enumerator PER_CHUNK#
Sub-ranges are routed to reactors round-robin, independently of which
pread()they belong to. This maximizes load balance across reactors. Trade-off: two sub-ranges of the same file may land on different reactors, each with its own libcurl connection cache, so they may not share an established TCP/TLS connection.
-
enumerator PER_PREAD#
All sub-ranges of a single
pread()are submitted to the same reactor (the reactor is itself chosen round-robin perpread()call). The sub-ranges then share that reactor’s libcurl connection cache, allowing an established TCP/TLS connection to be reused. Best for HTTPS, where the TLS handshake cost is non-trivial.
-
enumerator PER_CHUNK#
Functions
- void buffer_register(
- void const *devPtr_base,
- std::size_t size,
- int flags = 0,
- std::vector<int> const &errors_to_ignore = std::vector<int>()
Register a device memory region with cuFile for GPUDirect Storage access.
This is the low-level registration function that requires the caller to specify the exact base address and size of the memory region to register. For a convenience wrapper that automatically discovers the allocation boundaries, see memory_register().
Registration pins the memory for GPU Direct DMA transfers, which can improve performance when the same buffer is reused across multiple cuFile I/O operations.
In compatibility mode (when GDS is unavailable), this function is a no-op.
See also
memory_register for automatic discovery of allocation base address and size.
See also
buffer_deregister to deregister the memory.
Warning
This API is intended for streaming buffers reused across multiple cuFile I/O operations. For one-time transfers, the overhead of registration may outweigh the benefits.
- Parameters:
devPtr_base – Base address of the device memory region to register.
size – Size in bytes of the memory region to register.
flags – Registration flags. Should be 0 or
CU_FILE_RDMA_REGISTER(experimental).errors_to_ignore – cuFile error codes to silently ignore, such as
CU_FILE_MEMORY_ALREADY_REGISTEREDorCU_FILE_INVALID_MAPPING_SIZE.
- Throws:
CUfileException – If cuFile registration fails with an error not in
errors_to_ignore.
-
void buffer_deregister(void const *devPtr_base)#
Deregister a device memory region from cuFile.
This is the low-level deregistration function that requires the caller to specify the exact base address that was previously registered. For a convenience wrapper that automatically discovers the allocation boundaries, see memory_deregister().
In compatibility mode (when GDS is unavailable), this function is a no-op.
See also
memory_deregister for automatic discovery of allocation base address.
See also
buffer_register to register the memory.
- Parameters:
devPtr_base – Base address of the device memory region to deregister. Must match the address used in the corresponding buffer_register() call.
- Throws:
CUfileException – If cuFile deregistration fails.
- void memory_register(
- void const *devPtr,
- int flags = 0,
- std::vector<int> const &errors_to_ignore = {}
Register a device memory allocation with cuFile for GPUDirect Storage access. Use this function together with FileHandle::pread() and FileHandle::pwrite().
This is a convenience wrapper around buffer_register() that automatically discovers the base address and size of the CUDA memory allocation containing
devPtr. The entire underlying allocation is registered, regardless of which portiondevPtrpoints to.Registration pins the memory for GPU Direct DMA transfers, which can improve performance when the same buffer is reused across multiple cuFile I/O operations.
In compatibility mode (when GDS is unavailable), this function is a no-op.
See also
buffer_register for registering with explicit base address and size.
See also
memory_deregister to deregister the memory.
Warning
This API is intended for streaming buffers reused across multiple cuFile I/O operations. For one-time transfers, the overhead of registration may outweigh the benefits.
- Parameters:
devPtr – Pointer anywhere within a CUDA device memory allocation.
flags – Registration flags. Should be 0 or
CU_FILE_RDMA_REGISTER(experimental).errors_to_ignore – cuFile error codes to silently ignore, such as
CU_FILE_MEMORY_ALREADY_REGISTEREDorCU_FILE_INVALID_MAPPING_SIZE.
- Throws:
CUfileException – If cuFile registration fails with an error not in
errors_to_ignore.
-
void memory_deregister(void const *devPtr)#
Deregister a device memory allocation from cuFile.
This is a convenience wrapper around buffer_deregister() that automatically discovers the base address of the CUDA memory allocation containing
devPtr. The entire underlying allocation is deregistered, regardless of which portiondevPtrpoints to.In compatibility mode (when GDS is unavailable), this function is a no-op.
See also
buffer_deregister for deregistering with explicit base address.
See also
memory_register to register the memory.
- Parameters:
devPtr – Pointer anywhere within a previously registered CUDA device memory allocation.
- Throws:
CUfileException – If cuFile deregistration fails.
-
std::string const &config_path()#
Get the filepath to cuFile’s config file (
cufile.json) or the empty string.This lookup is cached.
- Returns:
The filepath to the cufile.json file or the empty string if it isn’t found.
-
template<>
bool getenv_or( - std::string_view env_var_name,
- bool default_val
-
template<>
CompatMode getenv_or( - std::string_view env_var_name,
- CompatMode default_val
-
template<>
std::vector<int> getenv_or( - std::string_view env_var_name,
- std::vector<int> default_val
-
template<>
RemoteIOBackend getenv_or( - std::string_view env_var_name,
- RemoteIOBackend default_val
-
template<>
RemoteReactorDispatch getenv_or( - std::string_view env_var_name,
- RemoteReactorDispatch default_val
-
template<typename T>
std::tuple<std::string_view, T, bool> getenv_or( - std::initializer_list<std::string_view> env_var_names,
- T default_val
Get the environment variable value from a candidate list.
- Template Parameters:
T – Type of the environment variable value
- Parameters:
env_var_names – Candidate list containing the names of environment variable
default_val – Default value of the environment variable, if none of the candidates has been found
- Throws:
std::invalid_argument – if:
env_var_namesis empty.The environment variable is not defined to be string type and is assigned an empty value (in other words, string-type environment variables are allowed to hold an empty value).
More than one candidates have been set with different values.
An invalid value is given, e.g. value that cannot be converted to type T.
- Returns:
A tuple of (
env_var_name,result,has_found), where:If the environment variable is not set by any of the candidates,
has_foundwill be false,resultwill bedefault_val, andenv_var_namewill be empty.If the environment variable is set by
env_var_name, thenhas_foundwill be true, andresultbe the set value. If more than one candidates have been set with the same value,env_var_namewill be assigned the last candidate.
-
int open_fd_parse_flags(std::string const &flags, bool o_direct)#
Parse open file flags given as a string and return oflags.
- Parameters:
flags – The flags
o_direct – Append O_DIRECT to the open flags
- Throws:
std::invalid_argument – if the specified flags are not supported.
std::invalid_argument – if
o_directis true, butO_DIRECTis not supported.
- Returns:
oflags
- int open_fd(
- std::string const &file_path,
- std::string const &flags,
- bool o_direct,
- mode_t mode
Open file using
open(2)- Parameters:
flags – Open flags given as a string
o_direct – Append O_DIRECT to
flagsmode – Access modes
- Returns:
File descriptor
-
int open_flags(int fd)#
Get the flags of the file descriptor (see
open(2))- Returns:
Open flags
-
std::size_t get_file_size(std::string const &file_path)#
Get file size from file descriptor
fstat(3)- Parameters:
file_path – Path to the file
- Returns:
The number of bytes
-
std::size_t get_file_size(int file_descriptor)#
Get file size given the file path.
- Parameters:
file_descriptor – Open file descriptor
- Returns:
The number of bytes
- std::pair<std::size_t, std::size_t> get_page_cache_info(
- std::string const &file_path,
- std::size_t offset = 0,
- std::size_t length = 0
Obtain the page cache residency information for a given file.
Note
See
get_page_cache_info(int, std::size_t, std::size_t)for detailed behavior and caveats- Parameters:
file_path – Path to the file.
offset – Starting byte offset (default: 0 for beginning of file)
length – Number of bytes to query (default: 0, meaning entire file from offset)
- Returns:
A pair containing the number of pages resident in the page cache and the total number of pages.
- std::pair<std::size_t, std::size_t> get_page_cache_info(
- int fd,
- std::size_t offset = 0,
- std::size_t length = 0
Obtain the page cache residency information for a given file.
Note
If
offsetis beyond the end of the file, returns {0, 0}.Note
If
offset+lengthextends beyond the file, the query is clamped to the file size.Note
The page cache residency query takes place in granularity of full pages. If the specified range does not align to page boundaries, partial pages at the start and end of the range are included.
- Parameters:
fd – Open file descriptor.
offset – Starting byte offset (default: 0 for beginning of file)
length – Number of bytes to query (default: 0, meaning entire file from offset)
- Returns:
A pair containing the number of pages resident in the page cache and the total number of pages.
- void drop_file_page_cache(
- int fd,
- std::size_t offset = 0,
- std::size_t length = 0,
- bool sync_first = true
Drop page cache for a specific file.
Advises the kernel to evict cached pages for the specified file descriptor using
posix_fadvisewithPOSIX_FADV_DONTNEED.Note
This is the preferred method for benchmark cache invalidation as it:
Requires no elevated privileges
Affects only the specified file, not other processes
Has minimal overhead (no child process spawned)
Note
The page cache dropping takes place in granularity of full pages. If the specified range does not align to page boundaries, partial pages at the start and end of the range are retained. Only pages fully contained within the range are dropped.
Note
For dropping page cache system-wide (requires elevated privileges), see
drop_system_page_cache().- Parameters:
fd – Open file descriptor
offset – Starting byte offset (default: 0 for beginning of file)
length – Number of bytes to drop (default: 0, meaning entire file from offset)
sync_first – Whether to flush dirty pages to disk before dropping. If
true,fdatasyncwill be called prior to dropping. This ensures dirty pages become clean and thus droppable. Can be set tofalseif we are certain no dirty pages exist for this file.
- Throws:
kvikio::GenericSystemError – if the file descriptor is invalid, or the file cannot be synchronized, or the attempt to drop the page cache fails.
- void drop_file_page_cache(
- std::string const &file_path,
- std::size_t offset = 0,
- std::size_t length = 0,
- bool sync_first = true
Drop page cache for a specific file.
Convenience overload that opens the file, drops its page cache, and closes it.
Note
For dropping page cache system-wide (requires elevated privileges), see
drop_system_page_cache().Note
See
drop_file_page_cache(int, std::size_t, std::size_t, bool)for detailed behavior and caveats- Parameters:
file_path – Path to the file
offset – Starting byte offset (default: 0 for beginning of file)
length – Number of bytes to drop (default: 0, meaning entire file from offset)
sync_first – Whether to flush dirty pages to disk before dropping. If
true,fdatasyncwill be called prior to dropping. This ensures dirty pages become clean and thus droppable. Can be set tofalseif we are certain no dirty pages exist for this file.
- Throws:
kvikio::GenericSystemError – if the file cannot be opened, or the file cannot be synchronized, or the attempt to drop the page cache fails.
- bool drop_system_page_cache(
- bool reclaim_dentries_and_inodes = true,
- bool sync_first = true
Drop the system page cache.
Note
This drops page cache system-wide, affecting all processes. For dropping cache for a specific file without elevated privileges, see
drop_file_page_cache(int, std::size_t, std::size_t, bool).Note
This function creates a child process and executes the cache dropping shell command in the following order:
Execute the command without
sudoprefix. This is for the superuser and also for specially configured systems where unprivileged users cannot execute/usr/bin/sudobut can execute/sbin/sysctl. If this step succeeds, the function returnstrueimmediately.Execute the command with
sudoprefix. This is for the general case where selective unprivileged users have permission to run/sbin/sysctlwithsudoprefix.
- Parameters:
reclaim_dentries_and_inodes – Whether to free reclaimable slab objects which include dentries and inodes.
If
true, equivalent to executing/sbin/sysctl vm.drop_caches=3;If
false, equivalent to executing/sbin/sysctl vm.drop_caches=1.
sync_first – Whether to flush dirty pages to disk before dropping. If
true,syncwill be called prior to dropping. This ensures dirty pages become clean and thus droppable.
- Throws:
kvikio::GenericSystemError – if somehow the child process could not be created.
- Returns:
Whether the page cache has been successfully dropped.
- bool clear_page_cache(
- bool reclaim_dentries_and_inodes = true,
- bool clear_dirty_pages = true
Drop the system page cache. Deprecated. Use
drop_system_page_cacheinstead.
-
BlockDeviceInfo get_block_device_info(std::string const &file_path)#
Get information about the physical block device hosting a file.
Resolves the underlying block device for a given file path, handling:
Partitions: walks up to the parent block device (e.g., sda1 -> sda)
NVMe namespaces: maps to the controller (e.g., nvme0n1 -> nvme0)
Other block devices (SATA, SAS, dm, md): returns the device’s own info
Note
Limitations:
For device-mapper devices (LVM, dm-crypt), this returns the dm device ID, not the underlying physical device(s). This may be suboptimal when multiple LVs share the same underlying physical drive (over-subscription) or when a single LV is striped across multiple drives (under-utilization).
Files residing on virtual filesystems (overlayfs, tmpfs) or network filesystems (NFS, CIFS, FUSE) are not backed by a local block device, and this function will throw.
- Parameters:
file_path – Path to the file whose block device ID is to be determined.
- Throws:
kvikio::GenericSystemError – if the file does not exist, or if the block device cannot be determined (e.g., virtual or network filesystem).
- Returns:
Block device info for the underlying physical block device.
-
rapids_logger::logger &default_logger()#
Returns the global logger instance for KvikIO.
The logger is configured once on first access using the following environment variables:
KVIKIO_LOG_LEVEL: Sets the log level. Accepted values (case-insensitive) areTRACE,DEBUG,INFO,WARN,ERROR,CRITICAL, andOFF. If unset or set to any other value, logging is disabled.KVIKIO_LOG_FILE: If set, log output is written to this file path (overwritten on each process start). If the file cannot be opened, falls back to stderr with a warning. Has no effect when logging is disabled.
- Returns:
Reference to the global KvikIO logger
-
std::string_view to_string(IoBackend backend) noexcept#
Human-readable name of an I/O backend.
- Parameters:
backend – The backend.
- Returns:
A static string such as
"POSIX".
-
std::string_view to_string(TransferDirection direction) noexcept#
Human-readable name of a transfer direction.
- Parameters:
direction – The direction.
- Returns:
A static string such as
"READ".
-
std::string_view to_string(MemoryKind memory_kind) noexcept#
Human-readable name of a memory kind.
- Parameters:
memory_kind – The memory kind.
- Returns:
A static string such as
"DEVICE".
-
std::string_view to_string(ObservationKind kind) noexcept#
Human-readable name of an observation kind.
- Parameters:
kind – The kind.
- Returns:
A static string such as
"LOGICAL".
- std::uint64_t register_monitor(
- Monitor *monitor,
- ObservationKind kind = ObservationKind::LOGICAL
Register a monitor, which begins receiving both notifications.
- Parameters:
monitor – The monitor. Not owned, and must outlive the registration.
kind – Which observations it watches.
- Throws:
std::invalid_argument – if
monitoris null.std::runtime_error – if called from inside a monitor callback.
- Returns:
An id for
unregister_monitor().
-
void unregister_monitor(std::uint64_t id)#
Unregister a monitor.
Blocks until no thread is inside either callback, so the monitor may be destroyed once this returns.
- Parameters:
id – The id from
register_monitor().
-
RemoteEndpointType infer_remote_endpoint_type(std::string const &url)#
Infer remote endpoint type from URL.
This function follows the same endpoint-selection order as
RemoteHandle::open()inRemoteEndpointType::AUTOmode, but only infers the endpoint type and does not create a handle. Note that this function will not returnRemoteEndpointType::S3_PUBLIC, because disambiguating between a URL that’s accessible only with authorization or only anonymously is not possible without making an HTTP request.- Parameters:
url – The URL of the remote file.
- Returns:
The inferred endpoint type.
-
void stream_register(CUstream stream, unsigned flags)#
Registers the CUDA stream to the cuFile subsystem.
- Parameters:
stream – CUDA stream which queues the async I/O operations
flags – Specifies when the I/O parameters become valid (submission time or execution time) and what I/O parameters are page-aligned. For details, refer to https://docs.nvidia.com/gpudirect-storage/api-reference-guide/index.html#cufilestreamregister
-
void stream_deregister(CUstream stream)#
Deregisters the CUDA stream from the cuFile subsystem.
- Parameters:
stream – CUDA stream which queues the async I/O operations
- inline std::function<void()> make_thread_pool_init_task(
- std::string prefix
Build a
BS::thread_poolinit task that names each worker thread.The returned functor is intended to be passed to
BS::thread_pool’s constructor orreset()overloads that accept aninit_task. It runs once per worker as the pool starts each thread, setting the OS-level thread name (common Linux) to"<prefix>-<index>"so profilers such as nsys,top -H, and/proc/<pid>/task/<tid>/commshow meaningful names instead of the parent process name.The per-thread index is assigned via an atomic counter captured by the returned functor, so different pools can share the same prefix without colliding.
Linux caps thread names at 15 characters plus NUL, so keep
prefixshort (typically 10 characters or fewer).- Parameters:
prefix – Name prefix, e.g.
"kvikio"or"kvikio-bdev".- Returns:
An init task suitable for
BS::thread_pool.
-
std::size_t get_page_size()#
-
off_t convert_size2off(std::size_t x)#
-
ssize_t convert_size2ssize(std::size_t x)#
-
CUdeviceptr convert_void2deviceptr(void const *devPtr)#
-
template<typename T, std::enable_if_t<std::is_integral_v<T>>* = nullptr>
std::int64_t convert_to_64bit( - T value
Help function to convert value to 64 bit signed integer.
-
inline std::uint64_t convert_to_64bit(std::uint64_t value)#
Helper function to allow NVTX payload of type std::uint64_t to pass through without doing anything.
-
template<typename T, std::enable_if_t<std::is_floating_point_v<T>>* = nullptr>
double convert_to_64bit( - T value
Help function to convert value to 64 bit float.
-
bool is_host_memory(void const *ptr)#
Check if
ptrpoints to host memory (as opposed to device memory)In this context, managed memory counts as device memory
- Parameters:
ptr – Memory pointer to query
- Returns:
The boolean answer
-
int get_device_ordinal_from_pointer(CUdeviceptr dev_ptr)#
Return the device owning the pointer.
- Parameters:
ptr – Device pointer to query
- Returns:
The device ordinal
-
CUcontext get_primary_cuda_context(int ordinal)#
Given a device ordinal, return the primary context of the device.
This function caches the primary contexts retrieved until program exit
- Parameters:
ordinal – Device ordinal - an integer between 0 and the number of CUDA devices
- Returns:
Primary CUDA context
- std::optional<CUcontext> get_context_associated_pointer(
- CUdeviceptr dev_ptr
Return the CUDA context associated the given device pointer, if any.
- Parameters:
dev_ptr – Device pointer to query
- Returns:
Usable CUDA context, if one were found.
-
bool current_context_can_access_pointer(CUdeviceptr dev_ptr)#
Check if the current CUDA context can access the given device pointer.
- Parameters:
dev_ptr – Device pointer to query
- Returns:
The boolean answer
-
CUcontext get_context_from_pointer(void const *devPtr)#
Return a CUDA context that can be used with the given device pointer.
For robustness, we look for an usabale context in the following order: 1) If a context has been associated with
devPtr, it is returned. 2) If the current context exists and can accessdevPtr, it is returned. 3) Return the primary context of the device that ownsdevPtr. We assume the primary context can accessdevPtr, which might not be true in the exceptional disjoint addressing cases mention in the CUDA docs[1]. In these cases, the user has to set an usable current context before reading/writing using KvikIO.[1] https://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__UNIFIED.html
- Parameters:
devPtr – Device pointer to query
- Returns:
Usable CUDA context
- std::tuple<void*, std::size_t, std::size_t> get_alloc_info(
- void const *devPtr,
- CUcontext *ctx = nullptr
-
template<typename T>
std::future<std::decay_t<T>> make_ready_future( - T &&t
Create a shared state in a future object that is immediately ready.
A partial implementation of the namesake function from the concurrency TS (https://en.cppreference.com/w/cpp/experimental/make_ready_future). The cases of std::reference_wrapper and void are not implemented.
- Template Parameters:
T – Type of the value provided.
- Parameters:
t – Object provided.
- Returns:
A future holding a decayed copy of the object provided.
-
template<typename T>
bool is_future_done(T const &future)# Check the status of the future object. True indicates that the result is available in the future’s shared state. False otherwise.
The future shall not be created using
std::async(std::launch::deferred). Otherwise, this function always returns true.- Template Parameters:
T – Type of the future.
- Parameters:
future – Instance of the future.
- Returns:
Boolean answer indicating if the future is ready or not.
Variables
-
constexpr std::size_t num_io_backends = static_cast<std::size_t>(IoBackend::REMOTE_HDFS) + 1#
Number of
IoBackendvalues.
-
constexpr std::size_t num_observation_kinds = static_cast<std::size_t>(ObservationKind::PHYSICAL) + 1#
Number of
ObservationKindvalues.
-
struct BatchOp#
- #include <batch.hpp>
IO operation used when submitting batches.
-
class BatchHandle#
- #include <batch.hpp>
Handle of an cuFile batch using semantic.
The workflow is as follows: 1) Create a batch with a large enough
max_num_events. 2) Call.submit()with a vector of operations (vector.size() <= max_num_events). 3) Call.status()to wait on the operations to finish, or 3) Call.cancel()to cancel the operations. 4) Go to step 2 or call.close()to free up resources.Notice, a batch handle can only handle one “submit” at a time and is closed in the destructor automatically.
Public Functions
-
BatchHandle(int max_num_events)#
Construct a batch handle.
- Parameters:
max_num_events – The maximum number of operations supported by this instance.
-
BatchHandle(BatchHandle const&) = delete#
BatchHandle support move semantic but isn’t copyable.
-
void close() noexcept#
Destroy the batch handle and free up resources.
-
void submit(std::vector<BatchOp> const &operations)#
Submit a vector of batch operations.
- Parameters:
operations – The vector of batch operations, which must not exceed the
max_num_events.
- std::vector<CUfileIOEvents_t> status(
- unsigned min_nr,
- unsigned max_nr,
- struct timespec *timeout = nullptr
Get status of submitted operations.
- Parameters:
min_nr – The minimum number of IO entries for which status is requested.
max_nr – The maximum number of IO requests to poll for.
timeout – This parameter is used to specify the amount of time to wait for in this API, even if the minimum number of requests have not completed. If the timeout hits, it is possible that the number of returned IOs can be less than
min_nr
- Returns:
Vector of the status of the completed I/Os in the batch.
-
BatchHandle(int max_num_events)#
-
class PageAlignedAllocator#
- #include <bounce_buffer.hpp>
Allocator for page-aligned host memory.
Uses std::aligned_alloc to allocate host memory aligned to page boundaries (typically 4096 bytes). This allocator is suitable for Direct I/O operations that require page-aligned buffers but do not need CUDA context (i.e., host-to-host transfers only).
Public Functions
-
void *allocate(std::size_t size)#
Allocate page-aligned host memory.
- Parameters:
size – Requested size in bytes (will be rounded up to page boundary)
- Returns:
Pointer to allocated memory
-
void deallocate(void *buffer, std::size_t size)#
Deallocate memory previously allocated by this allocator.
- Parameters:
buffer – Pointer to memory to deallocate
size – Size of the allocation (unused, for interface consistency)
-
void *allocate(std::size_t size)#
-
class CudaPinnedAllocator#
- #include <bounce_buffer.hpp>
Allocator for CUDA pinned host memory.
Uses cudaMemHostAlloc to allocate pinned (page-locked) host memory that can be efficiently transferred to/from GPU device memory. The allocation is only guaranteed to be aligned to “at
least 256 bytes”. It is NOT guaranteed to be page aligned.
Note
Do NOT use with Direct I/O - lacks page alignment guarantee
Public Functions
-
void *allocate(std::size_t size)#
Allocate CUDA pinned host memory.
- Parameters:
size – Requested size in bytes
- Returns:
Pointer to allocated pinned memory
-
void deallocate(void *buffer, std::size_t size)#
Deallocate memory previously allocated by this allocator.
- Parameters:
buffer – Pointer to memory to deallocate
size – Size of the allocation (unused, for interface consistency)
-
void *allocate(std::size_t size)#
-
class CudaPageAlignedPinnedAllocator#
- #include <bounce_buffer.hpp>
Allocator for page-aligned AND CUDA-registered pinned host memory.
Combines the benefits of both page alignment (for Direct I/O) and CUDA registration (for efficient host-device transfers). Uses std::aligned_alloc followed by cudaMemHostRegister to achieve both properties.
Note
This is the required allocator for Direct I/O with device memory. Requires a valid CUDA context when allocating.
Public Functions
-
void *allocate(std::size_t size)#
Allocate page-aligned CUDA-registered pinned host memory.
- Parameters:
size – Requested size in bytes (will be rounded up to page boundary)
- Returns:
Pointer to allocated memory
-
void deallocate(void *buffer, std::size_t size)#
Deallocate memory previously allocated by this allocator.
- Parameters:
buffer – Pointer to memory to deallocate
size – Size of the allocation (unused, for interface consistency)
-
void *allocate(std::size_t size)#
-
template<typename Allocator = CudaPinnedAllocator>
class BounceBufferPool# - #include <bounce_buffer.hpp>
Thread-safe singleton pool for reusable bounce buffers.
Manages a pool of host memory buffers used for staging data during I/O operations. Buffers are retained and reused across calls to minimize allocation overhead. The pool uses a LIFO (stack) allocation strategy optimized for cache locality.
All buffers in the pool have the same size, controlled by
defaults::bounce_buffer_size(). If the buffer size changes, all cached buffers are cleared and reallocated at the new size.Call
BounceBufferPool::getto get an allocation that will be retained when it goes out of scope (RAII). The size of all retained allocations are the same.Note
The destructor intentionally leaks allocations to avoid CUDA cleanup issues when static destructors run after CUDA context destruction
- Template Parameters:
Allocator – The allocator policy that determines buffer properties:
PageAlignedAllocator: For host-only Direct I/O
CudaPinnedAllocator: For device I/O without Direct I/O
CudaPageAlignedPinnedAllocator: For device I/O with Direct I/O
Public Functions
-
Buffer get()#
Acquire a bounce buffer from the pool.
Returns a cached buffer if available, otherwise allocates a new one. The returned Buffer object will automatically return the buffer to the pool when it goes out of scope.
- Throws:
CudaError – if allocation fails (e.g., invalid CUDA context for pinned allocators)
- Returns:
RAII Buffer object wrapping the allocated memory
-
void put(void *buffer, std::size_t size) noexcept#
Return a buffer to the pool for reuse.
Typically called automatically by Buffer’s destructor. Only adds the buffer to the pool if its size matches the current pool buffer size; otherwise the buffer is deallocated immediately.
Note
noexcept: any failure during the underlying push or deallocation is caught and logged.
- Parameters:
buffer – Pointer to memory to return
size – Size of the buffer in bytes
-
std::size_t clear()#
Free all retained allocations in the pool.
Clears the pool and deallocates all cached buffers. Useful for reclaiming memory when bounce buffers are no longer needed.
- Returns:
The number of bytes cleared
-
std::size_t num_free_buffers() const#
Get the number of free buffers currently available in the pool.
Returns the count of buffers that have been returned to the pool and are ready for reuse.
- Returns:
The number of buffers available for reuse
-
std::size_t buffer_size() const#
Get the current buffer size used by the pool.
Returns the size of buffers currently managed by the pool. This reflects the value of
defaults::bounce_buffer_size()as of the last pool operation.- Returns:
The size in bytes of each buffer in the pool
Public Static Functions
-
static BounceBufferPool &instance()#
Get the singleton instance of the pool.
Each template instantiation (different Allocator) has its own singleton instance.
- Returns:
Reference to the singleton pool instance
-
class Buffer#
- #include <bounce_buffer.hpp>
RAII wrapper for a host bounce buffer allocation.
Automatically returns the buffer to the pool when destroyed (RAII pattern). Provides access to the underlying memory and its size.
Note
Non-copyable but movable to allow transfer of ownership while maintaining RAII
-
class CompatModeManager#
- #include <compat_mode_manager.hpp>
Store and manage the compatibility mode data associated with a FileHandle.
Public Functions
-
CompatModeManager() noexcept = default#
Construct an empty compatibility mode manager.
- CompatModeManager(
- std::string const &file_path,
- std::string const &flags,
- mode_t mode,
- CompatMode compat_mode_requested,
- FileHandle *file_handle
Construct a compatibility mode manager associated with a FileHandle.
According to the file path, requested compatibility mode, and the system configuration, the compatibility manager:
Infers the final compatibility modes for synchronous and asynchronous I/O paths, respectively.
Initializes the file wrappers and cuFile handle associated with a FileHandle.
- Parameters:
file_path – Refer to FileHandle::FileHandle(std::string const&, std::string const&, mode_t, CompatMode).
flags – Same as above.
mode – Same as above.
compat_mode_requested – Same as above.
file_handle – Pointer to the FileHandle object that owns this compatibility mode manager.
-
bool is_compat_mode_preferred() const noexcept#
Check if the compatibility mode for synchronous I/O of the associated FileHandle is expected to be CompatMode::ON.
- Returns:
Boolean answer.
-
bool is_compat_mode_preferred_for_async() const noexcept#
Check if the compatibility mode for asynchronous I/O of the associated FileHandle is expected to be CompatMode::ON.
- Returns:
Boolean answer.
-
CompatMode compat_mode_requested() const noexcept#
Retrieve the original compatibility mode requested.
- Returns:
The original compatibility mode requested.
-
void validate_compat_mode_for_async() const#
Determine if asynchronous I/O can be performed or not (throw exceptions) according to the existing compatibility mode data in the manager.
Asynchronous I/O cannot be performed, for instance, when compat_mode_requested() is CompatMode::OFF, is_compat_mode_preferred() is CompatMode::OFF, but is_compat_mode_preferred_for_async() is CompatMode::ON (due to missing cuFile stream API or cuFile configuration file).
-
CompatModeManager() noexcept = default#
-
struct DriverInitializer#
-
struct DriverProperties#
-
class defaults#
- #include <defaults.hpp>
Singleton class of default values used throughout KvikIO.
Public Static Functions
-
static CompatMode compat_mode()#
Return whether the KvikIO library is running in compatibility mode or not.
Notice, this is not the same as the compatibility mode in cuFile. That is, cuFile can run in compatibility mode while KvikIO is not.
When KvikIO is running in compatibility mode, it doesn’t load
libcufile.so. Instead, reads and writes are done using POSIX.Set the environment variable
KVIKIO_COMPAT_MODEto enable/disable compatibility mode. By default, compatibility mode is enabled:when
libcufilecannot be foundwhen running in Windows Subsystem for Linux (WSL)
when
/run/udevisn’t readable, which typically happens when running inside a docker image not launched with--volume /run/udev:/run/udev:ro
- Returns:
Compatibility mode.
-
static void set_compat_mode(CompatMode compat_mode)#
Set the value of
kvikio::defaults::compat_mode().Changing the compatibility mode affects all the new FileHandles whose
compat_modeargument is not explicitly set, but it never affects existing FileHandles.- Parameters:
compat_mode – Compatibility mode.
- static CompatMode infer_compat_mode_if_auto(
- CompatMode compat_mode
Infer the
AUTOcompatibility mode from the system runtime.If the requested compatibility mode is
AUTO, set the expected compatibility mode toONorOFFby performing a system config check; otherwise, do nothing. Effectively, this function reduces the requested compatibility mode from three possible states (ON/OFF/AUTO) to two (ON/OFF) so as to determine the actual I/O path. This function is lightweight as the inferred result is cached.
-
static bool is_compat_mode_preferred(CompatMode compat_mode) noexcept#
Given a requested compatibility mode, whether it is expected to reduce to
ON.This function returns true if any of the two condition is satisfied:
The compatibility mode is
ON.It is
AUTObut inferred to beON.
Conceptually, the opposite of this function is whether requested compatibility mode is expected to be
OFF, which would occur if any of the two condition is satisfied:The compatibility mode is
OFF.It is
AUTObut inferred to beOFF.
- Parameters:
compat_mode – Compatibility mode.
- Returns:
Boolean answer.
-
static bool is_compat_mode_preferred()#
Whether the global compatibility mode from class defaults is expected to be
ON.This function returns true if any of the two condition is satisfied:
The compatibility mode is
ON.It is
AUTObut inferred to beON.
Conceptually, the opposite of this function is whether the global compatibility mode is expected to be
OFF, which would occur if any of the two condition is satisfied:The compatibility mode is
OFF.It is
AUTObut inferred to beOFF.
- Returns:
Boolean answer.
-
static ThreadPool &thread_pool()#
Get the default thread pool.
Notice, it is not possible to change the default thread pool. KvikIO will always use the same thread pool however it is possible to change number of threads in the pool (see
kvikio::default::set_thread_pool_nthreads()).- Returns:
The default thread pool instance.
-
static unsigned int thread_pool_nthreads()#
Get the number of threads in the default thread pool.
Set the default value using
kvikio::default::set_thread_pool_nthreads()or by setting theKVIKIO_NTHREADSenvironment variable. If not set, the default value is 1.- Returns:
The number of threads.
-
static void set_thread_pool_nthreads(unsigned int nthreads)#
Set the number of threads in the default thread pool. Waits for all currently running tasks to be completed, then destroys all threads in the pool and creates a new thread pool with the new number of threads. Any tasks that were waiting in the queue before the pool was reset will then be executed by the new threads.
- Parameters:
nthreads – The number of threads to use.
-
static unsigned int num_threads()#
Alias of
thread_pool_nthreads- Returns:
The number of threads
-
static void set_num_threads(unsigned int nthreads)#
Alias of
set_thread_pool_nthreads- Parameters:
nthreads – The number of threads to use
-
static std::size_t task_size()#
Get the default task size used for parallel IO operations.
Set the default value using
kvikio::default::set_task_size()or by setting theKVIKIO_TASK_SIZEenvironment variable. If not set, the default value is 4 MiB.- Returns:
The default task size in bytes.
-
static void set_task_size(std::size_t nbytes)#
Set the default task size used for parallel IO operations.
When opportunistic Direct I/O read is enabled (
KVIKIO_AUTO_DIRECT_IO_READ=1), this value should be a multiple of page size (typically 4 KiB) so that parallel tasks start at page-aligned file offsets, avoiding buffered I/O fallback.- Parameters:
nbytes – The default task size in bytes.
-
static std::size_t gds_threshold()#
Get the default GDS threshold, which is the minimum size to use GDS (in bytes).
In order to improve performance of small IO,
.pread()and.pwrite()implement a shortcut that circumvent the threadpool and use the POSIX backend directly.Set the default value using
kvikio::default::set_gds_threshold()or by setting theKVIKIO_GDS_THRESHOLDenvironment variable. If not set, the default value is 1 MiB.- Returns:
The default GDS threshold size in bytes.
-
static void set_gds_threshold(std::size_t nbytes)#
Set the default GDS threshold, which is the minimum size to use GDS (in bytes).
- Parameters:
nbytes – The default GDS threshold size in bytes.
-
static std::size_t bounce_buffer_size()#
Get the size of the bounce buffer used to stage data in host memory.
Set the value using
kvikio::default::set_bounce_buffer_size()or by setting theKVIKIO_BOUNCE_BUFFER_SIZEenvironment variable. If not set, the value is 16 MiB.- Returns:
The bounce buffer size in bytes.
-
static void set_bounce_buffer_size(std::size_t nbytes)#
Set the size of the bounce buffer used to stage data in host memory.
- Parameters:
nbytes – The bounce buffer size in bytes.
-
static std::size_t http_max_attempts()#
Get the maximum number of attempts per remote IO read.
Set the value using
kvikio::default::set_http_max_attempts()or by setting theKVIKIO_HTTP_MAX_ATTEMPTSenvironment variable. If not set, the value is 3.- Returns:
The maximum number of remote IO reads to attempt before raising an error.
-
static void set_http_max_attempts(std::size_t attempts)#
Set the maximum number of attempts per remote IO read.
- Parameters:
attempts – The maximum number of attempts to try before raising an error.
-
static long http_timeout()#
The maximum time, in seconds, the transfer is allowed to complete.
Set the value using
kvikio::default::set_http_timeout()or by setting theKVIKIO_HTTP_TIMEOUTenvironment variable. If not set, the value is 60.- Returns:
The maximum time the transfer is allowed to complete.
-
static void set_http_timeout(long timeout_seconds)#
Reset the http timeout.
- Parameters:
timeout_seconds – The maximum time the transfer is allowed to complete.
-
static std::vector<int> const &http_status_codes()#
The list of HTTP status codes to retry.
Set the value using
kvikio::default::set_http_status_codes()or by setting theKVIKIO_HTTP_STATUS_CODESenvironment variable. If not set, the default value is429
500
502
503
504
- Returns:
The list of HTTP status codes to retry.
-
static void set_http_status_codes(std::vector<int> status_codes)#
Set the list of HTTP status codes to retry.
- Parameters:
status_codes – The HTTP status codes to retry.
-
static bool auto_direct_io_read()#
Check if Direct I/O is enabled for POSIX reads.
Returns true if KvikIO should attempt to use Direct I/O (O_DIRECT) for POSIX read operations.
- Returns:
Boolean answer
-
static void set_auto_direct_io_read(bool flag)#
Enable or disable Direct I/O for POSIX reads.
Controls whether KvikIO should attempt to use Direct I/O (O_DIRECT) for POSIX read operations.
- Parameters:
flag – true to enable opportunistic Direct I/O reads, false to disable
-
static bool auto_direct_io_read_overread()#
Check if Direct I/O over-read alignment is enabled for device reads.
When enabled, device memory reads use pure Direct I/O by aligning offsets down and sizes up to page boundaries, at the cost of reading extra bytes from disk. When disabled (default), unaligned portions fall back to buffered I/O. Only affects the device memory read path (disk to bounce buffer to GPU). Host memory reads are unaffected.
Requires
auto_direct_io_read()to be enabled to have any effect.- Returns:
Boolean answer
-
static void set_auto_direct_io_read_overread(bool flag)#
Enable or disable Direct I/O over-read alignment for device reads.
- Parameters:
flag – true to enable over-read alignment, false to use opportunistic DIO with buffered I/O fallback for unaligned portions (default)
-
static bool auto_direct_io_write()#
Check if Direct I/O is enabled for POSIX writes.
Returns true if KvikIO should attempt to use Direct I/O (O_DIRECT) for POSIX write operations.
- Returns:
Boolean answer
-
static void set_auto_direct_io_write(bool flag)#
Enable or disable Direct I/O for POSIX writes.
Controls whether KvikIO should attempt to use Direct I/O (O_DIRECT) for POSIX write operations.
- Parameters:
flag – true to enable opportunistic Direct I/O writes, false to disable
-
static bool thread_pool_per_block_device()#
Check if per-block-device thread pools are enabled.
The initial value is determined by the environment variable
KVIKIO_THREAD_POOL_PER_BLOCK_DEVICE. If not set, defaults tofalse.- Returns:
Boolean answer
-
static void set_thread_pool_per_block_device(bool flag)#
Enable or disable per-block-device thread pools.
Each pool is initialized with the number of threads specified by
thread_pool_nthreads(). Changes take effect only for files opened after this call. Files already opened retain their existing thread pool assignments.- Parameters:
flag –
trueto enable per-block-device thread pools,falseto use the single global thread pool for all I/O operations.
-
static RemoteIOBackend remote_io_backend()#
The remote I/O backend selected.
Controlled by the environment variable
KVIKIO_REMOTE_IO_BACKEND, parsed case-insensitively. The only accepted values are the canonical namesEASY_THREADPOOLandMULTI_POLL. If unset, defaults toEASY_THREADPOOL.- Returns:
The remote I/O backend.
-
static void set_remote_io_backend(RemoteIOBackend backend)#
Select the remote I/O backend at runtime, overriding
KVIKIO_REMOTE_IO_BACKEND.- Parameters:
backend – The remote I/O backend.
-
static unsigned int remote_io_num_reactors()#
Number of reactor threads used by the
MULTI_POLLremote I/O backend.Controlled by
KVIKIO_REMOTE_IO_NUM_REACTORS. Must be a positive integer. Defaults to 1. Ignored when the active backend is notMULTI_POLL.- Returns:
The configured reactor count.
-
static RemoteReactorDispatch remote_io_reactor_dispatch()#
How sub-ranges of one
pread()are distributed across reactor threads under theMULTI_POLLremote I/O backend.Controlled by
KVIKIO_REMOTE_IO_REACTOR_DISPATCH, parsed case-insensitively.PER_CHUNK:RemoteReactorDispatch::PER_CHUNK(default).PER_PREAD:RemoteReactorDispatch::PER_PREAD. When a single reactor is used, both modes are equivalent.
- Returns:
The reactor dispatch policy.
-
static std::size_t remote_io_max_concurrent_requests()#
Maximum number of concurrent in-flight requests across all reactor threads under the
MULTI_POLLremote I/O backend.One
pread()of a large file is split into many sub-range requests (one libcurl easy handle each). This bounds how many of them are attached to the reactors’ multi handles at once, summed across all reactor threads.The budget is divided into an equal private share per reactor, so the effective total is approximate: it rounds down when the value is not a multiple of the reactor count, and up when it is smaller than the reactor count (each reactor is floored to at least 1).
Controlled by
KVIKIO_REMOTE_IO_MAX_CONCURRENT_REQUESTS. Must be a non-negative integer. 0 means unlimited. Defaults to 256. Ignored when the active backend is notMULTI_POLL(EASY_THREADPOOLis already bounded byKVIKIO_NTHREADS).- Returns:
The configured concurrent-request ceiling, or 0 for unlimited.
-
static CompatMode compat_mode()#
-
struct CUfileException : public std::runtime_error#
-
class GenericSystemError : public std::system_error#
-
class FileHandle#
- #include <file_handle.hpp>
Handle of an open file registered with cufile.
In order to utilize cufile and GDS, a file must be registered with cufile.
Public Functions
- FileHandle(
- std::string const &file_path,
- std::string const &flags = "r",
- mode_t mode = m644,
- CompatMode compat_mode = defaults::compat_mode()
Construct a file handle from a file path.
FileHandle opens the file twice and maintains two file descriptors. One file is opened with the specified
flagsand the other file is opened with theflagsplus theO_DIRECTflag.- Parameters:
file_path – File path to the file
flags – Open flags (see also
fopen(3)): “r” -> “open for reading (default)” “w” -> “open for writing, truncating the file first” “a” -> “open for writing, appending to the end of file if it exists” “+” -> “open for updating (reading and writing)”mode – Access modes (see
open(2)).compat_mode – Set KvikIO’s compatibility mode for this file.
-
FileHandle(FileHandle const&) = delete#
FileHandle support move semantic but isn’t copyable.
-
bool closed() const noexcept#
Whether the file is closed according to its initialization status.
- Returns:
Boolean answer.
-
void close() noexcept#
Deregister the file and close the two files.
-
CUfileHandle_t handle()#
Get the underlying cuFile file handle.
The file handle must be open and not in compatibility mode i.e. both
closed()andis_compat_mode_preferred()must be false.- Returns:
cuFile’s file handle
-
int fd(bool o_direct = false) const noexcept#
Get one of the file descriptors.
Notice, FileHandle maintains two file descriptors - one opened with the
O_DIRECTflag and one without.- Parameters:
o_direct – Whether to get the file descriptor opened with the
O_DIRECTflag.- Returns:
File descriptor
-
int fd_open_flags(bool o_direct = false) const#
Get the flags of one of the file descriptors (see open(2))
Notice, FileHandle maintains two file descriptors - one opened with the
O_DIRECTflag and one without.- Parameters:
o_direct – Whether to get the flags of the file descriptor opened with the
O_DIRECTflag.- Returns:
File descriptor
-
std::size_t nbytes() const#
Get the file size.
The value are cached.
- Returns:
The number of bytes
- std::size_t read(
- void *devPtr_base,
- std::size_t size,
- std::size_t file_offset,
- std::size_t devPtr_offset,
- bool sync_default_stream = true
Reads specified bytes from the file into the device memory.
This API reads the data from the GPU memory to the file at a specified offset and size bytes by using GDS functionality. The API works correctly for unaligned offset and data sizes, although the performance is not on-par with aligned read. This is a synchronous call and will block until the IO is complete.
Note
For the
devPtr_offset, if data will be read starting exactly from thedevPtr_basethat is registered withbuffer_register,devPtr_offsetshould be set to 0. To read starting from an offset in the registered buffer range, the relative offset should be specified in thedevPtr_offset, and thedevPtr_basemust remain set to the base address that was used in thebuffer_registercall.- Parameters:
devPtr_base – Base address of buffer in device memory. For registered buffers,
devPtr_basemust remain set to the base address used in thebuffer_registercall.size – Size in bytes to read.
file_offset – Offset in the file to read from.
devPtr_offset – Offset relative to the
devPtr_basepointer to read into. This parameter should be used only with registered buffers.sync_default_stream – Synchronize the CUDA default (null) stream prior to calling cuFile. Contrary to most of the non-async CUDA API, cuFile does not have the semantic of being ordered with respect to other non-cuFile work in the default stream. By enabling
sync_default_stream, KvikIO will synchronize the default stream and order the operation with respect to other work in the null stream. When in KvikIO’s compatibility mode or when accessing host memory, the operation is always default stream ordered like the rest of the non-async CUDA API. In this case, the value ofsync_default_streamis ignored.
- Returns:
Size of bytes that were successfully read.
- std::size_t write(
- void const *devPtr_base,
- std::size_t size,
- std::size_t file_offset,
- std::size_t devPtr_offset,
- bool sync_default_stream = true
Writes specified bytes from the device memory into the file.
This API writes the data from the GPU memory to the file at a specified offset and size bytes by using GDS functionality. The API works correctly for unaligned offset and data sizes, although the performance is not on-par with aligned writes. This is a synchronous call and will block until the IO is complete.
Note
GDS functionality modified the standard file system metadata in SysMem. However, GDS functionality does not take any special responsibility for writing that metadata back to permanent storage. The data is not guaranteed to be present after a system crash unless the application uses an explicit
fsync(2)call. If the file is opened with anO_SYNCflag, the metadata will be written to the disk before the call is complete. Refer to the note in read for more information aboutdevPtr_offset.- Parameters:
devPtr_base – Base address of buffer in device memory. For registered buffers,
devPtr_basemust remain set to the base address used in thebuffer_registercall.size – Size in bytes to write.
file_offset – Offset in the file to write from.
devPtr_offset – Offset relative to the
devPtr_basepointer to write from. This parameter should be used only with registered buffers.sync_default_stream – Synchronize the CUDA default (null) stream prior to calling cuFile. Contrary to most of the non-async CUDA API, cuFile does not have the semantic of being ordered with respect to other non-cuFile work in the default stream. By enabling
sync_default_stream, KvikIO will synchronize the default stream and order the operation with respect to other work in the null stream. When in KvikIO’s compatibility mode or when accessing host memory, the operation is always default stream ordered like the rest of the non-async CUDA API. In this case, the value ofsync_default_streamis ignored.
- Returns:
Size of bytes that were successfully written.
- std::future<std::size_t> pread(
- void *buf,
- std::size_t size,
- std::size_t file_offset = 0,
- std::size_t task_size = defaults::task_size(),
- std::size_t gds_threshold = defaults::gds_threshold(),
- bool sync_default_stream = true,
- ThreadPool *thread_pool = &defaults::thread_pool()
Reads specified bytes from the file into the device or host memory in parallel.
This API is a parallel async version of
.read()that partition the operation into tasks of sizetask_sizefor execution in the default thread pool.In order to improve performance of small buffers, when
size < gds_thresholda shortcut that circumvent the threadpool and use the POSIX backend directly is used.Note
For cuFile reads, the base address of the allocation
bufis part of is used. This means that when registering buffers, use the base address of the allocation. This is whatmemory_registerandmemory_deregisterdo automatically.Note
The returned
std::futureobject must not outlive either the FileHandle or the thread pool. Callingwait()orget()on the future after the FileHandle or thread pool has been destroyed results in undefined behavior.- Parameters:
buf – Address to device or host memory.
size – Size in bytes to read.
file_offset – Offset in the file to read from.
task_size – Size of each task in bytes.
gds_threshold – Minimum buffer size to use GDS and the thread pool.
sync_default_stream – Synchronize the CUDA default (null) stream prior to calling cuFile. Contrary to most of the non-async CUDA API, cuFile does not have the semantic of being ordered with respect to other non-cuFile work in the default stream. By enabling
sync_default_stream, KvikIO will synchronize the default stream and order the operation with respect to other work in the null stream. When in KvikIO’s compatibility mode or when accessing host memory, the operation is always default stream ordered like the rest of the non-async CUDA API. In this case, the value ofsync_default_streamis ignored.thread_pool – Thread pool to use for parallel execution. Defaults to the global default thread pool. The caller is responsible for ensuring that the thread pool remains valid until the returned future is consumed (i.e., until
get()orwait()is called on it).
- Returns:
Future that on completion returns the size of bytes that were successfully read.
- std::future<std::size_t> pwrite(
- void const *buf,
- std::size_t size,
- std::size_t file_offset = 0,
- std::size_t task_size = defaults::task_size(),
- std::size_t gds_threshold = defaults::gds_threshold(),
- bool sync_default_stream = true,
- ThreadPool *thread_pool = &defaults::thread_pool()
Writes specified bytes from device or host memory into the file in parallel.
This API is a parallel async version of
.write()that partition the operation into tasks of sizetask_sizefor execution in the default thread pool.In order to improve performance of small buffers, when
size < gds_thresholda shortcut that circumvent the threadpool and use the POSIX backend directly is used.Note
For cuFile reads, the base address of the allocation
bufis part of is used. This means that when registering buffers, use the base address of the allocation. This is whatmemory_registerandmemory_deregisterdo automatically.Note
The returned
std::futureobject must not outlive either the FileHandle or the thread pool. Callingwait()orget()on the future after the FileHandle or thread pool has been destroyed results in undefined behavior.- Parameters:
buf – Address to device or host memory.
size – Size in bytes to write.
file_offset – Offset in the file to write from.
task_size – Size of each task in bytes.
gds_threshold – Minimum buffer size to use GDS and the thread pool.
sync_default_stream – Synchronize the CUDA default (null) stream prior to calling cuFile. Contrary to most of the non-async CUDA API, cuFile does not have the semantic of being ordered with respect to other non-cuFile work in the default stream. By enabling
sync_default_stream, KvikIO will synchronize the default stream and order the operation with respect to other work in the null stream. When in KvikIO’s compatibility mode or when accessing host memory, the operation is always default stream ordered like the rest of the non-async CUDA API. In this case, the value ofsync_default_streamis ignored.thread_pool – Thread pool to use for parallel execution. Defaults to the global default thread pool. The caller is responsible for ensuring that the thread pool remains valid until the returned future is consumed (i.e., until
get()orwait()is called on it).
- Returns:
Future that on completion returns the size of bytes that were successfully written.
- void read_async(
- void *devPtr_base,
- std::size_t *size_p,
- off_t *file_offset_p,
- off_t *devPtr_offset_p,
- ssize_t *bytes_read_p,
- CUstream stream
Reads specified bytes from the file into the device memory asynchronously.
This is an asynchronous version of
.read(), which will be executed in sequence for the specified stream.The arguments have the same meaning as in
.read()but some of them are deferred. That is, the values pointed to bysize_p,file_offset_panddevPtr_offset_pwill not be evaluated until execution time. Notice, this behavior can be changed using cuFile’s cuFileStreamRegister API.- Parameters:
devPtr_base – Base address of buffer in device memory. For registered buffers,
devPtr_basemust remain set to the base address used in thebuffer_registercall.size_p – Pointer to size in bytes to read. If the exact size is not known at the time of I/O submission, then you must set it to the maximum possible I/O size for that stream I/O. Later the actual size can be set prior to the stream I/O execution.
file_offset_p – Pointer to offset in the file from which to read. Unless otherwise set using cuFileStreamRegister API, this value will not be evaluated until execution time.
devPtr_offset_p – Pointer to the offset relative to the bufPtr_base from which to write. Unless otherwise set using cuFileStreamRegister API, this value will not be evaluated until execution time.
bytes_read_p – Pointer to the bytes read from file. This pointer should be a non-NULL value and *bytes_read_p set to 0. The bytes_read_p memory should be allocated with cuMemHostAlloc/malloc/mmap or registered with cuMemHostRegister. After successful execution of the operation in the stream, the value *bytes_read_p will contain either:
The number of bytes successfully read.
-1 on IO errors.
All other errors return a negative integer value of the CUfileOpError enum value.
stream – CUDA stream in which to enqueue the operation. If NULL, make this operation synchronous.
- StreamFuture read_async(
- void *devPtr_base,
- std::size_t size,
- off_t file_offset = 0,
- off_t devPtr_offset = 0,
- CUstream stream = nullptr
Reads specified bytes from the file into the device memory asynchronously.
This is an asynchronous version of
.read(), which will be executed in sequence for the specified stream.The arguments have the same meaning as in
.read()but returns aStreamFutureobject that the caller must keep alive until all data has been read from disk. One way to do this, is by callingStreamFuture.check_bytes_done(), which will synchronize the associated stream and return the number of bytes read.- Parameters:
devPtr_base – Base address of buffer in device memory. For registered buffers,
devPtr_basemust remain set to the base address used in thebuffer_registercall.size – Size in bytes to read.
file_offset – Offset in the file to read from.
devPtr_offset – Offset relative to the
devPtr_basepointer to read into. This parameter should be used only with registered buffers.stream – CUDA stream in which to enqueue the operation. If NULL, make this operation synchronous.
- Returns:
A future object that must be kept alive until all data has been read to disk e.g. by synchronizing
stream.
- void write_async(
- void *devPtr_base,
- std::size_t *size_p,
- off_t *file_offset_p,
- off_t *devPtr_offset_p,
- ssize_t *bytes_written_p,
- CUstream stream
Writes specified bytes from the device memory into the file asynchronously.
This is an asynchronous version of
.write(), which will be executed in sequence for the specified stream.The arguments have the same meaning as in
.write()but some of them are deferred. That is, the values pointed to bysize_p,file_offset_panddevPtr_offset_pwill not be evaluated until execution time. Notice, this behavior can be changed using cuFile’s cuFileStreamRegister API.- Parameters:
devPtr_base – Base address of buffer in device memory. For registered buffers,
devPtr_basemust remain set to the base address used in thebuffer_registercall.size_p – Pointer to size in bytes to read. If the exact size is not known at the time of I/O submission, then you must set it to the maximum possible I/O size for that stream I/O. Later the actual size can be set prior to the stream I/O execution.
file_offset_p – Pointer to offset in the file from which to read. Unless otherwise set using cuFileStreamRegister API, this value will not be evaluated until execution time.
devPtr_offset_p – Pointer to the offset relative to the bufPtr_base from which to read. Unless otherwise set using cuFileStreamRegister API, this value will not be evaluated until execution time.
bytes_written_p – Pointer to the bytes read from file. This pointer should be a non-NULL value and *bytes_written_p set to 0. The bytes_written_p memory should be allocated with cuMemHostAlloc/malloc/mmap or registered with cuMemHostRegister. After successful execution of the operation in the stream, the value *bytes_written_p will contain either:
The number of bytes successfully read.
-1 on IO errors.
All other errors return a negative integer value of the CUfileOpError enum value.
stream – CUDA stream in which to enqueue the operation. If NULL, make this operation synchronous.
- StreamFuture write_async(
- void *devPtr_base,
- std::size_t size,
- off_t file_offset = 0,
- off_t devPtr_offset = 0,
- CUstream stream = nullptr
Writes specified bytes from the device memory into the file asynchronously.
This is an asynchronous version of
.write(), which will be executed in sequence for the specified stream.The arguments have the same meaning as in
.write()but returns aStreamFutureobject that the caller must keep alive until all data has been written to disk. One way to do this, is by callingStreamFuture.check_bytes_done(), which will synchronize the associated stream and return the number of bytes written.- Parameters:
devPtr_base – Base address of buffer in device memory. For registered buffers,
devPtr_basemust remain set to the base address used in thebuffer_registercall.size – Size in bytes to write.
file_offset – Offset in the file to write from.
devPtr_offset – Offset relative to the
devPtr_basepointer to write from. This parameter should be used only with registered buffers.stream – CUDA stream in which to enqueue the operation. If NULL, make this operation synchronous.
- Returns:
A future object that must be kept alive until all data has been written to disk e.g. by synchronizing
stream.
-
const CompatModeManager &get_compat_mode_manager() const noexcept#
Get the associated compatibility mode manager, which can be used to query the original requested compatibility mode or the expected compatibility modes for synchronous and asynchronous I/O.
- Returns:
The associated compatibility mode manager.
-
bool is_direct_io_supported() const noexcept#
Whether Direct I/O is supported on this file handle. This is determined by two factors:
Direct I/O support from the operating system and the file system
KvikIO global setting
auto_direct_io_readandauto_direct_io_write. If both values are false, Direct I/O will not be supported on this file handle.
- Returns:
Boolean answer.
-
class FileWrapper#
- #include <file_utils.hpp>
Class that provides RAII for file handling.
Public Functions
- FileWrapper(
- std::string const &file_path,
- std::string const &flags,
- bool o_direct,
- mode_t mode
Open file.
- Parameters:
file_path – File path.
flags – Open flags given as a string.
o_direct – Append O_DIRECT to
flags.mode – Access modes.
-
FileWrapper() noexcept = default#
Construct an empty file wrapper object without opening a file.
- void open(
- std::string const &file_path,
- std::string const &flags,
- bool o_direct,
- mode_t mode
Open file using
open(2)- Parameters:
file_path – File path.
flags – Open flags given as a string.
o_direct – Append O_DIRECT to
flags.mode – Access modes.
-
bool opened() const noexcept#
Check if the file has been opened.
- Returns:
A boolean answer indicating if the file has been opened.
-
void close() noexcept#
Close the file if it is opened; do nothing otherwise.
-
int fd() const noexcept#
Return the file descriptor.
- Returns:
File descriptor.
-
class CUFileHandleWrapper#
- #include <file_utils.hpp>
Class that provides RAII for the cuFile handle.
Public Functions
-
std::optional<CUfileError_t> register_handle(int fd) noexcept#
Register the file handle given the file descriptor.
- Parameters:
fd – File descriptor.
- Returns:
Return the cuFile error code from handle register. If the handle has already been registered by calling
register_handle(), returnstd::nullopt.
-
bool registered() const noexcept#
Check if the handle has been registered.
- Returns:
A boolean answer indicating if the handle has been registered.
-
CUfileHandle_t handle() const noexcept#
Return the cuFile handle.
- Returns:
The cuFile handle.
-
void unregister_handle() noexcept#
Unregister the handle if it has been registered; do nothing otherwise.
-
std::optional<CUfileError_t> register_handle(int fd) noexcept#
-
struct BlockDeviceInfo#
- #include <file_utils.hpp>
Information about a block device.
-
class WebHdfsEndpoint : public kvikio::RemoteEndpoint#
- #include <hdfs.hpp>
A remote endpoint for Apache Hadoop WebHDFS.
This endpoint is for accessing HDFS files via the WebHDFS REST API over HTTP/HTTPS. If KvikIO is run within Docker, pass
--network hostto thedocker runcommand to ensure proper name node connectivity.Public Functions
- explicit WebHdfsEndpoint(
- std::string url,
- std::optional<std::string> username = std::nullopt
Create an WebHDFS endpoint from a url.
Note
The optional username for authentication is determined in the following descending priority order:
Function parameter
usernameQuery string in URL (?user.name=xxx)
Environment variable
KVIKIO_WEBHDFS_USERNAME
- Parameters:
url – The WebHDFS HTTP/HTTPS url to the remote file.
username – Optional user name.
- explicit WebHdfsEndpoint(
- std::string host,
- std::string port,
- std::string remote_file_path,
- std::optional<std::string> username = std::nullopt
Create an WebHDFS endpoint from the host, port, file path and optionally username.
Note
The optional username for authentication is determined in the following descending priority order:
Function parameter
usernameEnvironment variable
KVIKIO_WEBHDFS_USERNAME
- Parameters:
host – Host
port – Port
remote_file_path – Remote file path
username – Optional user name.
-
virtual void setopt(CurlHandle &curl) override#
Set needed connection options on a curl handle.
Subsequently, a call to
curl.perform()should connect to the endpoint.- Parameters:
curl – The curl handle.
-
virtual std::string str() const override#
Get a description of this remote point instance.
- Returns:
A string description.
-
virtual std::size_t get_file_size() override#
Get the size of the remote file.
- Returns:
The file size
- virtual void setup_range_request(
- CurlHandle &curl,
- std::size_t file_offset,
- std::size_t size
Set up the range request in order to read part of a file given the file offset and read size.
Public Static Functions
-
static bool is_url_valid(std::string const &url) noexcept#
Whether the given URL is valid for the WebHDFS endpoints.
- Parameters:
url – A URL.
- Returns:
Boolean answer.
-
class MmapHandle#
- #include <mmap.hpp>
Handle of a memory-mapped file.
This utility class facilitates the use of file-backed memory by providing a performant method
pread()to read a range of data into user-provided memory residing on the host or device.File-backed memory can be considered when a large number of nonadjacent file ranges (specified by the
offsetandsizepair) are to be frequently accessed. It can potentially reduce memory usage due to demand paging (compared to reading the entire file withread(2)), and may improve I/O performance compared to frequent calls toread(2).Public Functions
-
MmapHandle() noexcept = default#
Construct an empty memory-mapped file.
- MmapHandle(
- std::string const &file_path,
- std::string const &flags = "r",
- std::optional<std::size_t> initial_map_size = std::nullopt,
- std::size_t initial_map_offset = 0,
- mode_t mode = FileHandle::m644,
- std::optional<int> map_flags = std::nullopt
Construct a new memory-mapped file.
- Parameters:
file_path – File path
flags – Open flags (see also
fopen(3)):”r”: “open for reading (default)”
”w”: “open for writing, truncating the file first”
”a”: “open for writing, appending to the end of file if it exists”
”+”: “open for updating (reading and writing)”
initial_map_size – Size in bytes of the mapped region. Must be greater than 0. If not specified, map the region starting from
initial_map_offsetto the end of fileinitial_map_offset – File offset of the mapped region
mode – Access mode
map_flags – Flags to be passed to the system call
mmap. Seemmap(2)for details
- Throws:
std::out_of_range – if
initial_map_offset(left bound of the mapped region) is equal to or greater than the file sizestd::out_of_range – if the sum of
initial_map_offsetandinitial_map_size(right bound of the mapped region) is greater than the file sizestd::invalid_argument – if
initial_map_sizeis given but is 0
-
std::size_t initial_map_size() const noexcept#
Size in bytes of the mapped region when the mapping handle was constructed.
- Returns:
Initial size of the mapped region
-
std::size_t initial_map_offset() const noexcept#
File offset of the mapped region when the mapping handle was constructed.
- Returns:
Initial file offset of the mapped region
-
std::size_t file_size() const#
Get the file size if the file is open. Returns 0 if the file is closed.
The behavior of this method is consistent with
FileHandle::nbytes.- Returns:
The file size in bytes
-
std::size_t nbytes() const#
Alias of
file_size- Returns:
The file size in bytes
-
bool closed() const noexcept#
Whether the mapping handle is closed.
- Returns:
Boolean answer
-
void close() noexcept#
Close the mapping handle if it is open; do nothing otherwise.
- std::size_t read(
- void *buf,
- std::optional<std::size_t> size = std::nullopt,
- std::size_t offset = 0
Sequential read
sizebytes from the file (with the offsetoffset) to the destination bufferbuf- Parameters:
buf – Address of the host or device memory (destination buffer)
size – Size in bytes to read. Can be 0 in which case nothing will be read. If not specified, read starts from
offsetto the end of fileoffset – File offset
- Throws:
std::out_of_range – if the read region specified by
offsetandsizeis outside the initial region specified when the mapping handle was constructedstd::runtime_error – if the mapping handle is closed
- Returns:
Number of bytes that have been read
- std::future<std::size_t> pread(
- void *buf,
- std::optional<std::size_t> size = std::nullopt,
- std::size_t offset = 0,
- std::size_t task_size = defaults::task_size(),
- ThreadPool *thread_pool = &defaults::thread_pool()
Parallel read
sizebytes from the file (with the offsetoffset) to the destination bufferbufNote
The returned
std::futureobject must not outlive either the MmapHandle or the thread pool. Callingwait()orget()on the future after the MmapHandle or thread pool has been destroyed results in undefined behavior.- Parameters:
buf – Address of the host or device memory (destination buffer)
size – Size in bytes to read. Can be 0 in which case nothing will be read. If not specified, read starts from
offsetto the end of fileoffset – File offset
task_size – Size of each task in bytes
thread_pool – Thread pool to use for parallel execution. Defaults to the global default thread pool. The caller is responsible for ensuring that the thread pool remains valid until the returned future is consumed (i.e., until
get()orwait()is called on it).
- Throws:
std::out_of_range – if the read region specified by
offsetandsizeis outside the initial region specified when the mapping handle was constructedstd::runtime_error – if the mapping handle is closed
- Returns:
Future that on completion returns the size of bytes that were successfully read.
-
MmapHandle() noexcept = default#
-
struct ClockAnchor#
- #include <observation.hpp>
A reading of
Clockand of the wall clock, taken together.Clockcannot be compared with anything outside this process, so an anchor is what relates an observation to a log line, to another process, or to a profiler trace.Public Functions
- inline std::chrono::system_clock::time_point to_wall_clock(
- TimePoint time
Convert a point on
Clockto wall-clock time.Warning
The wall clock can be stepped or slewed by NTP or an operator, so an old anchor may no longer be valid. Take an anchor at each end of a long run and compare them to detect an in-flight adjustment to the system time.
- Parameters:
time – The point to convert.
- Returns:
The corresponding wall-clock time.
Public Members
-
std::chrono::system_clock::time_point wall = {}#
The reading of the wall clock, taken at the same moment.
Public Static Functions
-
static ClockAnchor now() noexcept#
Read both clocks, one immediately after the other.
Warning
The readings are tens of nanoseconds apart, since the two clocks cannot be read at once, so the anchor’s offset is out by that much. Well below what a wall clock is worth anyway, NTP agreeing between machines to microseconds at best.
- Returns:
The pair of readings.
-
struct Observation#
- #include <observation.hpp>
One I/O operation, as observed by KvikIO.
[start, end)covers the operation from issue to completion.Public Functions
-
inline Duration duration() const noexcept#
How long the operation took.
- Returns:
end - start, or zero if the span is degenerate.
-
inline double bytes_per_sec() const noexcept#
Throughput of this single operation.
Warning
Averaging this across operations does not give the throughput of the program. For that, divide total bytes by a span of elapsed time.
- Returns:
Bytes per second, or zero if the operation had no measurable duration.
Public Members
-
std::size_t offset = {}#
Byte offset into the file or remote object.
-
std::size_t size = {}#
Number of bytes requested.
-
std::size_t bytes_transferred = {}#
Number of bytes actually transferred. Differs from
sizeon a short read, and is zero for an operation that failed.
-
std::uint64_t id = {}#
Identifies this operation, uniquely within the process.
-
std::optional<std::uint64_t> parent_id = {}#
For a physical observation, the
idof the logical operation it belongs to. Empty on a logical observation, and on a physical one whose call started with no monitor registered for logical observations. Nothing else leaves it empty.
-
char const *http_method = {nullptr}#
HTTP method, e.g.
"GET". Null for local I/O.
-
std::string_view source = {}#
The file path or URL the operation went to. Owned by the handle, and valid only for the duration of the callback. Copy what is needed later.
-
ObservationKind kind = {ObservationKind::LOGICAL}#
What layer this describes.
-
TransferDirection direction = {TransferDirection::READ}#
The direction of the operation.
-
MemoryKind memory_kind = {MemoryKind::HOST}#
The kind of memory the caller’s buffer lives in.
-
bool ok = {true}#
False if the operation failed.
-
inline Duration duration() const noexcept#
-
class Monitor#
- #include <observation.hpp>
Watches operations, from the moment they start until they finish.
Derive from this and register it to be told what KvikIO is doing. Two notifications per operation:
on_start()when it begins, carrying the record as it stands at submission, andon_finish()when it ends, carrying the finished record.Which operations it is told about is chosen at registration. A
LOGICALmonitor is told about user-facing calls: oneFileHandle::pread()is one operation however many reads KvikIO issued underneath. APHYSICALmonitor is told about the individual transfers instead, each linked to its call byObservation::parent_id.// Reports how many KvikIO operations are in flight at any moment. class QueueDepth : public kvikio::Monitor { public: [[nodiscard]] int depth() const noexcept { return _in_flight.load(); } private: void on_start(kvikio::Observation const&) noexcept override { ++_in_flight; } void on_finish(kvikio::Observation const&) noexcept override { --_in_flight; } std::atomic<int> _in_flight{0}; }; QueueDepth gauge; auto const id = kvikio::register_monitor(&gauge); ... kvikio::unregister_monitor(id); // Waits, so `gauge` may now be destroyed.Every operation that reports a start reports exactly one finish, on whichever thread does the work.
Note
Not everything is reported:
The cuFile asynchronous API (
FileHandle::read_async(),FileHandle::write_async()) on a system with working GDS reports nothing. In compatibility mode those calls fall back toread()/write()and are reported, so the same program is seen differently depending on whether GDS is available.The batch API (
BatchHandle) reports nothing.RemoteHandle::pread()into device memory finishes when the last pinned-to-device copy is issued rather than completed, so its span is slightly short. It is never too long.
Warning
A monitor runs inline with the I/O, on the thread performing it, on both the submission and the completion path. Keep it light, make it thread-safe, and do not call back into KvikIO, which throws
std::runtime_error. Neither callback may throw.Subclassed by kvikio::statistics::SummaryMonitor
Public Functions
-
virtual void on_start(Observation const &observation) noexcept = 0#
An operation has started.
The observation is not finished:
endandbytes_transferredare zero, andokistrueonly because nothing has failed yet. All three are set by the timeon_finish()is called.Warning
Runs inline with the I/O, on the thread performing it. Keep it light, make it thread-safe, and do not call back into KvikIO, which throws
std::runtime_error.- Parameters:
observation – The operation, as far as it is known. The reference is valid only for the duration of this call. Copy what is needed later.
-
virtual void on_finish(Observation const &observation) noexcept = 0#
An operation has completed.
A monitor registered after
observation.startnever saw the matchingon_start(), and should ignore such an operation.Warning
Runs inline with the I/O, on the thread performing it. Keep it light, make it thread-safe, and do not call back into KvikIO, which throws
std::runtime_error.- Parameters:
observation – The completed operation. The reference is valid only for the duration of this call. Copy what is needed later.
-
class RemoteEndpoint#
- #include <remote_handle.hpp>
Abstract base class for remote endpoints.
In this context, an endpoint refers to a remote file using a specific communication protocol.
Each communication protocol, such as HTTP or S3, needs to implement this ABC and implement its own ctor that takes communication protocol specific arguments.
Subclassed by kvikio::HttpEndpoint, kvikio::S3Endpoint, kvikio::S3EndpointWithPresignedUrl, kvikio::S3PublicEndpoint, kvikio::WebHdfsEndpoint
Public Functions
-
virtual void setopt(CurlHandle &curl) = 0#
Set needed connection options on a curl handle.
Subsequently, a call to
curl.perform()should connect to the endpoint.- Parameters:
curl – The curl handle.
-
virtual std::string str() const = 0#
Get a description of this remote point instance.
- Returns:
A string description.
-
virtual std::size_t get_file_size() = 0#
Get the size of the remote file.
- Returns:
The file size
- virtual void setup_range_request(
- CurlHandle &curl,
- std::size_t file_offset,
- std::size_t size
Set up the range request in order to read part of a file given the file offset and read size.
-
RemoteEndpointType remote_endpoint_type() const noexcept#
Get the type of the remote file.
- Returns:
The type of the remote file.
-
virtual void setopt(CurlHandle &curl) = 0#
-
class HttpEndpoint : public kvikio::RemoteEndpoint#
- #include <remote_handle.hpp>
A remote endpoint for HTTP/HTTPS resources.
This endpoint is for accessing files via standard HTTP/HTTPS protocols without any specialized authentication.
Public Functions
-
HttpEndpoint(std::string url)#
Create an http endpoint from a url.
- Parameters:
url – The full http url to the remote file.
-
virtual void setopt(CurlHandle &curl) override#
Set needed connection options on a curl handle.
Subsequently, a call to
curl.perform()should connect to the endpoint.- Parameters:
curl – The curl handle.
-
virtual std::string str() const override#
Get a description of this remote point instance.
- Returns:
A string description.
-
virtual std::size_t get_file_size() override#
Get the size of the remote file.
- Returns:
The file size
- virtual void setup_range_request(
- CurlHandle &curl,
- std::size_t file_offset,
- std::size_t size
Set up the range request in order to read part of a file given the file offset and read size.
Public Static Functions
-
static bool is_url_valid(std::string const &url) noexcept#
Whether the given URL is valid for HTTP/HTTPS endpoints.
- Parameters:
url – A URL.
- Returns:
Boolean answer.
-
HttpEndpoint(std::string url)#
-
class S3Endpoint : public kvikio::RemoteEndpoint#
- #include <remote_handle.hpp>
A remote endpoint for AWS S3 storage requiring credentials.
This endpoint is for accessing private S3 objects using AWS credentials (access key, secret key, region and optional session token).
Public Functions
- S3Endpoint(
- std::string url,
- std::optional<std::string> aws_region = std::nullopt,
- std::optional<std::string> aws_access_key = std::nullopt,
- std::optional<std::string> aws_secret_access_key = std::nullopt,
- std::optional<std::string> aws_session_token = std::nullopt
Create a S3 endpoint from a url.
- Parameters:
url – The full http url to the S3 file. NB: this should be an url starting with “http://” or “https://”. If you have an S3 url of the form “s3://<bucket>/<object>”, please use
S3Endpoint::parse_s3_url()and `S3Endpoint::url_from_bucket_and_object() to convert it.aws_region – The AWS region, such as “us-east-1”, to use. If nullopt, the value of the
AWS_DEFAULT_REGIONenvironment variable is used.aws_access_key – The AWS access key to use. If nullopt, the value of the
AWS_ACCESS_KEY_IDenvironment variable is used.aws_secret_access_key – The AWS secret access key to use. If nullopt, the value of the
AWS_SECRET_ACCESS_KEYenvironment variable is used.aws_session_token – The AWS session token to use. If nullopt, the value of the
AWS_SESSION_TOKENenvironment variable is used.
- S3Endpoint(
- std::pair<std::string, std::string> bucket_and_object_names,
- std::optional<std::string> aws_region = std::nullopt,
- std::optional<std::string> aws_access_key = std::nullopt,
- std::optional<std::string> aws_secret_access_key = std::nullopt,
- std::optional<std::string> aws_endpoint_url = std::nullopt,
- std::optional<std::string> aws_session_token = std::nullopt
Create a S3 endpoint from a bucket and object name.
- Parameters:
bucket_and_object_names – The bucket and object names of the S3 bucket.
aws_region – The AWS region, such as “us-east-1”, to use. If nullopt, the value of the
AWS_DEFAULT_REGIONenvironment variable is used.aws_access_key – The AWS access key to use. If nullopt, the value of the
AWS_ACCESS_KEY_IDenvironment variable is used.aws_secret_access_key – The AWS secret access key to use. If nullopt, the value of the
AWS_SECRET_ACCESS_KEYenvironment variable is used.aws_endpoint_url – Overwrite the endpoint url (including the protocol part) by using the scheme: “<aws_endpoint_url>/<bucket_name>/<object_name>”. If nullopt, the value of the
AWS_ENDPOINT_URLenvironment variable is used. If this is also not set, the regular AWS url scheme is used: “https://<bucket_name>.s3.<region>.amazonaws.com/<object_name>”.aws_session_token – The AWS session token to use. If nullopt, the value of the
AWS_SESSION_TOKENenvironment variable is used.
-
virtual void setopt(CurlHandle &curl) override#
Set needed connection options on a curl handle.
Subsequently, a call to
curl.perform()should connect to the endpoint.- Parameters:
curl – The curl handle.
-
virtual std::string str() const override#
Get a description of this remote point instance.
- Returns:
A string description.
-
virtual std::size_t get_file_size() override#
Get the size of the remote file.
- Returns:
The file size
- virtual void setup_range_request(
- CurlHandle &curl,
- std::size_t file_offset,
- std::size_t size
Set up the range request in order to read part of a file given the file offset and read size.
Public Static Functions
- static std::string url_from_bucket_and_object(
- std::string bucket_name,
- std::string object_name,
- std::optional<std::string> aws_region,
- std::optional<std::string> aws_endpoint_url
Get url from a AWS S3 bucket and object name.
- Throws:
std::invalid_argument – if no region is specified and no default region is specified in the environment.
- Parameters:
bucket_name – The name of the S3 bucket.
object_name – The name of the S3 object.
aws_region – The AWS region, such as “us-east-1”, to use. If nullopt, the value of the
AWS_DEFAULT_REGIONenvironment variable is used.aws_endpoint_url – Overwrite the endpoint url (including the protocol part) by using the scheme: “<aws_endpoint_url>/<bucket_name>/<object_name>”. If nullopt, the value of the
AWS_ENDPOINT_URLenvironment variable is used. If this is also not set, the regular AWS url scheme is used: “https://<bucket_name>.s3.<region>.amazonaws.com/<object_name>”.
- static std::pair<std::string, std::string> parse_s3_url(
- std::string const &s3_url
Given an url like “s3://<bucket>/<object>”, return the name of the bucket and object.
- Throws:
std::invalid_argument – if url is ill-formed or is missing the bucket or object name.
- Parameters:
s3_url – S3 url.
- Returns:
Pair of strings: [bucket-name, object-name].
-
static bool is_url_valid(std::string const &url) noexcept#
Whether the given URL is valid for S3 endpoints (excluding presigned URL).
- Parameters:
url – A URL.
- Returns:
Boolean answer.
-
class S3PublicEndpoint : public kvikio::RemoteEndpoint#
- #include <remote_handle.hpp>
A remote endpoint for publicly accessible S3 objects without authentication.
This endpoint is for accessing S3 objects configured with public read permissions, requiring no authentication. Supports AWS S3 services with anonymous access enabled.
Public Functions
-
virtual void setopt(CurlHandle &curl) override#
Set needed connection options on a curl handle.
Subsequently, a call to
curl.perform()should connect to the endpoint.- Parameters:
curl – The curl handle.
-
virtual std::string str() const override#
Get a description of this remote point instance.
- Returns:
A string description.
-
virtual std::size_t get_file_size() override#
Get the size of the remote file.
- Returns:
The file size
- virtual void setup_range_request(
- CurlHandle &curl,
- std::size_t file_offset,
- std::size_t size
Set up the range request in order to read part of a file given the file offset and read size.
Public Static Functions
-
static bool is_url_valid(std::string const &url) noexcept#
Whether the given URL is valid for S3 public endpoints.
- Parameters:
url – A URL.
- Returns:
Boolean answer.
-
virtual void setopt(CurlHandle &curl) override#
-
class S3EndpointWithPresignedUrl : public kvikio::RemoteEndpoint#
- #include <remote_handle.hpp>
A remote endpoint for AWS S3 storage using presigned URLs.
This endpoint is for accessing S3 objects via presigned URLs, which provide time-limited access without requiring AWS credentials on the client side.
Public Functions
-
virtual void setopt(CurlHandle &curl) override#
Set needed connection options on a curl handle.
Subsequently, a call to
curl.perform()should connect to the endpoint.- Parameters:
curl – The curl handle.
-
virtual std::string str() const override#
Get a description of this remote point instance.
- Returns:
A string description.
-
virtual std::size_t get_file_size() override#
Get the size of the remote file.
- Returns:
The file size
- virtual void setup_range_request(
- CurlHandle &curl,
- std::size_t file_offset,
- std::size_t size
Set up the range request in order to read part of a file given the file offset and read size.
Public Static Functions
-
static bool is_url_valid(std::string const &url) noexcept#
Whether the given URL is valid for S3 endpoints with presigned URL.
- Parameters:
url – A URL.
- Returns:
Boolean answer.
-
virtual void setopt(CurlHandle &curl) override#
-
class RemoteHandle#
- #include <remote_handle.hpp>
Handle of remote file.
Public Functions
- RemoteHandle(
- std::unique_ptr<RemoteEndpoint> endpoint,
- std::size_t nbytes
Create a new remote handle from an endpoint and a file size.
- Parameters:
endpoint – Remote endpoint used for subsequent IO.
nbytes – The size of the remote file (in bytes).
-
RemoteHandle(std::unique_ptr<RemoteEndpoint> endpoint)#
Create a new remote handle from an endpoint (infers the file size).
The file size is received from the remote server using
endpoint.- Parameters:
endpoint – Remote endpoint used for subsequently IO.
-
RemoteEndpointType remote_endpoint_type() const noexcept#
Get the type of the remote file.
- Returns:
The type of the remote file.
-
std::size_t nbytes() const noexcept#
Get the file size.
Note, the file size is retrieved at construction so this method is very fast, no communication needed.
- Returns:
The number of bytes.
-
RemoteEndpoint const &endpoint() const noexcept#
Get a const reference to the underlying remote endpoint.
- Returns:
The remote endpoint.
- std::size_t read(
- void *buf,
- std::size_t size,
- std::size_t file_offset = 0
Read from remote source into buffer (host or device memory).
When reading into device memory, a bounce buffer is used to avoid many small memory copies to device. Use
kvikio::default::bounce_buffer_size_reset()to set the size of this bounce buffer (default 16 MiB).- Parameters:
buf – Pointer to host or device memory.
size – Number of bytes to read.
file_offset – File offset in bytes.
- Returns:
Number of bytes read, which is always
size.
- std::future<std::size_t> pread(
- void *buf,
- std::size_t size,
- std::size_t file_offset = 0,
- std::size_t task_size = defaults::task_size(),
- ThreadPool *thread_pool = &defaults::thread_pool()
Read from a remote source into a buffer in parallel.
The parallel async counterpart of
read(). The byte range is partitioned into sub-ranges of sizetask_sizeand dispatched to the active remote-IO backend.EASY_THREADPOOL(default): each sub-range runs on a worker of the suppliedthread_pool, blocking incurl_easy_perform().MULTI_POLL: each sub-range is handed to a process-wide reactor pool that drives many libcurl easy handles viacurl_multi_poll(). Thethread_poolargument is ignored. The first failure surfaces via the returned future. SeeKVIKIO_REMOTE_IO_NUM_REACTORSandKVIKIO_REMOTE_IO_REACTOR_DISPATCHfor tuning knobs.
Note
The returned
std::futuremust not outlive theRemoteHandle(both backends). Under EASY_THREADPOOL it must additionally not outlive the suppliedthread_pool. Callingwait()orget()on the future after either has been destroyed results in undefined behavior.- Parameters:
buf – Pointer to host or device memory.
size – Number of bytes to read.
file_offset – File offset in bytes.
task_size – Size of each sub-range in bytes.
thread_pool – Thread pool to use under EASY_THREADPOOL. Ignored under MULTI_POLL. Defaults to the global default thread pool. The caller is responsible for keeping the thread pool valid until the returned future is consumed.
- Returns:
Future that on completion returns the number of bytes read, which is always
size.
Public Static Functions
- static RemoteHandle open(
- std::string const &url,
- RemoteEndpointType remote_endpoint_type = RemoteEndpointType::AUTO,
- std::optional<std::vector<RemoteEndpointType>> allow_list = std::nullopt,
- std::optional<std::size_t> nbytes = std::nullopt
Create a remote file handle from a URL.
This function creates a RemoteHandle for reading data from various remote endpoints including HTTP/HTTPS servers, AWS S3 buckets, S3 presigned URLs, and WebHDFS. The endpoint type can be automatically detected from the URL or explicitly specified.
If not provided, defaults to all supported types in this order: RemoteEndpointType::S3, RemoteEndpointType::S3_PRESIGNED_URL, RemoteEndpointType::WEBHDFS, and RemoteEndpointType::HTTP
.
Example:
Auto-detect endpoint type from URL
auto handle = kvikio::RemoteHandle::open( "https://bucket.s3.amazonaws.com/object?X-Amz-Algorithm=AWS4-HMAC-SHA256" "&X-Amz-Credential=...&X-Amz-Signature=..." );
Open S3 file with explicit endpoint type
auto handle = kvikio::RemoteHandle::open( "https://my-bucket.s3.us-east-1.amazonaws.com/data.bin", kvikio::RemoteEndpointType::S3 );
Restrict endpoint type candidates
std::vector<kvikio::RemoteEndpointType> allow_list = { kvikio::RemoteEndpointType::HTTP, kvikio::RemoteEndpointType::S3_PRESIGNED_URL }; auto handle = kvikio::RemoteHandle::open( user_provided_url, kvikio::RemoteEndpointType::AUTO, allow_list );
Provide known file size to skip HEAD request
auto handle = kvikio::RemoteHandle::open( "https://example.com/large-file.bin", kvikio::RemoteEndpointType::HTTP, std::nullopt, 1024 * 1024 * 100 // 100 MB );
- Parameters:
url – The URL of the remote file. Supported formats include:
S3 with credentials
S3 presigned URL
WebHDFS
HTTP/HTTPS
remote_endpoint_type – The type of remote endpoint. Default is RemoteEndpointType::AUTO which automatically detects the endpoint type from the URL. Can be explicitly set to RemoteEndpointType::S3, RemoteEndpointType::S3_PRESIGNED_URL, RemoteEndpointType::WEBHDFS, or RemoteEndpointType::HTTP to force a specific endpoint type.
allow_list – Optional list of allowed endpoint types. If provided:
If remote_endpoint_type is RemoteEndpointType::AUTO, Types are tried in the exact order specified until a match is found.
In explicit mode, the specified type must be in this list, otherwise an exception is thrown.
nbytes – Optional file size in bytes. If not provided, the function sends additional request to the server to query the file size.
- Throws:
std::runtime_error – If:
If the URL is malformed or missing required components.
RemoteEndpointType::AUTO mode is used and the URL doesn’t match any supported endpoint type.
The specified endpoint type is not in the
allow_list.The URL is invalid for the specified endpoint type.
Unable to connect to the remote server or determine file size (when nbytes not provided).
- Returns:
A RemoteHandle object that can be used to read data from the remote file.
-
class StreamFuture#
- #include <stream.hpp>
Future of an asynchronous IO operation.
This class shouldn’t be used directly, instead some stream operations such as
FileHandle.read_asyncandFileHandle.write_asyncreturns an instance of this class. Use.check_bytes_done()to synchronize the associated CUDA stream and return the number of bytes read or written by the operation.The goal of this class is twofold:
Have
read_asyncandwrite_asyncreturn an object that clearly associates the function arguments with the CUDA stream used. This is useful because the current validity of the arguments depends on the stream.Support of by-value arguments. In many cases, a user will use
read_asyncandwrite_asynclike most other asynchronous CUDA functions that take by-value arguments.
To support by-value arguments, we allocate the arguments on the heap (malloc
ArgByVal) and have the by-reference arguments points intoArgByVal. This way, theread_asyncandwrite_asynccan call.get_args()to get the by-reference arguments required by cuFile’s stream API.Public Functions
-
StreamFuture(StreamFuture const&) = delete#
StreamFuture support move semantic but isn’t copyable.
- std::tuple<void*, std::size_t*, off_t*, off_t*, ssize_t*, CUstream> get_args(
Return the arguments of the future call.
- Returns:
Tuple of the arguments in the order matching
FileHandle.read()andFileHandle.write()
-
std::size_t check_bytes_done()#
Return the number of bytes read or written by the future operation.
Synchronize the associated CUDA stream.
- Returns:
Number of bytes read or written by the future operation.
-
~StreamFuture() noexcept#
Free the by-value arguments and make sure the associated CUDA stream has been synchronized.
-
class PushAndPopContext#
- #include <utils.hpp>
Push CUDA context on creation and pop it on destruction.
-
namespace detail#
Functions
-
CompatMode parse_compat_mode_str(std::string_view compat_mode_str)#
Parse a string into a CompatMode enum.
- Parameters:
compat_mode_str – Compatibility mode in string format (case-insensitive). Valid values are:
ON(alias:TRUE,YES,1)OFF(alias:FALSE,NO,0)AUTO
- Returns:
A CompatMode enum.
-
template<typename Exception, typename MsgFunc>
void kvikio_fail( - MsgFunc &&msg_func,
- int line_number,
- char const *filename
Throw an exception with a formatted error message including source location.
- Template Parameters:
Exception – The exception type to throw.
MsgFunc – A callable type that returns a std::string error message.
- Parameters:
msg_func – Callable that produces the error message string.
line_number – Source line number (typically from LINE).
filename – Source file name (typically from FILE).
- Throws:
Exception – Always thrown with a message containing the source location and user message.
-
template<typename Exception>
void cuda_driver_try( - CUresult error,
- int line_number,
- char const *filename
Check a CUDA driver API return code and throw on failure.
- Template Parameters:
Exception – The exception type to throw.
- Parameters:
error – The CUresult return code from a CUDA driver API call.
line_number – Source line number (typically from LINE).
filename – Source file name (typically from FILE).
- Throws:
Exception – Thrown if
erroris not CUDA_SUCCESS.
-
template<typename Exception>
void cufile_try( - CUfileError_t error,
- int line_number,
- char const *filename
Check a cuFile API return code and throw on failure.
If the error indicates an underlying CUDA driver error, delegates to cuda_driver_try().
- Template Parameters:
Exception – The exception type to throw.
- Parameters:
error – The CUfileError_t return code from a cuFile API call.
line_number – Source line number (typically from LINE).
filename – Source file name (typically from FILE).
- Throws:
Exception – Thrown if
errordoes not indicate CU_FILE_SUCCESS.
-
template<typename Exception>
void cufile_check_bytes_done( - ssize_t nbytes_done,
- int line_number,
- char const *filename
Check the byte count returned by a cuFile read/write and throw on failure.
A negative value encodes an error: either a cuFile operation error (if above CUFILEOP_BASE_ERR) or a standard errno value.
- Template Parameters:
Exception – The exception type to throw.
- Parameters:
nbytes_done – The byte count returned by a cuFile read/write operation.
line_number – Source line number (typically from LINE).
filename – Source file name (typically from FILE).
- Throws:
Exception – Thrown if
nbytes_doneis negative.
- inline void handle_linux_call_error(
- int line_number,
- char const *filename,
- std::string_view extra_msg
Throw a GenericSystemError with the current errno and a formatted message.
This is the shared error-reporting path for check_linux_call() overloads.
- Parameters:
line_number – Source line number (typically from LINE).
filename – Source file name (typically from FILE).
extra_msg – Optional extra context prepended to the error message.
- Throws:
kvikio::GenericSystemError – Always thrown, capturing the current errno.
- inline void check_linux_call(
- long return_value,
- int line_number,
- char const *filename,
- std::string_view extra_msg = "",
- long error_value = -1
Check the return value of a Linux system call and throw on failure.
This non-template overload handles the common case where the return value is a long type (Linux system call return type).
- Parameters:
return_value – The return value of the system call.
line_number – Source line number (typically from LINE).
filename – Source file name (typically from FILE).
extra_msg – Optional extra context for the error message (default: empty).
error_value – The sentinel value indicating failure (default: -1).
- Throws:
kvikio::GenericSystemError – Thrown if
return_valueequalserror_value.
-
template<typename T>
void check_linux_call(
)# Check the return value of a Linux system call and throw on failure.
This template overload handles non-integer return types such as
void*from mmap().- Template Parameters:
T – The return type of the system call.
- Parameters:
return_value – The return value of the system call.
line_number – Source line number (typically from LINE).
filename – Source file name (typically from FILE).
extra_msg – Extra context for the error message.
error_value – The sentinel value indicating failure (e.g. MAP_FAILED for mmap).
- Throws:
kvikio::GenericSystemError – Thrown if
return_valueequalserror_value.
- std::vector<int> parse_http_status_codes(
- std::string_view env_var_name,
- std::string const &status_codes
Parse a string of comma-separated string of HTTP status codes.
- Parameters:
env_var_name – The environment variable holding the string. Used to report errors.
status_codes – The comma-separated string of HTTP status codes. Each code should be a 3-digit integer.
- Returns:
The vector with the parsed, integer HTTP status codes.
-
void count_remote_size_probe(Duration probing) noexcept#
Record asking a remote endpoint how big a file is.
- Parameters:
probing – How long the round trip took.
- void count_http_connection( ) noexcept#
Record what a finished HTTP transfer spent getting connected.
- Parameters:
connections – Connections opened, which is zero when one was reused.
dns – Time resolving the name.
tcp – Time establishing the transport connection.
tls – Time shaking hands, or zero without TLS.
-
template<typename Record>
class ScopedTimer# - #include <counters.hpp>
Times a scope and records the duration however the scope is left.
detail::ScopedTimer const probe{detail::count_remote_size_probe}; curl.perform(); // Counted whether it returns or throws.
- Template Parameters:
Record – What to hand the duration to. A
count_*()below, or a lambda for one that takes more than a duration.
-
CompatMode parse_compat_mode_str(std::string_view compat_mode_str)#
-
namespace statistics#
Enums
Functions
-
struct Counters#
- #include <counters.hpp>
Totals for work that belongs to no single operation.
An
Observationrecords one operation, and part of what I/O costs does not fit there, either because nothing correlates it with one operation or because it is shared between many.These counters count from the moment the process starts, whether or not anybody is watching, so there is nothing to enable and nothing to switch off. Reading them is
counters(), and the cost of an interval is the difference between two readings.Public Functions
-
Counters since(Counters const &previous) const noexcept#
The difference between this reading and an earlier one.
- Parameters:
previous – An earlier reading.
- Returns:
What was spent in between, saturating at zero.
-
bool empty() const noexcept#
Whether anything was counted at all.
- Returns:
True if every counter is zero.
-
std::string to_json() const#
Serialise to JSON.
- Returns:
A JSON object as a string.
-
std::string report(ReportRows rows = ReportRows::USED) const#
Format a human-readable report.
Grouped by subsystem, and a group the run never touched is left out, so an empty reading formats as an empty string.
http size probes 12 probes, 600 ms http handshake 128 connections, 40 ms dns, 900 ms tcp, 1.90 s tls
- Parameters:
rows – Which rows to print.
- Returns:
The report, newline-terminated, or empty.
Public Members
-
std::uint64_t remote_size_probes = {}#
Remote file sizes asked for, which is an HTTP round trip each.
-
std::uint64_t http_connections = {}#
Connections libcurl opened, as opposed to reused. Against the requests a run made, this is whether connections are being reused at all, which against a TLS endpoint dominates everything else.
-
Duration http_dns = {}#
Time those connections spent resolving, connecting, and shaking hands. libcurl measures these whether or not anybody asks, so reading them costs nothing.
-
std::uint64_t http_retries = {}#
Requests the endpoint turned away with a retryable error, and the time spent sleeping before trying again. A request that was retried twice counts twice. Nothing else records this, since a retry that eventually succeeds is reported as a success.
-
Counters since(Counters const &previous) const noexcept#
-
struct Summary#
- #include <summary.hpp>
Running totals of the I/O KvikIO has performed.
Everything here describes logical operations: one
pread()is one operation however many reads KvikIO issued underneath, and its duration covers the call from issue to completion.Public Functions
-
Duration wall() const noexcept#
Wall-clock span this summary covers.
- Returns:
end - start, or zero if the span is degenerate.
-
double busy_bytes_per_sec() const noexcept#
Throughput while KvikIO was actually busy.
Understates while an operation is in flight, since its time counts from the moment it starts and its bytes only once it completes.
- Returns:
Bytes per second while busy, or zero if no time was spent busy.
-
double busy_fraction() const noexcept#
Fraction of the span during which KvikIO was doing something.
- Returns:
The ratio, or zero if the span is degenerate.
-
Duration mean_duration() const noexcept#
Average time one operation took.
- Returns:
total_duration / num_ops, or zero if nothing completed.
-
Summary since(Summary const &previous) const#
Totals for the interval between an earlier reading and this one.
Every field is the difference of the two readings.
total_durationis the exception: an operation counts whole in the interval it finished in, however long it had been running.- Parameters:
previous – An earlier reading of the same span.
- Throws:
std::invalid_argument – if
previousis not one, which covers an interval fromsince(), a reading from another monitor, and one from before areset().- Returns:
The interval’s totals.
-
std::string to_json() const#
Serialize to JSON.
The timestamps are against the wall clock, so another program can line the summary up with its own log.
- Returns:
A JSON object as a string.
-
std::vector<std::byte> serialize() const#
Serialize to bytes, exactly.
Everything survives, including the clock anchor and the monotonic timestamps, so a summary that has been through a pipe is still a valid
previousforSummaryMonitor::since().Warning
Not a wire format. The payload is this build’s representation of the struct, so the bytes are readable only by the same architecture and the same version of KvikIO. The header carries the version, the size and a byte-order mark, so
deserialize()refuses anything it does not recognise and a mismatch is an exception rather than a wrong number.to_json()is the format to use when something else has to read it.- Returns:
The bytes, the same number of them for every summary.
-
std::string report(ReportRows rows = ReportRows::USED) const#
Format a human-readable report of every field.
Byte counts, durations and rates are scaled to readable units. Use
to_json()instead when the output is going to be parsed.KvikIO I/O summary wall time 243.80 ms operations 7 ...
- Parameters:
rows – Which rows to print. Under
ReportRows::USEDa backend the run never reached and a counter group it never touched are left out.- Returns:
The report, one field per line, newline-terminated.
Public Members
-
ClockAnchor anchor = {}#
What relates
startandendto the wall clock.They are read from a monotonic clock, so nothing outside this process can interpret them. The monitor takes one anchor when it is constructed and stamps every reading with it. See
kvikio::ClockAnchorfor how far to trust it over a long run.
-
std::uint64_t num_ops = {}#
Number of user-facing operations.
-
std::uint64_t num_reads = {}#
Of those, how many were reads and how many were writes.
-
std::uint64_t bytes_requested = {}#
Bytes the operations asked for.
-
std::uint64_t bytes_transferred = {}#
Bytes actually transferred. Differs from
bytes_requestedon a short read.
-
std::uint64_t bytes_read = {}#
Of those, how many were read and how many were written.
-
std::uint64_t num_errors = {}#
Number of operations that failed.
-
std::array<BackendTotals, num_io_backends> by_backend = {}#
What each backend carried, indexed by
IoBackend. Compatibility mode decides per call whether a read reaches cuFile or falls back to POSIX, so this is where that shows.
-
Counters counters = {}#
The work in the span that belongs to no single operation.
The counters run for the life of the process, and this is the part of them that falls inside the span.
-
Duration busy = {}#
Wall-clock time during which at least one operation was in flight.
The union of the operations’ time spans: overlapping work is counted once, the gaps between calls count as idle, and it never exceeds
wall(). An operation still running when the reading is taken counts for the time it has been running so far.Warning
An approximation, in both directions: a report delivered later than it was stamped can have an idle gap counted as busy, or busy time missed. Both need two threads and a report delayed past a whole operation. Against an exact merge of every span, the error is under 1.5 % for 8 B reads on 8 threads and zero for a
pread()of 4 KiB or more. Either waybusy <= wall()is guaranteed.
-
ObservationKind kind = {ObservationKind::LOGICAL}#
Which observations these totals are over.
LOGICALcounts one operation per user-facing call,PHYSICALone per transfer.
-
std::array<std::byte, 7> _reserved = {}#
Named rather than implicit padding, so that
serialize()never copies an indeterminate byte.
Public Static Functions
-
static Summary deserialize(std::vector<std::byte> const &bytes)#
Rebuild a summary from
serialize().- Parameters:
bytes – What
serialize()produced, on this architecture and this build.- Throws:
std::invalid_argument – if the bytes are not a summary, are the wrong length, or come from a build whose summary differs from this one’s.
- Returns:
The summary.
-
struct BackendTotals#
- #include <summary.hpp>
What one backend carried, for
Summary::by_backend.Every operation belongs to exactly one backend, so these add up to the summary’s own.
busyhas no counterpart here: it is a union over wall time, which two backends running at once would both claim, so per-backend unions would not sum to the total.
-
Duration wall() const noexcept#
-
class SummaryMonitor : private kvikio::Monitor#
- #include <summary.hpp>
Turns on I/O statistics for the process and accumulates them while it exists.
Create one early, keep it, and read it whenever a report is wanted:
kvikio::statistics::SummaryMonitor const monitor; // statistics are now on ... auto const s = monitor.get(); // totals so far std::cout << s.bytes_transferred << " B, " << s.busy_bytes_per_sec() / 1e9 << " GB/s\n";
For a rate over an interval rather than since the beginning, difference two readings. The result spans
[previous reading, now):auto const before = monitor.get(); run_a_phase(); std::cout << monitor.since(before).busy_bytes_per_sec() / 1e9 << " GB/s during that phase\n";
Or hand it a callback and let it report itself once, when it goes out of scope:
kvikio::statistics::SummaryMonitor const monitor{[](kvikio::statistics::Summary const& s) { std::cout << s.bytes_transferred << " bytes\n"; }};
By default a monitor counts one row per user-facing call. Pass
ObservationKind::PHYSICALto count one row per transfer instead, so a call split across the thread pool contributes one row per task andtotal_durationcovers the transfers rather than the calls waiting for a thread. The bytes are the same either way. Registering one of each gives both views of the same run:kvikio::statistics::SummaryMonitor const calls; kvikio::statistics::SummaryMonitor const transfers{kvikio::ObservationKind::PHYSICAL}; ... auto const queue_wait = calls.get().total_duration - transfers.get().total_duration;
Monitors are independent. Any number can exist at once, nested or overlapping, and resetting one has no effect on the others. An operation already in flight when the monitor is created is ignored entirely, neither counted nor timed.
Thread-safe:
get(),reset()andstop()may be called from any thread while I/O is in flight.Warning
A monitor measures the whole process, not a scope. It counts every thread’s I/O while it exists, not only the I/O of the thread that created it, and it cannot attribute I/O to a particular call. Wrapping a block in a monitor therefore measures that block only in a program where nothing else is doing I/O at the same time. In a library, or anywhere with a background reader, it will also count work you did not write.
Warning
The totals cover only what KvikIO observes, which is not every call it serves. See
kvikio::Monitorfor what is left out. A program doing all its I/O that way reports zero operations.Public Types
Public Functions
- explicit SummaryMonitor(
- ObservationKind kind = ObservationKind::LOGICAL
Create a monitor and begin counting.
- Parameters:
kind – Which observations to count.
LOGICALtotals one row per user-facing call.PHYSICALtotals one row per transfer, sobusycovers the transfers themselves rather than the calls that were waiting for a thread.
- explicit SummaryMonitor(
- Callback on_destruction,
- ObservationKind kind = ObservationKind::LOGICAL
Create a monitor that reports itself when it goes out of scope.
- Parameters:
on_destruction – Invoked with the totals from the destructor. Exceptions it throws are caught and logged, since a destructor cannot propagate them.
kind – Which observations to count.
-
~SummaryMonitor()#
Stop counting, invoke the callback if there is one, and release the registration.
Waits for any in-flight observation delivery to finish, so the monitor’s state is never touched after this returns.
-
Summary get() const#
Read the totals accumulated since construction, or since the last
reset().Safe to call repeatedly, and non-destructive.
Warning
This is a snapshot of a moving target. Operations still in flight are not included, and neither are completed ones whose observation has not been delivered yet, so a reading taken immediately after a single operation may fall short. Nothing is lost. It lands in a later reading.
- Returns:
The totals.
-
void reset()#
Zero the totals and restart the wall-clock span, as if the monitor had just been constructed.
Note
On a monitor that has been stopped this leaves an empty summary over a degenerate span: the origin moves forward, the end stays where
stop()fixed it, and nothing further can be counted.
-
Summary since(Summary const &previous) const#
Totals for the interval between an earlier reading and one taken now.
get().since(previous), for the common case of reporting one interval.auto const before = monitor.get(); run_a_phase(); std::cout << monitor.since(before).busy_bytes_per_sec() << " B/s during that phase\n";
Reporting periodically wants one reading per tick, differenced against the last, rather than this. Two calls would leave a gap between them, and an operation that completed in the gap would fall into both intervals.
auto baseline = monitor.get(); while (running) { sleep_for(interval); auto const now = monitor.get(); report(now.since(baseline)); baseline = now; }
- Parameters:
previous – An earlier reading from
get()on this monitor, taken since the lastreset().- Throws:
std::invalid_argument – if
previousis not one. SeeSummary::since().- Returns:
The interval’s totals.
-
void stop()#
Stop counting. Idempotent, and one-way, there is no resuming.
Safe to call from more than one thread, where the totals are final once any of them returns.
The totals are final once this returns, and
get()keeps returning them. The measured span ends here too, sowall()andbusy_fraction()describe the interval that was measured and do not drift as the process goes on to do other things.
-
struct Counters#
-
using PageAlignedBounceBufferPool = BounceBufferPool<PageAlignedAllocator>#