Project

carray-jit

0.0
The project is in a healthy, maintained state
Write the loop in Ruby, and it runs at the speed of C -- one to two orders of magnitude faster than interpreted. It is for what a CArray expression cannot say: a cell that reaches its neighbours, a recurrence, a loop written out. What may be in a block is a subset of Ruby, and a C compiler has to be present at run time.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

>= 3.0.3, < 3.1
>= 0
 Project Readme

carray-jit

JIT compilation of CArray kernels written in Ruby.

This library was written to make explicit, cell-by-cell work on CArray arrays fast. A subset of Ruby chosen for numerical computation is JIT-compiled and evaluated as a C-level loop over CArray arrays: a cell that reads its neighbours, a recurrence, a loop written out. The aim is to combine that with CArray's already fast vectorized arithmetic and reductions, and so speed up numerical computation with CArray as a whole.

The block is read with Prism, translated to C if it falls inside that subset, compiled with the system C compiler and called through Fiddle. The compiled object is cached on disk, so a kernel is compiled once.

Status

0.1.4 is the current release, and it still moves: behaviour can change between releases.

Features

  • A JIT compiler for C-level loops. A block becomes one C function over CArray's own memory, built by the system C compiler and called through Fiddle.
  • Ordinary Ruby, and enough of it. The source is parsed with Prism -- no DSL, no eval -- and every operation means what Ruby means by it, apart from the order a reduction takes its terms in. The subset is enough to state a numerical algorithm; what falls outside it is refused by name and line, not run as a Ruby loop.
  • A method for each shape. jit_for for recurrences and loops written out, jit_stencil for windows at any rank, CArray.jit_contract for contraction over a repeated index, or over every index the result's axes do not name, jit_each and jit_map for a pass that reaches no neighbour, jit_init for filling an array from its own indices.
  • View- and mask-aware. Columns, transposes and slices of slices are written in place without a copy, and masks propagate as CArray propagates them.
  • Pure C functions, in and out. jit_extern binds one from a library and a kernel calls it by address; jit_function compiles one from a block and hands back a C function pointer.
  • The backend for CArray.fuse. An array expression compiles instead of being walked a node at a time, without being asked and without changing the answer.
  • Compiled once, across processes. The shared object is cached on disk and reused by later runs.

Install

gem install carray-jit

Or add it to your Gemfile:

gem "carray-jit"

Requires:

  • Ruby >= 3.2
  • CArray >= 3.0.4, < 3.1
  • A C compiler
  • Prism and Fiddle (both ship with Ruby; Fiddle is a bundled gem)

Example

# Legendre polynomials at x = 0.5, by the recurrence that defines them.
# No array expression states this: P[i] needs P[i-1], which the same
# loop has just written.

x = 0.5
legendre = CArray.double(24)
legendre[0] = 1.0                     # P_0(x) = 1
legendre[1] = x                       # P_1(x) = x

CArray.jit_for(2...24) { |i|          # i is the loop index: 2, 3, ... 23
  w  = x * legendre[i-1]              # a block local; its type is inferred
  wy = w - legendre[i-2]              # reaching back two cells
  legendre[i] = wy + w - wy/i         # the cell this pass writes
}

legendre[0..5].to_a
#  => [1.0, 0.5, -0.125, -0.4375, -0.2890625, 0.08984375]

The jit_ methods are this gem's, and exist once require "carray/jit" has run. An expression over whole arrays wants CArray.fuse, which is CArray's own and needs no compiler -- and gets compiled anyway where this gem is loaded.

Documentation

Contributing

Bug reports and feature requests are welcome — please open an issue.

Before opening a pull request, read CONTRIBUTING.md. It is short, and it says which form a contribution is best sent in. A small, self-contained bug fix is fine as a pull request. Anything larger is better started as an issue: code here gets rewritten as a matter of course, so a patch for a larger change is likely to end up reimplemented rather than merged, and describing the problem gets you further than writing one.

Credits

carray-jit is created and maintained by himotoyoshi. The author provided the design; the implementation was written with AI coding tools and has been verified primarily through the test suite and practical use.

License

MIT