weld 0.4.0

Weld is a language and runtime for improving the performance of data-intensive applications.
Documentation

Weld is a runtime for improving the performance of data-intensive applications. It optimizes across libraries and functions by expressing the core computations in libraries using a small common intermediate representation, similar to CUDA and OpenCL.

Using Weld

Weld is a small programming language that supports parallel loops and builders, which are declarative objects that specify how to build results. The parallel loops can be used in conjunction with the builders to build a result in parallel.

This crate contains the Weld compiler and runtime, though users only interact with the compiler. Users use Weld by constructing a Weld program (currently as a string), compiling the string into a runnable module, and then running the module with in-memory data.

Weld JITs code into the current process using LLVM. As a result, Weld users must have a version of LLVM installed on their machine (currently, Weld uses LLVM 6).

Example

The following program shows a minimal Weld program that adds two numbers:

# extern crate weld;
#
# use weld::*;
#
#[repr(C)]
struct MyArgs {
a: i32,
b: i32,
}

let code = "|a: i32, b: i32| a + b";
let conf = &WeldConf::new();
let mut module = WeldModule::compile(code, conf).unwrap();

// Weld accepts a packed C struct as an argument.
let args = &MyArgs { a: 1, b: 50 };
let input = &WeldValue::new_from_data(args as *const _ as Data);

// A context manages memory.
let context = &mut WeldContext::new(conf).unwrap();

// Running a Weld module and reading a value out of it is unsafe!
unsafe {
// Run the module, which returns a wrapper `WeldValue`.
let result = module.run(context, input).unwrap();
// The data is just a pointer: cast it to the expected type
let data = result.data() as *const i32;

let result = (*data).clone();
assert_eq!(args.a + args.b, result);
}

Users write a Weld program as a string, compile it into a module, and then pass packed arguments into it to run the JITed code. The result is a pointer that represents the output of the Weld program: we can cast that to the appropriate pointer type and read it by dereferencing.

Modules

The WeldModule is the main entry point into Weld. Users can compile Weld programs using WeldModule::compile, and then run compiled programs using WeldModule::run.

The module functions can be configured in several ways. This configuration is controlled using the WeldConf struct, which is effectively a dictionary of String key/value pairs that control how a Weld program is compiled and run.

Values

Since Weld JITs code and implements a custom runtime, data passed in and out of it must be in a specific, C-compatible packed format. The Weld Github contains a plethora of information on how data should be formatted when passed into Weld, but in short, it is not safe to simply pass Rust objects into Weld.

WeldModule accepts and returns a wrapper struct called WeldValue, which wraps an opaque *const void that Weld reads depending on the argument and return types of the Weld program. Weld's main run function is thus unsafe: users need to guarantee that the data passed into Weld is properly formatted!

Passing Rust Values into Weld

Currently, users need to manually munge Rust values into a format that Weld understands, as specified here. Eventually, we may add a module in this crate that contains wrappers for some useful types. The current Rust types can be passed safely into Weld already:

  • Primitive types such as i8, i16, and f32. These have a 1-1 correspondance with Weld.
  • Rust structs with repr(C).

Notably, Vec<T> cannot be passed without adhering to the custom Weld format. Currently, that format is defined as:

#[repr(C)]
struct WeldVec<T> {
ptr: *const T,
len: i64,
}

There is thus a straightforward conversion from Vec<T> to a WeldVec<T>.

The data module defines layouts of Weld-compatible types, and also contains some methods for converting Rust values into Weld values.

Contexts

A context manages state such as allocation information. A context is passed into WeldModule::run and updated by the compiled Weld program.

The WeldContext struct wraps a context. Contexts are internally reference counted because values produced by Weld hold references to the context in which they are allocated. The memory backing a WeldContext is freed when all references to the context are dropped.