Git Product home page Git Product logo

easy-just-in-time's Introduction

Easy::jit: A just-in-time compiler for C++

About

Easy::jit is a compiler-assisted library that enables simple Just-In-Time code generation for C++ codes.

Talks

Building

First, install clang and LLVM.

apt install llvm-6.0-dev llvm-6.0-tools clang-6.0

Then, configure and compile the project.

cmake -DLLVM_DIR=/usr/lib/llvm-6.0/cmake <path_to_easy_jit_src>
cmake --build .

To build the examples, install the opencv library, and add the flags -DEASY_JIT_EXAMPLE=1 to the cmake command.

To enable benchmarking, install the google benchmark framework, and add the flags -DEASY_JIT_BENCHMARK=1 -DBENCHMARK_DIR=<path_to_google_benchmark_install> to the cmake command.

Everything is ready to go!

Docker

If you want to give only a quick test to the project, everything is provided to use it with docker. To do this, generate a Dockerfile from the current directory using the scripts in <path_to_easy_jit_src>/misc/docker, then generate your docker instance.

python3 <path_to_easy_jit_src>/misc/docker/GenDockerfile.py  <path_to_easy_jit_src>/.travis.yml > Dockerfile
docker build -t easy/test -f Dockerfile
docker run -ti easy/test /bin/bash

Basic usage

Compiling my project with Easy::Jit

Since the Easy::Jit library relies on assistance from the compiler, its mandatory to load a compiler plugin in order to use it. The flag -Xclang -load -Xclang <path_to_easy_jit_build>/bin/EasyJitPass.so loads the plugin.

The included headers require C++14 support, and remember to add the include directories! Use --std=c++14 -I<path_to_easy_jit_src>/cpplib/include.

Finaly, the binary must be linked against the Easy::Jit runtime library, using -L<path_to_easy_jit_build>/bin -lEasyJitRuntime.

Putting all together we get the command bellow.

clang++-6.0 --std=c++14 <my_file.cpp> \
  -Xclang -load -Xclang /path/to/easy/jit/build/bin/bin/EasyJitPass.so \
  -I<path_to_easy_jit_src>/cpplib/include \
  -L<path_to_easy_jit_build>/bin -lEasyJitRuntime

Using Easy::Jit inside my project

Consider the code below from a software that applies image filters on a video stream. In the following sections we are going to adapt it to use the Easy::jit library. The function to optimize is kernel, which applies a mask on the entire image.

The mask, its dimensions and area do not change often, so specializing the function for these parameters seems reasonable. Moreover, the image dimensions and number of channels typically remain constant during the entire execution; however, it is impossible to know their values as they depend on the stream.

static void kernel(const char* mask, unsigned mask_size, unsigned mask_area,
                   const unsigned char* in, unsigned char* out,
                   unsigned rows, unsigned cols, unsigned channels) {
  unsigned mask_middle = (mask_size/2+1);
  unsigned middle = (cols+1)*mask_middle;

  for(unsigned i = 0; i != rows-mask_size; ++i) {
    for(unsigned j = 0; j != cols-mask_size; ++j) {
      for(unsigned ch = 0; ch != channels; ++ch) {

        long out_val = 0;
        for(unsigned ii = 0; ii != mask_size; ++ii) {
          for(unsigned jj = 0; jj != mask_size; ++jj) {
            out_val += mask[ii*mask_size+jj] * in[((i+ii)*cols+j+jj)*channels+ch];
          }
        }
        out[(i*cols+j+middle)*channels+ch] = out_val / mask_area;
      }
    }
  }
}

static void apply_filter(const char *mask, unsigned mask_size, unsigned mask_area, cv::Mat &image, cv::Mat *&out) {
  kernel(mask, mask_size, mask_area, image.ptr(0,0), out->ptr(0,0), image.rows, image.cols, image.channels());
}

The main header for the library is easy/jit.h, where the only core function of the library is exported. This function is called -- guess how? -- easy::jit. We add the corresponding include directive them in the top of the file.

#include <easy/jit.h>

With the call to easy::jit, we specialize the function and obtain a new one taking only two parameters (the input and the output frame).

static void apply_filter(const char *mask, unsigned mask_size, unsigned mask_area, cv::Mat &image, cv::Mat *&out) {
  using namespace std::placeholders;

  auto kernel_opt = easy::jit(kernel, mask, mask_size, mask_area, _1, _2, image.rows, image.cols, image.channels());
  kernel_opt(image.ptr(0,0), out->ptr(0,0));
}

Deducing which functions to expose at runtime

Easy::jit embeds the LLVM bitcode representation of the functions to specialize at runtime in the binary code. To perform this, the library requires access to the implementation of these functions. Easy::jit does an effort to deduce which functions are specialized at runtime, still in many cases this is not possible.

In this case, it's possible to use the EASY_JIT_EXPOSE macro, as shown in the following code,

void EASY_JIT_EXPOSE kernel() { /* ... */ }

or using a regular expression during compilation. The command bellow exports all functions whose name starts with "^kernel".

clang++ ... -mllvm -easy-export="^kernel.*"  ...

Caching

In parallel to the easy/jit.h header, there is easy/code_cache.h which provides a code cache to avoid recompilation of functions that already have been generated.

Bellow we show the code from previous section, but adapted to use a code cache.

#include <easy/code_cache.h>
static void apply_filter(const char *mask, unsigned mask_size, unsigned mask_area, cv::Mat &image, cv::Mat *&out) {
  using namespace std::placeholders;

  static easy::Cache<> cache;
  auto const &kernel_opt = cache.jit(kernel, mask, mask_size, mask_area, _1, _2, image.rows, image.cols, image.channels());
  kernel_opt(image.ptr(0,0), out->ptr(0,0));
}

License

See file LICENSE at the top-level directory of this project.

Thanks

Special thanks to Quarkslab for their support on working in personal projects.

Warriors

Serge Guelton (serge_sans_paille)

Juan Manuel Martinez Caamaño (jmmartinez)

Kavon Farvardin (kavon) author of atJIT

easy-just-in-time's People

Contributors

dendisuhubdy avatar jmmartinez avatar jmmartinez-qb avatar ppapageo avatar serge-sans-paille avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

easy-just-in-time's Issues

Every example fails with an Assertion Error

I am currently experimenting with this tool / library, but every example that I want to try fails with the following assertion error:

a.out: /path/to/easy-just-in-time/runtime/pass/InlineParameters.cpp:31: easy::HighLevelLayout GetNewLayout(const easy::Context &, easy::HighLevelLayout &): Assertion `C.size() == HLL.Args_.size()' failed.

Since I have no Idea about the internals of this project I do not know what to do. Do you have any idea whats wrong (or what I am missing?)?

Additional Information:

  • Happens during the call of easy::jit

  • Command used to compile the tests: clang++ --std=c++14 test.cpp -Xclang -load -Xclang /path/to/easy-just-in-time/build/bin/EasyJitPass.so -I /path/to/easy-just-in-time/include -L /path/to/easy-just-in-time/build/bin -lEasyJitRuntime -stdlib=libc++

Example camfilter fails

I have a self-built LLVM/Clang 6.0.1 and building with examples fails at camfilter with

[1/2] Building CXX object doc/readme/CMakeFiles/easyjit-example.dir/camfilter.cpp.o
FAILED: doc/readme/CMakeFiles/easyjit-example.dir/camfilter.cpp.o 
/usr/local/bin/clang++   -I/usr/local/include -I/home/maliusarth/dev/ext/repos/easy-just-in-time/include -isystem /usr/local/include/opencv4 -Xclang -disable-O0-optnone -Xclang -load -Xclang /home/maliusarth/dev/ext/projects/cmake/easy-just-in-time/bin/EasyJitPass.so -g   -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -std=gnu++14 -MD -MT doc/readme/CMakeFiles/easyjit-example.dir/camfilter.cpp.o -MF doc/readme/CMakeFiles/easyjit-example.dir/camfilter.cpp.o.d -o doc/readme/CMakeFiles/easyjit-example.dir/camfilter.cpp.o -c /home/maliusarth/dev/ext/repos/easy-just-in-time/doc/readme/camfilter.cpp
/home/maliusarth/dev/ext/repos/easy-just-in-time/doc/readme/camfilter.cpp:198:50: error: use of undeclared identifier 'cvPoint'
    cv::putText(*Out, fps_message.str().c_str(), cvPoint(30,30),
                                                 ^
/home/maliusarth/dev/ext/repos/easy-just-in-time/doc/readme/camfilter.cpp:200:17: error: use of undeclared identifier 'cvScalar'
                cvScalar(200,200,250), 1, CV_AA);
                ^
/home/maliusarth/dev/ext/repos/easy-just-in-time/doc/readme/camfilter.cpp:200:43: error: use of undeclared identifier 'CV_AA'
                cvScalar(200,200,250), 1, CV_AA);
                                          ^
3 errors generated.
ninja: build stopped: subcommand failed.

more complex examples?

the idea behind his project is really cool. very nice work.

i've been looking at some of the examples, and i'm wondering if you have any more complex examples of the functions that can be jit compiled. it looks like all the examples (maybe im missing some?) are all just doing basic variable value substitution before the jit compile step. i'm wondering about loop unrolling (e.g. if a vector is the parameter), or perhaps changing control flow to build expressions.

Compare with optimized convolutions

Hey there, promising work on a C++ JIT.

Can you compare your JIT results with state-of-the-art convolution or at least im2col + GEMM convolution and report the GFLOP/s reached and theoretical peak?

Here are all the resources I gathered regarding convolution optimisation.

The main issue with naive direct convolution are the cache misses and poor utilisation of the CPU cache hierarchy.

On benchmarks on my CPU, a i5-5257U 2.7Ghz dual core Broadwell supporting AVX+FMA the theoretical compute peak is 172.8 GLOP/s, however a naive convolution can reach only 2.6 GFLOP/s. When reframing as a im2col + GEMM (matrix multiplication), I can reach 20+ GFLOP/s.

I didn't finish yet but I hope to reach 120+ GFLOP/s using my own BLAS which attains 98% of the speed of OpenBLAS (72.4 GFLOPS vs 73.8 GFLOPS single threaded, 136 GFLOP/s vs 145 GFLOP/s multithreaded) and fusing im2col with the matrix multiplication repacking steps.

Other promising approaches that should reach 100+ GFLOP/s are MKL-DNN and libxsmm which is described in great detail in this paper.

Also Halide has an optimised JIT generation for computational imagery and already relies on LLVM.

Internal structure of the project

Hi, I'm actually doing my bachelor's thesis about Just in Time compiler and i found your project, which could be really useful for me. But, I have a question, is there any documentation about the internal structure of the project, or about how the library works ? It could be a mailling list or a schema with explanation or anything else.

CMake Error: Could NOT find PY_lit (missing: PY_LIT)

Ubuntu 18.04
Clang 8.0
LLVM 6.0 dev and tools
CMake 3.12
Running CMake as appropriate yields an immediate failure of
-- Could NOT find PY_lit (missing: PY_LIT)
I assume this to be some kind of python dependency but I've never seen that error before.
Python 2.7.15 and 3.6.8 are installed, so I don't know what the issue is.

Linking errors when moving to LLVM 14.0.6

I'm attempting to update this library to use LLVM 14.0.6. I can compile the plugin and runtime library, but I encounter a linking error when attempting to build the easyjit-example test:

Undefined symbols for architecture arm64:
  "char* easy::layout::serialize_arg<char const*>(char const*)", referenced from:
      void* easy::layout::get_layout<char const*>() in camfilter.cpp.o
  "char* easy::layout::serialize_arg<unsigned char const*>(unsigned char const*)", referenced from:
      void* easy::layout::get_layout<unsigned char const*>() in camfilter.cpp.o
  "char* easy::layout::serialize_arg<unsigned char*>(unsigned char*)", referenced from:
      void* easy::layout::get_layout<unsigned char*>() in camfilter.cpp.o
  "char* easy::layout::serialize_arg<unsigned int>(unsigned int)", referenced from:
      void* easy::layout::get_layout<unsigned int>() in camfilter.cpp.o
ld: symbol(s) not found for architecture arm64

My fork:
https://github.com/kathlenehurt-sifive/easy-just-in-time/tree/llvm-14.0.6

Is this repo still being maintained?

Example fails with `Inserted && "Pass registered multiple times!"' error

Compiling with a custom build of LLVM 6.0 works:

$ pwd
/home/mogosanu/llvm-jit/easyjit-obj
$ cmake -DLLVM_DIR=/opt/llvm-6.0/lib/cmake/llvm/ ../easy-just-in-time/
$ cmake --build .
# generates /home/mogosanu/llvm-jit/easyjit-obj/bin/{EasyJitPass.so,libEasyJitRuntime.so}

And so does compiling a very simple example:

/opt/llvm-6.0/bin/clang++ -O2 --std=c++14 -o hello hello.cpp \
  -Xclang -load -Xclang /home/mogosanu/llvm-jit/easyjit-obj/bin/EasyJitPass.so \
  -I/home/mogosanu/llvm-jit/easy-just-in-time/include -L/home/mogosanu/llvm-jit/easyjit-obj/bin \
  -lEasyJitRuntime

But running it gives the following error:

$ LD_LIBRARY_PATH=/home/mogosanu/llvm-jit/easyjit-obj/bin ./hello 
hello: /home/mogosanu/llvm-jit/llvm/lib/IR/PassRegistry.cpp:62: void llvm::PassRegistry::registerPass(const llvm::PassInfo&, bool): Assertion `Inserted && "Pass registered multiple times!"' failed.
Aborted

hello.cpp:

#include <cstdio>

int main(void)
{
	printf("Hello, world!\n");
	return 0;
}

Can I get some help regarding this? Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.