Easy::jit adalah pustaka berbantuan kompiler yang memungkinkan pembuatan kode Just-In-Time sederhana untuk kode C++.
Pertama, instal dentang dan LLVM.
apt install llvm-6.0-dev llvm-6.0-tools clang-6.0
Kemudian, konfigurasikan dan kompilasi proyek.
cmake -DLLVM_DIR=/usr/lib/llvm-6.0/cmake < path_to_easy_jit_src >
cmake --build .
Untuk membuat contoh, instal pustaka opencv, dan tambahkan flag -DEASY_JIT_EXAMPLE=1
ke perintah cmake.
Untuk mengaktifkan benchmarking, instal kerangka benchmark Google, dan tambahkan flag -DEASY_JIT_BENCHMARK=1 -DBENCHMARK_DIR=<path_to_google_benchmark_install>
ke perintah cmake.
Semuanya siap berangkat!
Jika Anda hanya ingin memberikan tes cepat pada proyek tersebut, semuanya disediakan untuk menggunakannya dengan buruh pelabuhan. Untuk melakukannya, buat Dockerfile dari direktori saat ini menggunakan skrip di <path_to_easy_jit_src>/misc/docker
, lalu buat instance buruh pelabuhan Anda.
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
Karena pustaka Easy::Jit bergantung pada bantuan dari kompiler, maka wajib memuat plugin kompiler agar dapat menggunakannya. Bendera -Xclang -load -Xclang <path_to_easy_jit_build>/bin/EasyJitPass.so
memuat plugin.
Header yang disertakan memerlukan dukungan C++14, dan ingatlah untuk menambahkan direktori include! Gunakan --std=c++14 -I<path_to_easy_jit_src>/cpplib/include
.
Terakhir, biner harus ditautkan dengan pustaka runtime Easy::Jit, menggunakan -L<path_to_easy_jit_build>/bin -lEasyJitRuntime
.
Secara keseluruhan kita mendapatkan perintah di bawah ini.
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
Pertimbangkan kode di bawah ini dari perangkat lunak yang menerapkan filter gambar pada aliran video. Pada bagian berikut kita akan mengadaptasinya untuk menggunakan perpustakaan Easy::jit. Fungsi untuk mengoptimalkannya adalah kernel
, yang menerapkan mask pada seluruh gambar.
Topeng, dimensi dan luasnya tidak sering berubah, jadi mengkhususkan fungsi untuk parameter ini tampaknya masuk akal. Selain itu, dimensi gambar dan jumlah saluran biasanya tetap konstan selama keseluruhan eksekusi; namun, nilainya tidak mungkin diketahui karena bergantung pada aliran sungai.
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 ());
}
Header utama perpustakaan adalah easy/jit.h
, di mana satu-satunya fungsi inti perpustakaan diekspor. Fungsi ini disebut -- coba tebak? -- easy::jit
. Kami menambahkan arahan penyertaan yang sesuai di bagian atas file.
# include < easy/jit.h >
Dengan panggilan ke easy::jit
, kami mengkhususkan fungsi dan mendapatkan fungsi baru yang hanya mengambil dua parameter (bingkai masukan dan keluaran).
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 ));
}
Easy::jit menyematkan representasi bitcode LLVM dari fungsi-fungsi yang dikhususkan saat runtime dalam kode biner. Untuk melakukan hal ini, perpustakaan memerlukan akses ke implementasi fungsi-fungsi ini. Easy::jit melakukan upaya untuk menyimpulkan fungsi mana yang dikhususkan pada waktu proses, namun dalam banyak kasus hal ini tidak memungkinkan.
Dalam hal ini, dimungkinkan untuk menggunakan makro EASY_JIT_EXPOSE
, seperti yang ditunjukkan pada kode berikut,
void EASY_JIT_EXPOSE kernel () { /* ... */ }
atau menggunakan ekspresi reguler selama kompilasi. Perintah di bawah ini mengekspor semua fungsi yang namanya dimulai dengan "^kernel".
clang++ ... -mllvm -easy-export= " ^kernel.* " ...
Sejalan dengan header easy/jit.h
, terdapat easy/code_cache.h
yang menyediakan cache kode untuk menghindari kompilasi ulang fungsi yang telah dibuat.
Di bawah ini kami menampilkan kode dari bagian sebelumnya, tetapi diadaptasi untuk menggunakan cache kode.
# 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 ));
}
Lihat file LICENSE
di direktori tingkat atas proyek ini.
Terima kasih khusus kepada Quarkslab atas dukungan mereka dalam mengerjakan proyek pribadi.
Serge Guelton (serge_sans_paille)
Juan Manuel Martinez Caamaño (jmmartinez)
Kavon Farvardin (kavon) penulis atJIT