-
Notifications
You must be signed in to change notification settings - Fork 5
Examples
Now that you have FlipIt installed, let's walk though several examples to better understand FlipIt.
- Test Pass
- Sequential
- Matmul
- Countdown
- MPI
- Jacobi
This simplistic example shows the minimum code that needs to be added to enable corruptions via FlipIt.
#include <stdio.h>
#include "FlipIt/corrupt/corrupt.h"
int main(int argc, char** argv)
{
int a = 2, b=2;
int rank = 0;
int seed = 7;
FLIPIT_Init(rank, argc, argv, seed);
printf("Should be corrupted: %d + %d = %d\n", a, b, work(a, b));
FLIPIT_Finalize(NULL);
return 0;
}
Walking though the code we see the inclusion of a header file corrupt.h. This header file defines all API functions in FlipIt. Inside the function main we see calls to FLIPIT_Init and FLIPIT_Finalize. Calls to these functions should bound all execution of code instrumented by FlipIt's compiler pass. Should this not be the case segfaults can occur!
FLIPIT_Init's first argument is the rank of the current process (uses MPI terminology). For all sequential applications this argument can be set to 0. The last argument is a seed number that seed FlipIt's internal random number generator. This value should differ between runs to generate differing sequence of random numbers.
FLIPIT_Finalize's lone argument is the name of the file that it should write the histogram of fault site traversal to.
The function work is corrupted during the compilation process. It is corrupted using the following terminal commands to replace a normal compilation step cc -c work.c -o final.o
$LLVM_BUILD_PATH/bin/clang -g -emit-llvm work.c -c -o work.bc
$LLVM_BUILD_PATH/bin/llvm-link $FLIPIT_PATH/include/FlipIt/corrupt/corrupt.bc work.bc -o crpt_work.bc
$LLVM_BUILD_PATH/bin/opt -load $FLIPIT_PATH/lib/libFlipItPass.so -FlipIt -srcFile "work.c" -singleInj 1 -prob 0.95 -byte -1 -arith 1 -ctrl 0 -ptr 0 -funcList "" crpt_work.bc -o final.bc
$LLVM_BUILD_PATH/bin/clang -g -c final.bc -o final.o
Command 1 compiles the C code to LLVM bitcode.
Command 2 links the resulting bitcode to a bitcode header file declaring FlipIt's corruption functions. Command 3 runs the fault injection compiler pass over the bitcode. In this case we want a single injection (-singleInj 1), a fault probability of (-prob 0.95), the injection can be in any byte of the data type (-byte -1), we want only injections into arithmetic and not control or pointer type instructions (-arith 1 -ctrl 0 -ptr 0), corrupt all functions defined in this file (-funcList ""), bitcode file to transform, and finally the output file name.
Command 4 compiled the instrumented bitcode into the object code we need for linking with other files.
The log file that is generated by command 3 in a binary format. We convert this to an ASCII version using the script binary2ascii.py which is found in $FLIPIT_PATH/scripts and display it to the terminal prompt. In practice, you don't need to convert to ASCII unless you want to see properties for a particular fault site. (Learn more about the log file.)
Finally, we compile main.c where we must include the path to corrupt.h and link to the corruption library -L$FLIPIT_PAHT/lib -lcorrupt when creating the executable.
Running the script ./testPass.sh will generate output similar to
File Name: work.c
Function Name: work
------------------------------------------------------------------------------
#0 Store Value Arith-Fix __NF:0
#1 Store Value Arith-Fix __NF:0
#2 Load Result Arith-Fix /home/aperson40/Desktop/FlipIt/examples/work.c:3
#3 Load Result Arith-Fix /home/aperson40/Desktop/FlipIt/examples/work.c:3
#4 Add Result Arith-Fix /home/aperson40/Desktop/FlipIt/examples/work.c:3
Fault injector seed: 7
/*********************************Start**************************************/
Successfully injected 32-bit Integer Data error!!
Rank: 0
Total # faults injected: 1
Bit position is: 11
Index of the fault site: 0
Fault site probability: 9.500000e-01
Chosen random probability is: 2.664442e-01
Attempts since last injection: 1
/*********************************End**************************************/
Should be corrupted: 2 + 2 = 2052
On execution of FLIPIT_Init the supplied fault injection seed is displayed for purposes of reproducibility. On every injection information about FlipIt's local injection state, fault site location, and injection properties are displayed. This information from several runs can be used for visualization to look for patterns that can show susceptible sections of code. The file line of output shows the corrupted computation of 2 + 2. This sum is off by 2048, which is 2^11 exactly the bit that was flipped from 0 to 1 in the store of the argument to the stack frame for the function.
This examples highlights FlipIt's compiler wrapper flipit-cc to make easy makefile modifications.
The code structure modifications for this example are silimar to that of [Test Pass] (), but introduced a new API routine FLIPIT_SetInjector which turns on (FLIPIT_ON) and off(FLIPIT_OFF) FlipIt's ability to inject faults. We use this feature to calculate the correct result of the matrix matrix multiply for a verification phase at the end. Note with the selected seed this should only corrupt 1 entry when run.
Inside the Makefile shown below we see that we build this program in two different ways. The first was is the verbose way outlined in [Test Pass] (), and the second way uses the flipit-cc compiler script.
CC=gcc
CFLAGS = -g -I$(FLIPIT_PATH)/include
FILIB= -L$(FLIPIT_PATH)/lib -lcorrupt
FIPASS= $(FLIPIT_PATH)/lib/libFlipItPass.so
LFLAGS = $(FILIB)
long: matmul.o main.o
$(CC) -o long matmul.o main.o $(LFLAGS)
matmul.o: matmul.c
$(LLVM_BUILD_PATH)/bin/clang $(CFLAGS) -emit-llvm matmul.c -c -o matmul.bc
$(LLVM_BUILD_PATH)/bin/llvm-link $(FLIPIT_PATH)/include/FlipIt/corrupt/corrupt.bc matmul.bc -o crpt_matmul.bc
$(LLVM_BUILD_PATH)/bin/opt -load $(FIPASS) -FlipIt -srcFile matmul.c -config FlipIt.config -singleInj 1 -prob 1e-8 -byte -1 -arith 1 -ctrl 1 -ptr 1 -funcList "" crpt_matmul.bc -o final.bc
$(LLVM_BUILD_PATH)/bin/clang -c final.bc -o matmul.o
main.o: main.c
$(CC) $(CFLAGS) -o main.o -c main.c
short: _matmul.o _main.o
$(CC) -o short _matmul.o _main.o $(LFLAGS)
_matmul.o: matmul.c
$(FLIPIT_PATH)/scripts/flipit-cc $(CFLAGS) -o _matmul.o -c matmul.c
_main.o: main.c
$(FLIPIT_PATH)/scripts/flipit-cc $(CFLAGS) -o _main.o -c main.c
Running both executables long and short produce the same results, but the amount of modification to the Makefile is much reduced by using flipit-cc. In fact, flipit-cc can be used to compile every file in the program as it uses two configuration files to determine what functions to inject into.
The configuration file matmul.config is used by the compiler pass itself to set instruction probabilities and function weights. In this configuration file the # character denotes a comment and that line will be ignored. Lines such as FLIPIT_Init=0 denote that these functions will not be instrumented for injection. By default all FlipIt routines and function main will not be instrumented.
The configuration file config.py is used by flipit-cc and sets all the compiler pass parameters and key variables required for successful compilation. These key variables include
-
SHOW- series of libraries and paths that your particular compiler wraps, e.g.mpiccis a wrapper that includes several libraries including MPI (mpicc-show ormpicc -showmereveals the full command) -
notInject- is a python list of file names that contain no functions to instrument. This speeds up compilation by outright rejecting the file for instrumentation instead of testing every function contained inside. -
cc- the compiler that you would normally use to compile the program -
verbose- toggles the display of each of the 5 commands required to generate the object file (useful for debugging)
When matmul.c is compiled by either method, matmul.c.LLVM.txt is generated. This is a log file that is used by the analysis software to generate and visualize statistics based on fault injection runs. For more information about this see the Analysis wiki page.
This example's code is exactly that of Matmul with the exception of
FLIPIT_CountdownTimer(125);
This routine instructs FlipIt to forgo the calculation of probabilities at each fault site and instead decrement a counter counting down until an injection. In this case, we iterate over 125 fault sites before we make an injection. If the code is compiled with -singleInj 1, this will be the only injection, but if it is compiled with -singleInj 0, then there will be an injection every 125 fault sites for the duration of the program while FlipIt's state is set to FLIPIT_ON.
This examples highlights how to use FlipIt for MPI applications. For this example to compile please modify config.py appropriately. The modifications to the main function are similar to the sequential examples with the exception that the MPI rank of each process is passed to FLIPIT_Init. Note that the seeds are the same. They are internally modified by FlipIt to generate different random numbers on each rank.
Inside the Makefile we see two testing options test-selection and test-all. The latter has all MPI ranks faulty and can suffer 4 injection during the programs execution. test-selection uses FlipIt's command line arguments to say there is going to be one MPI rank generating faults --numberFaulty 1 and that MPI rank is 3 --faulty 3. The following command allows injections on MPI ranks 1 and 2 --numberFaulty 2 --faulty 1 2. Currently --numberFaulty must appear before --faulty.
At this point you should have a working understanding of how to add FlipIt to your code for fault injection. In order to make meaningful statements with fault injection, you require numerous fault injection trials. Our analysis software will aid in understanding what happens to your code when faults are injected. A brief tutorial of how to use the analysis software can be found here.