The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
OpenCL compiles a single string of source code for each program. The string must be self-contained: all functions used by the kernel must be defined in the same string, in order, before they are called. There are no separate compilation units and no linker.
When a kernel needs dnorm4, and dnorm4
itself needs R_D__0 and R_finite, those
definitions must precede dnorm4 in the string, which must
precede the kernel body. opencltools provides two R
functions that assemble and sort source components; use
package = "nmathopencl" for this package’s
inst/cl/ tree.
opencltools::load_kernel_source()Reads and returns the contents of a single .cl file from
inst/cl/ inside the named package. The
relative_path is relative to inst/cl/:
# Load the dnorm kernel entry-point file
kernel_src <- opencltools::load_kernel_source("src/dnorm_kernel.cl",
package = "nmathopencl")
# Load a custom kernel from another package's inst/cl/
my_kernel <- opencltools::load_kernel_source("ex_glmbayes_src/f2_f3_binomial_logit.cl",
package = "nmathopencl")The returned character string can be concatenated with a library string and passed to the C++ runner.
opencltools::load_kernel_library()Reads all .cl files from
inst/cl/<subdir>/, parses the @provides
/ @depends annotations in each file, performs a topological
sort, and returns a single concatenated source string with files in
dependency-correct order.
# Load the complete nmath library (all ~180 files)
nmath_src <- opencltools::load_kernel_library("nmath", package = "nmathopencl")
# Load a smaller subset pre-curated for glmbayes kernels
nmath_glm <- opencltools::load_kernel_library("ex_glmbayes_nmath",
package = "nmathopencl")
# Load with diagnostic output to trace the sort order
nmath_src <- opencltools::load_kernel_library("nmath",
package = "nmathopencl",
verbose = TRUE)For opencltools::load_kernel_library() to sort
correctly, every .cl file in the subdirectory must begin
with an annotation block:
| Tag | Required? | Meaning |
|---|---|---|
@provides |
Yes | Comma-separated list of function (or symbol) names defined in this file |
@depends |
Yes (may be empty) | Comma-separated list of .cl filenames (without
extension) that must appear earlier in the output |
@includes |
Optional | Library grouping label; used for diagnostics only |
Rules for @depends:
@depends,
so the header is always loaded first.@depends empty or omit the tag.Example for dgamma.cl:
This tells the resolver: emit nmath.cl,
dpois.cl, and lgamma.cl before
dgamma.cl. The resolver handles those files’ own
dependencies recursively.
opencltools::load_kernel_library() uses a
straightforward iterative topological sort:
.cl files and extract their
@provides and @depends tags.@depends
entries are all already in the sorted set. Emit those files and add them
to the sorted set."Dependency sort failed: unresolved dependencies remain."Files with an empty @depends list are emitted first
(pass 1). These are always the library header files.
When verbose = TRUE, the function prints each pass of
the sort:
Pass 1: emitting nmath.cl, Rmath.cl, dpq.cl
Pass 2: emitting chebyshev.cl, cospi.cl, fmax2.cl, gammalims.cl
Pass 3: emitting lgammacor.cl
Pass 4: emitting lgamma.cl, gamma.cl
...
This is invaluable for debugging missing or circular
@depends tags.
If file A lists file B in its @depends and file B lists
file A, the resolver will detect this on the first pass where neither
can be promoted, and throw an error. If verbose = TRUE, it
prints the stuck files before throwing.
The standard fix is to split one of the mutually dependent files into two:
refactored.cl that provides forward declarations for
any symbols referenced before they are defined.Chapter 04 describes the three specific cycles in the nmath library and how they are resolved.
A complete OpenCL program string is assembled by concatenating library and kernel sources in order:
library(nmathopencl)
# 1. Load the nmath library (sorted automatically)
nmath_src <- opencltools::load_kernel_library("nmath", package = "nmathopencl")
# 2. Load the kernel entry-point
kernel_src <- opencltools::load_kernel_source("src/dnorm_kernel.cl",
package = "nmathopencl")
# 3. Concatenate into a single program string
program <- paste(nmath_src, kernel_src, sep = "\n")This program string is then passed to the C++ runner
(see Chapter 09).
The package argument tells
opencltools::load_kernel_source() and
opencltools::load_kernel_library() which package’s
inst/cl/ to look in:
# Load the curated nmath subset shipped inside nmathopencl
# for use by a downstream package's kernels
nmath_sub <- opencltools::load_kernel_library("ex_glmbayes_nmath",
package = "nmathopencl")
# Load a custom kernel from the same downstream package
my_kernel <- opencltools::load_kernel_source("ex_glmbayes_src/f2_f3_binomial_logit.cl",
package = "nmathopencl")
program <- paste(nmath_sub, my_kernel, sep = "\n")This is exactly the pattern used by f2_f3_opencl() in
the ex_glmbayes example (see Chapter 10).
opencltools::load_kernel_library() always sorts and
loads all files in the subdirectory. For a large
library like nmath (137 files) this is thorough but
wasteful when only a small subset is needed for a specific kernel.
nmathopencl therefore ships a pre-built dependency index
alongside every curated library subdirectory. The index encodes the full
transitive dependency map and the global load order, enabling two
important optimizations:
load_library_for_kernel() (R) — loads
only the files required by one specific kernel, with no sort at
runtime.load_library_for_kernel() (C++) — the
same function implemented entirely in C++, suitable for use inside Rcpp
kernel wrappers.write_kernel_dependency_index()This function analyzes a library directory, computes the full
transitive dependency closure for every stem, and writes two
companion files next to the .cl sources:
| File | Format | Consumer |
|---|---|---|
kernel_dependency_index.rds |
Binary R object | R functions |
kernel_dependency_index.tsv |
Tab-separated text | C++ code |
The .tsv has a header row and one row per stem in global
load order:
stem all_depends
refactored
Rmath refactored
nmath refactored, Rmath
chebyshev refactored, Rmath, nmath
dbinom dpq, refactored, Rmath, nmath, stirlerr_cycle_free, ...
Both files are shipped with the package so end users never need to
regenerate them. Run write_kernel_dependency_index() only
after adding or removing .cl files from a library
directory.
load_library_for_kernel()
(R)Reads the annotation tag @{depends_tag} from the kernel
file to get the list of needed stems, looks them up in the pre-loaded
index, and returns their source concatenated in correct dependency
order. Returns "" when the kernel has no
@{depends_tag} annotation (e.g. a kernel using only OpenCL
built-ins).
The index argument should always be supplied. Load it
once and reuse it across all calls to avoid reading from disk on every
invocation:
nmath_dir <- system.file("cl", "nmath", package = "nmathopencl")
# Load the index once
idx <- readRDS(file.path(nmath_dir, "kernel_dependency_index.rds"))
# Re-use across multiple kernels --- only the subset for each kernel is read
src_gaussian <- load_library_for_kernel(
kernel_path = system.file("cl", "ex_glmbayes_src",
"f2_f3_gaussian.cl", package = "nmathopencl"),
library_dir = nmath_dir,
depends_tag = "depends_nmath",
index = idx
)
src_gamma <- load_library_for_kernel(
kernel_path = system.file("cl", "ex_glmbayes_src",
"f2_f3_gamma.cl", package = "nmathopencl"),
library_dir = nmath_dir,
depends_tag = "depends_nmath",
index = idx
)The annotation tag in the kernel file must follow the same format used throughout the library:
extract_library_subset()extract_library_subset(kernel_paths, library_dir, dest_dir,
depends_tag = "all_depends",
index = NULL,
overwrite = FALSE)Given a set of kernel files, reads their @{depends_tag}
annotations, takes the union of all transitive dependencies, and copies
exactly those .cl files (plus both index files) from
library_dir to dest_dir in dependency order.
The destination directory must already exist.
nmath_dir <- system.file("cl", "nmath", package = "nmathopencl")
src_dir <- system.file("cl", "ex_glmbayes_src", package = "nmathopencl")
dest_dir <- "inst/cl/mypkg_nmath" # must exist
idx <- readRDS(file.path(nmath_dir, "kernel_dependency_index.rds"))
result <- extract_library_subset(
kernel_paths = list.files(src_dir, pattern = "\\.cl$", full.names = TRUE),
library_dir = nmath_dir,
dest_dir = dest_dir,
depends_tag = "depends_nmath",
index = idx
)
print(result) # data frame: stem, source, dest, copiedThe result includes a row for
kernel_dependency_index.rds and
kernel_dependency_index.tsv so the extracted subset is
immediately usable by both R and C++.
openclPort::load_library_for_kernel()For use inside Rcpp kernel wrappers (where calling back into R is not
permitted), kernel_loader.cpp provides a C++ implementation
with the same semantics:
#include "openclPort.h" // declares load_library_for_kernel
// Inside a kernel wrapper, after the family/link dispatch has set kernel_file:
std::string nmath_source = openclPort::load_library_for_kernel(
kernel_file, // e.g. "ex_glmbayes_src/f2_f3_binomial_logit.cl"
"ex_glmbayes_nmath", // library subdirectory
"nmathopencl", // package
"depends_nmath" // annotation tag
);The C++ function reads kernel_dependency_index.tsv from
the library directory once per call, parses the annotation tag from the
kernel file, and loads only the required subset in the pre-computed
order. No topological sort is performed at runtime.
The @depends_nmath annotation must list the
direct nmath entry-point stems called by the kernel
(not the full transitive list):
The transitive expansion is performed automatically using the TSV index.
| Error | Cause |
|---|---|
"OpenCL support is not available" |
Package built without USE_OPENCL |
"Dependency sort failed: unresolved dependencies remain." |
A @depends entry names a file that does not exist in
the directory, or there is a genuine circular dependency |
"File not found: inst/cl/<path>" |
relative_path does not match any file in the
package |
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.