Expand description
§ispc-rs
A small library meant to be used as a build dependency with Cargo for easily integrating ISPC code into Rust projects.
§Documentation
Rust doc can be found here, ISPC documentation can be found here.
§Using ispc-rs
With ispc-rs you can compile your ISPC code from your build script to generate a native library and a Rust module containing bindings to the exported ISPC functions. ispc-rs will output commands to Cargo to link the native library, and you can import the Rust bindings into your code using a provided macro to call into the library. Using ispc-rs in this mode requires that the ISPC compiler and clang are available when compiling your crate.
When writing a crate or program which wants to package and use ISPC
code, but not necessarily require these dependencies on the end user’s system,
ispc-rs is actually split into two crates: a compile time crate (ispc_compile
)
and a runtime crate (ispc_rt
). The ispc_compile
crate is used to compile
the ISPC code in a build script, generating the native library and Rust bindings.
The ispc_rt
crate contains lightweight code to include in the build script
which will find and link against the previously compiled native libraries,
and a macro to import the previously generated Rust bindings. The recommended
use case is to include ispc_compile
as an optional dependency behind a feature
gate. When building with this feature gate the ISPC code will be built, otherwise
the runtime crate will find and use the existing libraries.
§Using ispc-rs as a Single Crate
To use ispc-rs as a single crate, you’ll want to add a build script to your
crate (build.rs
), tell Cargo about it, and add ispc-rs as a build time and
compile time dependency
# Cargo.toml
[package]
# ...
build = "build.rs"
[dependencies]
ispc = "2.0"
[build-dependencies]
ispc = "2.0"
Now you can use ispc
to compile your code into a static library:
extern crate ispc;
fn main() {
// Compile our ISPC library, this call will exit with EXIT_FAILURE if
// compilation fails.
ispc::compile_library("simple", &["src/simple.ispc"]);
}
Running cargo build
should now build your ISPC files into a library and link your Rust
application with it. For extra convenience the ispc_module
macro is provided to import
bindings to the library generated with rust-bindgen
into a module of the same name. Note that all the functions imported will be unsafe as they’re
the raw C bindings to your lib.
#[macro_use]
extern crate ispc;
// Functions exported from simple will be callable under simple::*
ispc_module!(simple);
§Requirements for Compiling ISPC Code
Both the ISPC compiler and libclang
(for rust-bindgen) must be available in your path
to compile the ISPC code and generate the bindings. These are not required if using ispc_rt
to link against a previously compiled library.
§Windows Users
You’ll need Visual Studio and will have to use the MSVC ABI version of Rust since ISPC
and Clang link with MSVC on Windows. For bindgen to find libclang you’ll need to copy
libclang.lib
to clang.lib
and place it in your path.
§Using the Separate Compile and Runtime Crates
The process of using the separate crates is similar to that of the single crate;
however, you’ll use the individual ispc_compile
and ispc_rt
crates, with the
former marked as an optional dependency. This will allow end users to use the
crate and leverage its ISPC code, without needing to re-build the code on their
machine. For this reason, it’s also recommended to build your ISPC code for multiple
vector ISAs, to allow for portability across CPU architectures. You’ll also need
to package a compiled ISPC library for each host target triple. This can
be done by building your crate with the ispc feature enabled on each target
host system you want to support users of your library on. Note that users
of your crate on a system you haven’t provided a binary for can still compile the ISPC
code themselves, by using your crate with the ispc feature enabled.
# Cargo.toml
[package]
# ...
build = "build.rs"
[dependencies]
ispc_rt = "2.0"
[build-dependencies]
ispc_rt = "2.0"
ispc_compile = { "2.0", optional = true }
[features]
ispc = ["ispc_compile"]
In the build script we can now use the ispc
feature to optionally
compile the ispc code using ispc_compile
, otherwise we’ll link the
previously built code with ispc_rt
. Here we’ll also output the
compiled ISPC libraries and bindings into the src/ directory.
extern crate ispc_rt;
#[cfg(feature = "ispc")]
extern crate ispc_compile;
#[cfg(feature = "ispc")]
fn link_ispc() {
use ispc_compile::TargetISA;
ispc_compile::Config::new()
.file("src/simple.ispc")
.target_isas(vec![
TargetISA::SSE2i32x4,
TargetISA::SSE4i32x4,
TargetISA::AVX1i32x8,
TargetISA::AVX2i32x8,
TargetISA::AVX512KNLi32x16,
TargetISA::AVX512SKXi32x16])
.out_dir("src/")
.compile("simple");
}
#[cfg(not(feature = "ispc"))]
fn link_ispc() {
ispc_rt::PackagedModule::new("simple")
.lib_path("src/")
.link();
}
fn main() {
link_ispc();
}
Running cargo build --features ispc
will now build your ISPC files into a library
and generate bindings for your exported ISPC functions. The compiled library and
generated bindings file will be saved under src/
, to allow packaging with the rest
of the crate. When building with cargo build
, the previously compiled library
for the host system will be linked against.
Whether building with or without the ispc feature, you can import the generated
bindings into your rust code with the ispc_module!
macro as before:
#[macro_use]
extern crate ispc;
// Functions exported from simple will be callable under simple::*
ispc_module!(simple);
Some more complete examples can be found in the examples/ folder. The separate crates example is here
Modules§
- bindgen
- Generate Rust bindings for C and C++ libraries.
- exec
- Defines the trait that must be implemented by ISPC task execution systems and provides a default threaded one for use.
- instrument
- Defines the trait that must be implemented by ISPC instrumentation callbacks structs and provides a default one.
- opt
- This module has various option flags and configs we can pass to ISPC, located here for convience and clutter reduction.
- task
- Defines structs for operating on ISPC task groups and getting chunks of a task to be scheduled on to threads
Macros§
- ispc_
module - Convenience macro for generating the module to hold the raw/unsafe ISPC bindings.
Structs§
- Config
- Extra configuration to be passed to ISPC
- Packaged
Module - A
PackagedModule
refers to an ISPC module which was previously built usingispc_compile
, and is now distributed with the crate. - Parallel
- A multithreaded execution environment for the tasks launched in ISPC
- Simple
Instrument - A simple ISPC instrumenter which will print the information passed to it out.
Enums§
- Addressing
- Select 32 or 64 bit addressing to be used by ISPC. Note: 32-bit addressing calculations are done by default, even on 64 bit target architectures.
- Architecture
- Select the target CPU architecture
- CPU
- ISPC target CPU ISA options. If none is set, ISPC will target the machine being compiled on.
- MathLib
- Different math libraries that ISPC can use for computations.
- Optimization
Opt - ISPC optimization options.
- TargetISA
- Target instruction sets and vector widths available to specialize for. The default if none is set will be the host CPU’s ISA and vector width.
- TargetOS
- Target instruction sets and vector widths available to specialize for. The default if none is set will be the host CPU’s ISA and vector width.
Traits§
- Instrument
- Trait to be implemented to provide ISPC instrumentation functionality.
- Task
System - Trait to be implemented to provide ISPC task execution functionality.
Functions§
- compile_
library - Compile the list of ISPC files into a static library and generate bindings using bindgen. The library name should not contain a lib prefix or a lib extension like ‘.a’ or ‘.lib’, the appropriate prefix and suffix will be added based on the compilation target.
- print_
instrumenting_ summary - Print out a summary of performace data gathered from instrumenting ISPC.
Must enable instrumenting to have this record and print data, see
Config::instrument
. - set_
instrument - If you have implemented your own instrument for logging ISPC performance data you can use this function to provide it for use instead of the default one. This function must be called before calling into ISPC code, otherwise the instrumenter will already be set to the default.
- set_
task_ system - If you have implemented your own task system you can provide it for use instead
of the default threaded one. This must be done prior to calling ISPC code which
spawns tasks otherwise the task system will have already been initialized to
Parallel
, which you can also see as an example for implementing a task system.
Type Aliases§
- ISPC
Task Fn - A pointer to an ISPC task function.