Compiler Interrupts are instrumentation-based and light-weight, allowing frequent interrupts with little performance impact. Compiler Interrupts instead enable efficient, automatic high-rate polling on a shared thread, which performs other work between polls.
This repository contains source code for Compiler Interrupts framework, its C API, examples and benchmarks. Check out the white paper for more info.
Rust API is available. cargo-compiler-interrupts
subcommand is also available for enabling seamless Compiler Interrupts integration to any Rust packages.
- LLVM 9 or later is required. You can check the LLVM version by running
llvm-config --version
. - Linux system is required for running the benchmarks.
cd src
make
cd ../lib # compiled artifacts are exported to `lib` directory
Compiler Interrupts framework (CompilerInterrupt.so
) and its C API library (libci.a
and libci.so
) are exported to the lib
directory.
- Build and run the example:
cd example
make
./orig_demo # original binary
./ci_llvm_demo # CI-integrated binary
./ci_profiler # check the median interval in cycles for a configured IR interval
./ci_mult_files # compiled using multiple source files
./ci_modularity_demo # compiled using a CI-instrumented library
./test.sh # runs some basic test cases and checks if the output is as expected
orig_demo
is the original, unmodified binary. It simply spawns multiple threads to print out a thread-local counter. Check out thedemo.c
source code for more info.ci_llvm_demo
is the same asorig_demo
, except that it has been integrated with Compiler Interrupts. You should expect to see a lot ofCI: last interval = {} IR
besides ordinary counter prints. These CI prints are frominterrupt_handler
function, which is called by the Compiler Interrupts every 1000 instructions.ci_profiler
is a program meant to understand the IR instruction to cycles relation for a specific program. You can run it with different IR intervals and check the corresponding median cycle intervals achieved.ci_mult_files
andci_modularity_demo
demonstrate the modularity and flexibility when integrating the Compiler Interrupts for your program. Check out theMakefile
for more info.test.sh
is a basic test case that verifies the output ofci_llvm_demo
#include "ci_lib.h"
void interrupt_handler(long ic) {
static __thread long previous_ic = 0;
printf("CI: last interval = %ld IR\n", ic - previous_ic);
previous_ic = ic;
}
int main() {
register_ci(1000, 1000, interrupt_handler);
// your code
}
- Define a new function to handle Compiler Interrupts. The function should take one
long
integer as the parameter. Cumulative instruction count is provided through that parameter. - Call
register_ci
with an IR interval, cycles interval and the just-defined handler. - All Compiler Interrupts APIs are thread-specific, meaning other threads would not be interrupted if you register the handler in the main thread and vice versa. Check out the API documentation below.
CI_ROOT=$(pwd) # assume we are in the root folder of the repository
gcc -S -emit-llvm -I$(CI_ROOT)/src main.c -L$(CI_ROOT)/lib -Wl,-rpath,$(CI_ROOT)/lib -o main.ll -lci # 1
opt -S -postdomtree -mem2reg -indvars -loop-simplify -branch-prob -scalar-evolution < main.ll > opt_main.ll # 2
opt -S -load CompilerInterrupt.so -logicalclock -inst-gran=2 -commit-intv=100 -all-dev=100 < opt_main.ll > ci_main.ll # 3
gcc ci_main.ll -o ci_main # 4
- Link the API library and emit the LLVM IR from your code.
- Run
opt
with given built-in pass for overhead optimization. - Run
opt
with the Compiler Interrupts framework.-logicalclock
must be provided, followed by the arguments for the framework. - Compile the LLVM IR generated from
opt
. You will now have the binary with Compiler Interrupts integrated.
Compiler Interrupts C API are defined in src/ci_lib.h
. All APIs are thread-specific, meaning other threads would not be interrupted if you register the handler in the main thread and vice versa.
Function | Description |
---|---|
void register_ci(int, int, ci_handler) |
Registers the Compiler Interrupts handler with given IR and cycles interval |
void deregister_ci(void) |
De-registers the Compiler Interrupts handler |
void register_ci_disable_hook(ci_margin_hook) |
Registers a function to be called just before Compiler Interrupts is disabled |
void register_ci_enable_hook(ci_margin_hook) |
Registers a function to be called just after Compiler Interrupts is enabled |
void ci_disable(void) |
Disables Compiler Interrupts |
void ci_enable(void) |
Enables Compiler Interrupts |
void instr_disable(void) |
Disables probe instrumentation |
void instr_enable(void) |
Enables probe instrumentation |
Rust API is also available for Rust programs.
- Compiler Interrupts leverages LLVM's analysis and transformation pass backend. Compiler Interrupts can be configured during the optimization stage.
-logicalclock
must be provided, followed by the arguments for the framework.
cd src
chmod +x ./setup.sh
sudo ./setup.sh
Linux system is required for running the benchmarks. The setup script will change some system settings and create some directories. You should always carefully examine the source code before running anything with sudo
.
- MTCP benchmarks (benchmarks/mtcp).
- Shenango benchmarks (benchmarks/shenango, benchmarks/cpuminer-multi).
- Server delegation benchmarks (benchmarks/server_delegation).
- Accuracy and Overhead benchmarks (benchmarks/accuracy_and_overhead).
Check out the white paper for more info about benchmarks.
For assistance in understanding and/or using the Compiler Interrupts framework, please send an email to nbasu4@uic.edu. All issue reports and pull requests are welcomed and much appreciated.
CompilerInterrupts
is available under the MIT license. See the LICENSE file for more info.