├── FlipIt.config ├── LICENSE.TXT ├── README.md ├── examples ├── mpi │ ├── jacobi │ │ ├── Makefile │ │ ├── config.py │ │ ├── jacobi.c │ │ ├── jacobi.config │ │ ├── jacobi.h │ │ └── main.c │ └── visualization │ │ ├── Makefile │ │ ├── README.txt │ │ ├── analysis │ │ ├── README │ │ ├── analysis_config.py │ │ ├── binaryParser.py │ │ ├── custom.py │ │ ├── database.py │ │ ├── main.py │ │ ├── migrate.py │ │ └── visualize.py │ │ ├── config.py │ │ ├── jacobi.c │ │ ├── jacobi.config │ │ ├── jacobi.h │ │ ├── main.c │ │ └── run.sh ├── pass │ ├── Foo │ │ ├── Makefile │ │ ├── createPass.sh │ │ ├── foo.cpp │ │ ├── foo.h │ │ ├── main.c │ │ └── test.sh │ └── setupPassExample.sh ├── seq │ ├── countdown │ │ ├── Makefile │ │ ├── config.py │ │ ├── main.c │ │ ├── matmul.c │ │ ├── matmul.h │ │ └── matmul_countdown.config │ └── matmul │ │ ├── Makefile │ │ ├── config.py │ │ ├── main.c │ │ ├── matmul.c │ │ ├── matmul.config │ │ └── matmul.h └── testPass.sh ├── scripts ├── analysis │ ├── README │ ├── analysis_config.py │ ├── binaryParser.py │ ├── custom.py │ ├── database.py │ ├── main.py │ ├── migrate.py │ └── visualize.py ├── binary2ascii.py ├── config.py ├── createPass.sh ├── findLLVMHeaders.py ├── flipit-cc ├── genBC.py ├── library.sh └── resetFaultIndex.sh ├── setup.sh └── src ├── corrupt ├── corrupt.c └── corrupt.h └── pass ├── Logger.h ├── Makefile ├── Makefile-Lib ├── faults.cpp └── faults.h /FlipIt.config: -------------------------------------------------------------------------------- 1 | INSTRUCTIONS: 2 | #add=1e-8 3 | #fadd=1e-8 4 | #sub=1e-8 5 | #fsub=1e-8 6 | #mul=1e-8 7 | #fmul=1e-8 8 | #udiv=1e-8 9 | #sdiv=1e-8 10 | #fdiv=1e-8 11 | #urem=1e-8 12 | #srem=1e-8 13 | #frem=1e-8 14 | #shl=1e-8 15 | #lshr=1e-8 16 | #ashr=1e-8 17 | #and=1e-8 18 | #or=1e-8 19 | #xor=1e-8 20 | #alloca=1e-8 21 | #load=1e-8 22 | #store=1e-8 23 | #getelementptr=1e-8 24 | #icmp=1e-8 25 | #fcmp=1e-8 26 | #call=1e-8 27 | FUNCTIONS: 28 | FLIPIT_Init=0 29 | FLIPIT_Finalize=0 30 | FLIPIT_SetInjector=0 31 | FLIPIT_SetRankInject=0 32 | FLIPIT_SetFaultProbability=0 33 | FLIPIT_SetCustomLogger=0 34 | global constructors keyed to a=0 35 | 36 | -------------------------------------------------------------------------------- /LICENSE.TXT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 University of Illinois at Urbana-Champaign 2 | All rights reserved. 3 | 4 | Developed by: Scientific Computing Group 5 | University of Illinois at Urbana-Champaign 6 | http://scicomp.cs.illinois.edu/ 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. 13 | 14 | * Neither the names of , nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FlipIt 2 | ====== 3 | 4 | FlipIt: An LLVM Based Fault Injector for HPC 5 | 6 | To cite: 7 | ``` 8 | @inproceedings{DBLP:conf/europar/CalhounOS14, 9 | author = {Jon Calhoun and Luke Olson and Marc Snir}, 10 | title = {FlipIt: An {LLVM} Based Fault Injector for {HPC}}, 11 | booktitle = {Euro-Par 2014: Parallel Processing Workshops - Euro-Par 2014 International Workshops, Porto, Portugal, August 25-26, 2014, Revised Selected Papers, Part {I}}, 12 | pages = {547--558}, 13 | year = {2014}, 14 | crossref = {DBLP:conf/europar/2014w1}, 15 | url = {http://dx.doi.org/10.1007/978-3-319-14325-5_47}, 16 | doi = {10.1007/978-3-319-14325-5_47}, 17 | timestamp = {Sun, 14 Dec 2014 18:38:30 +0100}, 18 | biburl = {http://dblp.uni-trier.de/rec/bib/conf/europar/CalhounOS14}, 19 | bibsource = {dblp computer science bibliography, http://dblp.org} 20 | } 21 | ``` 22 | This project is partially supported by the Air Force Office of Scientific Research under grant FA9550-12-1-0478. 23 | 24 | 25 | # FlipIt Installation 26 | 27 | 1.) Obtain a copy of LLVM and clang [here](http://llvm.org/releases/download.html). We have tested with LLVM 3.5.2 source and precompiled binaries. If you choose to build LLVM and clang from source, follow these [directions](http://clang.llvm.org/get_started.html). 28 | 29 | 2.) Get FlipIt: 30 | 31 | ``` 32 | git clone git@github.com:FTHPC/FlipIt.git 33 | ``` 34 | 35 | 3.) Modify your bashrc file to add directory to path and set some environment variables that are used throughout FlipIt 36 | ``` 37 | export LLVM_BUILD_PATH=/path/to/llvm/ 38 | export FLIPIT_PATH=/path/to/flipit 39 | 40 | #only required if you want to use FlipIt as a library with other code 41 | export LD_LIBRARY_PATH=/path/to/flipit/lib:$LD_LIBRARY_PATH 42 | 43 | #not required, but can make your fingers happy in you do not use the compiler wrapper 44 | PATH=$PATH:/path/to/llvm/bin 45 | export PATH 46 | ``` 47 | 48 | 4.) Run script to setup FlipIt with LLVM (Note: If you're not using LLVM version 3.4, the LLVM #include files in [faults.h](src/pass/faults.cpp) might not be correct. This is due to changes in the directory structure in LLVM between releases.): 49 | 50 | ``` 51 | cd $FLIPIT_PATH 52 | ./setup.sh 53 | ``` 54 | 5.) Test that everything works: 55 | 56 | 57 | ``` 58 | cd $FLIPIT_PATH/examples 59 | ./testPass.sh 60 | ``` 61 | 62 | If all worked correctly, 2 + 2 is not 4. If not, check out the [Examples](https://github.com/FTHPC/FlipIt/wiki/Examples) wiki page for suggested solutions. 63 | 64 | Detailed walk though of the FlipIt [examples](https://github.com/FTHPC/FlipIt/wiki/Examples). 65 | 66 | ------------------------------ 67 | FlipIt is licensed under the University of Illinois/NCSA Open Source License. See [LICENSE.TXT](LICENSE.TXT) for details. 68 | -------------------------------------------------------------------------------- /examples/mpi/jacobi/Makefile: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | # 3 | # This example shows how to used command line arguments to inject 4 | # on a single rank. In addition, we use a custom config file located 5 | # in this directoy "flipit/examples/mpi/jacobi/config.py" to change 6 | # the default parameters for the compiler pass. 7 | # 8 | ##################################################################### 9 | CC=$(FLIPIT_PATH)/scripts/flipit-cc 10 | CFLAGS = -c -g 11 | 12 | FILIB = -L$(FLIPIT_PATH)/lib -lcorrupt 13 | LFLAGS = $(FILIB) -lm 14 | 15 | jacobi: jacobi.o main.o 16 | mpicc -o jacobi jacobi.o main.o $(LFLAGS) 17 | 18 | jacobi.o: jacobi.c 19 | $(CC) $(CFLAGS) -o jacobi.o jacobi.c 20 | 21 | main.o: main.c 22 | $(CC) $(CFLAGS) -o main.o main.c 23 | 24 | clean: 25 | rm -f *.bc 26 | rm -f *.LLVM.bin 27 | rm -f *.o 28 | rm -f *.pyc 29 | rm -f jacobi 30 | 31 | test-selection: 32 | mpirun -n 4 ./jacobi --numberFaulty 1 --faulty 3 33 | 34 | test-all: 35 | mpirun -n 4 ./jacobi 36 | -------------------------------------------------------------------------------- /examples/mpi/jacobi/config.py: -------------------------------------------------------------------------------- 1 | ############### Injector Parameters ################## 2 | # 3 | # config - config file used by the compiler pass 4 | # funcList - list of functions that are faulty 5 | # prob - probability that instuction is faulty 6 | # byte - which byte is faulty (0-7) -1 random 7 | # singleInj - one injection per active rank (0 or 1) 8 | # ptr - add code to inject into pointers (0 or 1) 9 | # arith - add code to inject into mathematics (0 or 1) 10 | # ctrl - add code to inject into control (0 or 1) 11 | # stateFile - unique counter for fault site index; 12 | # should differ based on application 13 | # 14 | ##################################################### 15 | 16 | config = "jacobi.config" 17 | funcList = "\"\"" 18 | prob = 1e-5 19 | byte = -1 20 | bit = -1 21 | ptr = 1 22 | arith = 1 23 | ctrl = 1 24 | stateFile = "jacobi" 25 | 26 | ############# Library Parameters ##################### 27 | # 28 | # FLIPIT_PATH - Path to FlipIt repo 29 | # SHOW - libraries and path wraped by mpicc 30 | # 31 | ##################################################### 32 | import os 33 | FLIPIT_PATH = os.environ['FLIPIT_PATH'] 34 | LLVM_BUILD_PATH = os.environ['LLVM_BUILD_PATH'] 35 | SHOW = " " # TODO: set with include and library paths from mpicc -show; or mpicc -showme 36 | CPP_LIB = " " # not needed for this example (C program) 37 | 38 | 39 | ########### Files to NOT inject inside ############### 40 | notInject = [" ", " "] 41 | 42 | ############ Default Compiler ################# 43 | cc = "mpicc" 44 | 45 | ############ Verbose compiler output ############## 46 | verbose = False 47 | 48 | ############ Generate a histogram of fault site traversals ######### 49 | histogram = False 50 | -------------------------------------------------------------------------------- /examples/mpi/jacobi/jacobi.c: -------------------------------------------------------------------------------- 1 | #include "jacobi.h" 2 | 3 | void jacobi(int rank) 4 | { 5 | int value, size, errcnt, toterr, i, j, itcnt; 6 | int i_first, i_last; 7 | MPI_Status status; 8 | double diffnorm, gdiffnorm; 9 | double xlocal[(12/4)+2][12]; 10 | double xnew[(12/3)+2][12]; 11 | 12 | MPI_Comm_size( MPI_COMM_WORLD, &size ); 13 | 14 | if (size != 4) MPI_Abort( MPI_COMM_WORLD, 1 ); 15 | 16 | /* xlocal[][0] is lower ghostpoints, xlocal[][maxn+2] is upper */ 17 | 18 | /* Note that top and bottom processes have one less row of interior 19 | points */ 20 | i_first = 1; 21 | i_last = maxn/size; 22 | if (rank == 0) i_first++; 23 | if (rank == size - 1) i_last--; 24 | 25 | /* Fill the data as specified */ 26 | for (i=1; i<=maxn/size; i++) 27 | for (j=0; j 0) 42 | MPI_Recv( xlocal[0], maxn, MPI_DOUBLE, rank - 1, 0, 43 | MPI_COMM_WORLD, &status ); 44 | /* Send down unless I'm at the bottom */ 45 | if (rank > 0) 46 | MPI_Send( xlocal[1], maxn, MPI_DOUBLE, rank - 1, 1, 47 | MPI_COMM_WORLD ); 48 | if (rank < size - 1) 49 | MPI_Recv( xlocal[maxn/size+1], maxn, MPI_DOUBLE, rank + 1, 1, 50 | MPI_COMM_WORLD, &status ); 51 | 52 | /* Compute new values (but not on boundary) */ 53 | itcnt ++; 54 | diffnorm = 0.0; 55 | for (i=i_first; i<=i_last; i++) 56 | for (j=1; j 1.0e-8 && itcnt < 1000); 73 | } -------------------------------------------------------------------------------- /examples/mpi/jacobi/jacobi.config: -------------------------------------------------------------------------------- 1 | INSTRUCTIONS: 2 | #add=1e-8 3 | #fadd=1e-8 4 | #sub=1e-8 5 | #fsub=1e-8 6 | #mul=1e-8 7 | #fmul=1e-8 8 | #udiv=1e-8 9 | #sdiv=1e-8 10 | #fdiv=1e-8 11 | #urem=1e-8 12 | #srem=1e-8 13 | #frem=1e-8 14 | #shl=1e-8 15 | #lshr=1e-8 16 | #ashr=1e-8 17 | #and=1e-8 18 | #or=1e-8 19 | #xor=1e-8 20 | #alloca=1e-8 21 | #load=1e-8 22 | #store=1e-8 23 | #getelementptr=1e-8 24 | #icmp=1e-8 25 | #fcmp=1e-8 26 | #call=1e-8 27 | FUNCTIONS: 28 | FLIPIT_Init=0 29 | FLIPIT_Finalize=0 30 | FLIPIT_SetInjector=0 31 | FLIPIT_SetRankInject=0 32 | FLIPIT_SetFaultProbability=0 33 | FLIPIT_SetCustomLogger=0 34 | 35 | -------------------------------------------------------------------------------- /examples/mpi/jacobi/jacobi.h: -------------------------------------------------------------------------------- 1 | #ifndef JACOBI_H 2 | #define JACOBI_H 3 | 4 | #include 5 | #include 6 | #include 7 | #define maxn 12 8 | void jacobi(int rank); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /examples/mpi/jacobi/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "jacobi.h" 5 | #include "FlipIt/corrupt/corrupt.h" 6 | 7 | /* This example handles a 12 x 12 mesh, on 4 processors only. */ 8 | 9 | 10 | int main(int argc, char** argv) 11 | { 12 | int rank; 13 | int seed = 233; 14 | MPI_Init(&argc, &argv); 15 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); 16 | 17 | FLIPIT_Init(rank, argc, argv, seed); 18 | jacobi(rank); 19 | FLIPIT_Finalize(NULL); 20 | 21 | MPI_Finalize(); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /examples/mpi/visualization/Makefile: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | # 3 | # This example shows how to used command line arguments to inject 4 | # on a single rank. In addition, we use a custom config file located 5 | # in this directoy "flipit/examples/mpi/jacobi/config.py" to change 6 | # the default parameters for the compiler pass. 7 | # 8 | ##################################################################### 9 | CC=$(FLIPIT_PATH)/scripts/flipit-cc 10 | CFLAGS = -c -g 11 | 12 | FILIB = -L$(FLIPIT_PATH)/lib -lcorrupt 13 | LFLAGS = $(FILIB) -lm 14 | 15 | jacobi: jacobi.o main.o 16 | mpicc -o jacobi jacobi.o main.o $(LFLAGS) 17 | 18 | jacobi.o: jacobi.c 19 | $(CC) $(CFLAGS) -o jacobi.o jacobi.c 20 | 21 | main.o: main.c 22 | $(CC) $(CFLAGS) -o main.o main.c 23 | 24 | clean: 25 | rm -f *.bc 26 | rm -f *.LLVM.bin 27 | rm -f *.o 28 | rm -f *.pyc 29 | rm -f jacobi 30 | 31 | test-selection: 32 | mpirun -n 4 ./jacobi --numberFaulty 1 --faulty 3 33 | 34 | test-all: 35 | mpirun -n 4 ./jacobi 36 | -------------------------------------------------------------------------------- /examples/mpi/visualization/README.txt: -------------------------------------------------------------------------------- 1 | This example demonstrates how to use the visualization scripts found in 2 | `$FLIPIT_PATH/scripts/analysis` on the Jacobi example. Before we visualize 3 | anything we first need to run the application compiled with FlipIt several 4 | times to get significant enough data. Here we only run the application 25 5 | times which is not sufficient for publication quality results, but is sufficient 6 | to demonstrate how to utilize the analysis scripts. 7 | 8 | ```bash 9 | #compile the application 10 | make 11 | 12 | #make a directory for the run output and run jacobi 25 times 13 | mkdir run_data 14 | for $i in [0..25] 15 | do 16 | #in a real run we would want to set the faulty rank a random 17 | mpirun -n 4 ./jacobi --numberFaulty 1 --faulty 3 1&2> run_$i.txt 18 | enddo 19 | ``` 20 | 21 | Now that we have run data, we are able to visualize. We recommend that 22 | you copy analysis scripts into your project's directory as we will be modifying 23 | several files. 24 | 25 | ```bash 26 | cp -r $FLIPIT_PATH/scripts/analysis . 27 | ``` 28 | 29 | The file `analysis_config.py` has several variables that need to be set 30 | to correctly visualize the fault injection campaign. 31 | 32 | 33 | * LLVM_log_path 34 | * trial_path 35 | * trial_prefix 36 | * srcPath 37 | * numTrials 38 | * more_detail_funcs 39 | * busError 40 | * assertMessage 41 | * segError 42 | * detectMessage 43 | 44 | Once these are set, we can visualize the campaign 45 | 46 | ```bash 47 | python main.py 48 | ``` 49 | 50 | 51 | FlipIt's analysis scripts allow the graphing of user logged data. 52 | 53 | ```bash 54 | mkdir run_data_custom 55 | for $i in [0..25] 56 | do 57 | #in a real run we would want to set the faulty rank a random 58 | mpirun -n 4 ./jacobi-custom --numberFaulty 1 --faulty 3 1&2> run_$i.txt 59 | enddo 60 | ``` 61 | 62 | If we look at the difference bettwen the two programs, we see the addition of the following code: 63 | 64 | ```c 65 | int ITER 66 | ``` 67 | -------------------------------------------------------------------------------- /examples/mpi/visualization/analysis/README: -------------------------------------------------------------------------------- 1 | Information 2 | ----------- 3 | 4 | Basic analysis scripts that combine injection site, source code, and runtime 5 | injection information to generate graphs about the fault injection campaign. 6 | The scripts read the compiler log files and run output files to store key 7 | information into a database that is used when visualizing the fault injection 8 | campaign. 9 | 10 | Such graphs include: 11 | - Classification of injections based on instruction type 12 | - Percent of injections based on function (includes type information 13 | - Signals generated 14 | - Trials with detection (includes bit locations and types) 15 | - Latency of detection 16 | - Trials that unexpectedly terminate (includes bit locations and types) 17 | 18 | The scripts are extensible with user defined functions placed in 'custom.py'. 19 | The user can collect information from the run output files being parsed, 20 | e.g. application progress, SDC detector performance, by extending the 21 | database's tables or creating their own, and visualize their data, or 22 | combine data that is already collected into new visualizations. 23 | 24 | 25 | 26 | 27 | Usage 28 | ----- 29 | 30 | These scripts depend on 'numpy', 'matplotlib', and 'sqlite3'. 31 | 32 | To use these scripts: 33 | 34 | 1.) modify 'analysis_config.py' 35 | 2.) python 'main.py' 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /examples/mpi/visualization/analysis/analysis_config.py: -------------------------------------------------------------------------------- 1 | """Name of the database file on disk to visualize, or if it does not exist 2 | create it and populate with injection information 3 | """ 4 | database = "campaign.db" 5 | 6 | """Boolean that specifies if we should rebuild the database on each execution 7 | """ 8 | rebuild_database = True 9 | 10 | """Path to where the LLVM log files, (*.LLVM.bin), generated by FlipIt exist. 11 | 12 | Notes 13 | ---- 14 | analysis scripts recursilvely search this directory for the logs 15 | """ 16 | LLVM_log_path = "../" 17 | 18 | """Determines what type of log files to look for and parse. 19 | 20 | Notes 21 | ---- 22 | Options are "Binary" or "ASCII" 23 | """ 24 | LLVM_log_type = "Binary" 25 | 26 | """Path to where the output files of the run(s) are stored. Each output file 27 | should a seperate fault injection run of the application. 28 | 29 | Notes 30 | ----- 31 | 1) assumes files from a fault injection campaign end in _# or _#.txt 32 | where # is the trial number e.g. foo_1 or foo_1.txt 33 | 2) stdout and stderr are in the same file 34 | 35 | See Also 36 | -------- 37 | migrate.py to suffix _# or _#.txt to existing run output files 38 | """ 39 | trial_path = "../run_data" 40 | 41 | """Begining of the trial file name e.g. foo for trials foo_1 or foo_1.txt 42 | """ 43 | trial_prefix = "run" 44 | 45 | """Path to source code. 46 | 47 | Notes 48 | ----- 49 | assumes stdout and stderr are in the same file 50 | """ 51 | srcPath = "../" 52 | 53 | """Number of fault injection trials to read 54 | """ 55 | numTrials = 25. 56 | 57 | """Names of functions that a more detailed analysis should be conducted for 58 | 59 | Notes 60 | ----- 61 | A more detailed analysis includes color coding source code based on 62 | injection frequency 63 | """ 64 | more_detail_funcs = ["jacobi"] 65 | 66 | """Snipits of system generated messages. These SHOULD be changed based on 67 | your system 68 | """ 69 | busError = "exit signal Bus error" 70 | assertMessage = "Assertion" 71 | segError = "Sig 11" 72 | 73 | """Snipit of a detection message. This SHOULD be changed based on your 74 | detection scheme 75 | """ 76 | detectMessage = "Foo Check" 77 | 78 | """FlipIt Injection markers. You SHOULD NOT need to change these. 79 | """ 80 | bitMessage = "Bit position" 81 | siteMessage = "/*********************************Start**************************************/" 82 | siteEndMessage = "/*********************************End**************************************/" 83 | -------------------------------------------------------------------------------- /examples/mpi/visualization/analysis/binaryParser.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | NEW_FILE_MASK = 0x8000 4 | currSize = 0 5 | def unpack(binary, fmt, size = None): 6 | """Reads a value from a binary file 'binary'. 7 | Parameters 8 | ---------- 9 | binary : open binary file 10 | open binary file to read from 11 | fmt : single character 12 | format code for the data type to read from the binary file 13 | size : int 14 | used when reading strings from the binary file as the size of the 15 | string that should be read 16 | """ 17 | 18 | global currSize 19 | value = None 20 | 21 | if fmt == 'B': 22 | #print len(binary) 23 | #print "reading byte[", currSize, "] = ", binary[currSize] 24 | #tmplue = struct.unpack(fmt, binary[currSize])[0] 25 | value = struct.unpack(fmt, binary[currSize])[0] 26 | #value = struct.unpack(fmt, binary[currSize])[0] 27 | currSize += 1 28 | elif fmt == 'H': 29 | value = struct.unpack(fmt, binary[currSize:currSize+2])[0] 30 | currSize += 2 31 | elif fmt == 'L': 32 | value = struct.unpack(fmt, binary[currSize:currSize+8])[0] 33 | currSize += 8 34 | elif fmt == 's': 35 | value = binary[currSize:currSize + size] 36 | currSize += size 37 | 38 | return value 39 | 40 | 41 | class INJ_TYPE: 42 | ARITHMETIC_FP = 0 43 | POINTER = 1 44 | ARITHMETIC_FIX = 2 45 | CONTROL_LOOP = 3 46 | CONTROL_BRANCH = 4 47 | UNKNOWN_INJ = 5 48 | 49 | 50 | class INJ_INFO_TYPE: 51 | RESULT = 0 52 | VALUE = RESULT 53 | ADDRESS = 1 54 | UNKNOWN_INJ_TYPE = 30 55 | 56 | class INST_TYPE: 57 | Unknown = 0 58 | 59 | # Terminator Instructions 60 | Ret = 1 61 | Br = 2 62 | Switch = 3 63 | IndirectBr = 4 64 | Invoke = 5 65 | Resume = 6 66 | Unreachable = 7 67 | 68 | # Standard binary operators... 69 | Add = 8 70 | FAdd = 9 71 | Sub = 10 72 | FSub = 11 73 | Mul = 12 74 | FMul = 13 75 | UDiv = 14 76 | SDiv = 15 77 | FDiv = 16 78 | URem = 17 79 | SRem = 18 80 | FRem = 19 81 | 82 | # Logical operators... 83 | Shl = 20 84 | LShr = 21 85 | Ashr = 22 86 | And = 23 87 | Or = 24 88 | Xor = 25 89 | 90 | #Memory operators... 91 | Alloca = 26 92 | Load = 27 93 | Store = 28 94 | GetElementPtr = 29 95 | Fence = 30 96 | AtomicCmpXchg = 31 97 | AtomicRMW = 32 98 | 99 | # Cast operators ... 100 | Truc = 33 101 | ZExt = 34 102 | SExt = 35 103 | FPToUI = 36 104 | FPToSI = 37 105 | UIToFP = 38 106 | SIToFP = 39 107 | FPTrunc = 40 108 | FPExt = 41 109 | PtrToInt = 42 110 | IntToPtr = 43 111 | BitCast = 44 112 | AddrSpaceCast = 45 113 | 114 | # Other operators... 115 | ICmp = 46 116 | FCmp = 47 117 | PHI = 48 118 | Call = 49 119 | Select = 50 120 | UserOp1 = 51 121 | UserOp2 = 52 122 | VAArg = 53 123 | ExtractElement = 54 124 | InsertElement = 55 125 | ShuffleVector = 56 126 | ExtractValue = 57 127 | InsertValue = 58 128 | LandingPad = 59 129 | 130 | INST_STR = ["Unknown", "Ret", "Br", "Switch", "IndirectBr", "Invoke", "Resume",\ 131 | "Unreachable", "Add", "FAdd", "Sub", "FSub", "Mul", "FMul", "UDiv", "SDiv",\ 132 | "FDiv", "URem", "SRem", "FRem", "Shl", "LShr", "Ashr", "And", "Or", "Xor", \ 133 | "Alloca", "Load", "Store", "GetElementPtr", "Fence", "AtomicCmpXchg", \ 134 | "AtomicRMW", "Truc", "ZExt", "SExt", "FPToUI", "FPToSI", "UIToFP", "SIToFP",\ 135 | "FPTrunc", "FPExt", "PtrToInt", "IntToPtr", "BitCast", "AddrSpaceCast", \ 136 | "ICmp", "FCmp", "PHI", "Call", "Select", "UserOp1", "UserOp2", "VAArg", \ 137 | "ExtractElement", "InsertElement", "ShuffleVector", "ExtractValue", \ 138 | "InsertValue", "LandingPad"] 139 | 140 | 141 | def info2Str(info, opstr): 142 | """Converts injection site info encoded as an integer into an ASCII string. 143 | Parameters 144 | ---------- 145 | info : int 146 | injection type incoded as an integer to express as a string 147 | opstr : string 148 | opcode string from the same fault site that 'info' comes from, and is 149 | used to better specify the injection 150 | """ 151 | 152 | if info == INJ_INFO_TYPE.RESULT: 153 | if opstr == "Store": 154 | return "Value" 155 | else: 156 | return "Result" 157 | elif info == INJ_INFO_TYPE.UNKNOWN_INJ_TYPE: 158 | return "Unknown" 159 | else: 160 | return "Arg " + str(info-1) 161 | 162 | 163 | def type2Str(ty): 164 | """Converts an injection type encoded as an integer into an ASCII string. 165 | Parameters 166 | ---------- 167 | ty : int 168 | injection type incoded as an integer to express as a string 169 | """ 170 | 171 | if ty == INJ_TYPE.ARITHMETIC_FP: 172 | return "Arith-FP" 173 | elif ty == INJ_TYPE.POINTER: 174 | return "Pointer" 175 | elif ty == INJ_TYPE.ARITHMETIC_FIX: 176 | return "Arith-Fix" 177 | elif ty == INJ_TYPE.CONTROL_LOOP: 178 | return "Contorl-Loop" 179 | elif ty == INJ_TYPE.CONTROL_BRANCH: 180 | return "Control-Branch" 181 | else: 182 | return "Unknown" 183 | 184 | def opcode2Str(opcode): 185 | """Converts an opcode into an ASCII string. 186 | Parameters 187 | ---------- 188 | opcode : int 189 | opcode to express as a string 190 | """ 191 | 192 | if opcode < len(INST_STR): 193 | return INST_STR[opcode] 194 | else: 195 | return INST_STR[0] 196 | 197 | 198 | def parseBinaryLogFile(c, filename, outfile = None): 199 | """Reads FLipIt LLVM log file and adds fault injection site 200 | information into the database. 201 | Parameters 202 | ---------- 203 | c : object 204 | sqlite3 database handle that is open to a valid filled database 205 | filename : str 206 | absolute name of the LLVM log file 207 | outfile : any 208 | if value is not 'None' then this function will write an ASCII 209 | version of the log file to disk with the name 'filename' but 210 | use the extension .txt 211 | """ 212 | 213 | global currSize 214 | currSize = 0 215 | if outfile != None: 216 | name = outfile 217 | if name == "": 218 | name = filename 219 | if name[-3:] == "bin": 220 | name = name[0:-3] + "txt" 221 | 222 | outfile = open(name, "w") 223 | with open(filename, "rb") as f: 224 | logfile = f.read() 225 | #print logfile 226 | fileVersion = unpack(logfile, 'B') 227 | nameSize = unpack(logfile, 'H') 228 | srcFile = unpack(logfile, 's', nameSize) 229 | siteIdx = 0 230 | funcName = "" 231 | 232 | 233 | if outfile != None: 234 | outfile.write("File Version #: "+ str(fileVersion)) 235 | outfile.write("\nFile Name: " + str(srcFile)) 236 | 237 | # loop over all functions and fault locations 238 | while currSize < len(logfile): # for rest of file 239 | #print "GET OPCODE" 240 | opcode = unpack(logfile, 'B') #read function header 241 | if opcode != 255: 242 | # opcode(1 byte), Types/Info(1 byte [3,5 bits]), Location (2+ bytes) 243 | info_type = unpack(logfile, 'B') 244 | ty = info_type >> 5 245 | info = info_type & 0x1F 246 | lineNum = unpack(logfile, 'H') 247 | comment = info2Str(info, opcode2Str(opcode)) 248 | #print "opcode= ", opcode, " info= ", info, " ty= ", ty, " lineNum= ", lineNum 249 | msg = "\n#" + str(siteIdx) + "\t" + opcode2Str(opcode) + "\t" + info2Str(info, opcode2Str(opcode))\ 250 | + "\t" + type2Str(ty) 251 | 252 | # if the MSB bit in lineNum is set then lineNum is the size of 253 | # a new filename string and we must read a new lineNum 254 | #print "AND=", lineNum & NEW_FILE_MASK 255 | if lineNum & NEW_FILE_MASK != 0: 256 | size = lineNum & 0x7FFF 257 | lineNum = unpack(logfile, 'H', 2) 258 | srcFile = unpack(logfile, 's', size) 259 | #print "size=", size, " new file: ", srcFile, ":", lineNum #unpack(logfile, 's', size & 0x7F) 260 | #else: 261 | # print "old file: ", srcFile, ":", lineNum 262 | msg += "\t" + srcFile + ":" + str(lineNum) 263 | if c != None: 264 | #print msg 265 | c.execute("INSERT INTO sites VALUES (?,?,?,?,?,?,?)", (siteIdx, type2Str(ty), comment, srcFile, funcName, lineNum, opcode)) 266 | if outfile != None: 267 | outfile.write(msg) 268 | siteIdx += 1 269 | else: # start of function 270 | size = unpack(logfile, 'B') 271 | funcName = unpack(logfile, 's', size) 272 | if outfile != None: 273 | #funcName = unpack(logfile, 's', size) 274 | outfile.write("\n\nFunction Name: " + funcName) 275 | outfile.write("\n------------------------------------------------------------------------------") 276 | #print funcName 277 | siteIdx = unpack(logfile, 'L') 278 | #print "Fault Site Idx: ", siteIdx 279 | #print currSize 280 | 281 | if outfile != None: 282 | outfile.write("\n") 283 | outfile.close() 284 | 285 | #parseBinaryLogFile("work.c.LLVM.bin", "OUT.c.LLVM.txt") 286 | #parseBinaryLogFile("/home/aperson40/research/compilerSDC/HPCCG-1.0/ddot.cpp.LLVM.bin", "DD.c.LLVM.txt") 287 | 288 | -------------------------------------------------------------------------------- /examples/mpi/visualization/analysis/custom.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from matplotlib import pyplot as plot 3 | from analysis_config import * 4 | from visualize import * 5 | 6 | def customInit(c): 7 | """User defined function to initialize the fault injection campaign 8 | database. 9 | 10 | Parameters 11 | ---------- 12 | c : object 13 | sqlite3 database handle that is open to a valid filled database 14 | Notes 15 | ---------- 16 | Users will want to use this funcction to extend current tables or 17 | add there own tables to the data. 18 | 19 | Example 20 | ------- 21 | c.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='custom'") 22 | if len(c.fetchall()) == 0: 23 | c.execute("CREATE TABLE custom (trial int, site, iter int, rank int, level int, direction int)") 24 | c.execute("ALTER TABLE trials ADD COLUMN iter int") 25 | c.execute("ALTER TABLE trials ADD COLUMN converged int") 26 | """ 27 | 28 | def customParser(c, line, trial): 29 | """Parses the output of a fault injection trial for items interested to the user 30 | Parameters 31 | ---------- 32 | c : object 33 | sqlite3 database handle that is open to a valid filled database 34 | 35 | line : str 36 | Single line from the output file of a fault injection trial 37 | trial: int 38 | number of fault injection trial. obtained from filename 39 | Notes 40 | ---------- 41 | Users will want to fill out this function to parse both the custom 42 | injection log and any other lines such as detection messages or 43 | algorithm progress that may be visualized later. 44 | 45 | Example 46 | ------- 47 | if numIterationMessage in l: 48 | iter = int(l.split(" ")[-1]) 49 | c.execute("UPDATE trials SET iter = ? WHERE trials.trial = ?", (iter, trial)) 50 | if notConvergedMsg in l: 51 | c.execute("UPDATE trials SET converged = ? WHERE trials.trial = ?", (0,trial)) 52 | """ 53 | 54 | -------------------------------------------------------------------------------- /examples/mpi/visualization/analysis/database.py: -------------------------------------------------------------------------------- 1 | import sqlite3, os, sys 2 | from analysis_config import * 3 | from binaryParser import * 4 | 5 | 6 | 7 | def init(db, LLVMPath, trialPath, customFuncs = None): 8 | """Sets up the fault injection campaign visualization database 9 | by reading log files generated by FlipIt and run output files 10 | containing injection information. 11 | Parameters 12 | ---------- 13 | db : str 14 | Path to an existing sqlite3 database or the name of a database to 15 | create. 16 | LLVMPath : str 17 | Path to where the LLVM log files (*.LLVM.txt) generated by FlipIt exist. 18 | trialPath : str 19 | Path to where the output files of the run(s) are stored. Each output file 20 | should a seperate fault injection run of the application. 21 | customFuncs : tuple of function pointers 22 | Tuple of customs parsing functions (initcustomparsing(), customparser()) 23 | 24 | Return 25 | --------- 26 | sqlite3 database connection handle that is open 27 | 28 | Notes 29 | ---------- 30 | Searched recursively in LLVMPath for log files. 31 | customFuncs can be None. In that case, no user parseing is done. 32 | """ 33 | 34 | if rebuild_database: 35 | os.system("rm -rf " + db) 36 | exists = os.path.isfile(db) 37 | conn = sqlite3.connect(db) 38 | c = conn.cursor() 39 | if customFuncs == None: 40 | customFuncs = (None, None) 41 | if not exists: 42 | createTables(c) 43 | if customFuncs[0] != None: 44 | customFuncs[0](c) 45 | readLLVM(c, LLVMPath) 46 | if customFuncs != None and len(customFuncs) == 2: 47 | readTrials(c, trialPath, customFuncs[1]) 48 | else: 49 | readTrials(c, trialPath) 50 | 51 | c.execute("SELECT name FROM sqlite_master WHERE type='table';") 52 | conn.commit() 53 | return c 54 | 55 | def createTables(c): 56 | """Add tables into the database need when parsing run output files 57 | Parameters 58 | ---------- 59 | c : object 60 | sqlite3 database handle that is open to a valid filled database 61 | """ 62 | c.execute("CREATE TABLE sites (site int, type text, comment text, file text, function text, line int, opcode text)") 63 | c.execute("CREATE TABLE trials (trial int, numInj int, crashed int, detection int, path text, signal int)") 64 | c.execute("CREATE TABLE injections (trial int, site int, rank int, prob double, bit int, cycle int, notes text)") 65 | c.execute("CREATE TABLE signals (trial int, num int)") 66 | c.execute("CREATE TABLE detections (trial int, latency int, detector text)") 67 | #c.execute("CREATE TABLE ()") 68 | 69 | 70 | def readLLVM(c, LLVMPath): 71 | """Searches through the directory structure and collect 72 | fault injection site information and add it to the database 73 | 74 | Parameters 75 | ---------- 76 | c : object 77 | sqlite3 database handle that is open to a valid filled database 78 | LLVMPath : str 79 | Path to where the LLVM log files (*.LLVM.bin) generated by FlipIt exist. 80 | """ 81 | print "\n\nReading LLVM log files:" 82 | end = "LLVM.bin" 83 | if LLVM_log_type == "ASCII": 84 | end = "LLVM.txt" 85 | for path, subdirs, files in os.walk(LLVMPath): 86 | for name in files: 87 | if str(name).endswith(end): 88 | print "\t", name 89 | if LLVM_log_type == "Binary": 90 | parseBinaryLogFile(c, os.path.join(path, name)) 91 | else: 92 | parseInjLog(c, path, name) 93 | 94 | 95 | def parseInjLog(c, path, file): 96 | """Reads FLipIt LLVM log file and adds fault injection site 97 | information into the database. 98 | Parameters 99 | ---------- 100 | c : object 101 | sqlite3 database handle that is open to a valid filled database 102 | path : str 103 | path to where the LLVM log file resides 104 | file : str 105 | name of the LLVM log file to read 106 | """ 107 | 108 | fullPath = os.path.join(path, file) 109 | rawlog = open(fullPath).readlines() 110 | funcName = "" 111 | 112 | for i in range(0, len(rawlog)): 113 | if "Function Name: " in rawlog[i]: 114 | funcName = rawlog[i].split(" ")[-1].strip() 115 | 116 | if rawlog[i][0] == "#": 117 | # break line: "#NUM TYPE TXT TXT" to grab NUM 118 | split = rawlog[i].split("\t") 119 | site = int( split[0][1:] ) 120 | type = split[1] 121 | comment = split[-2] 122 | line = split[-1] 123 | srcLine = 0 124 | 125 | # compiled with -g and we know the src line number 126 | if ":" in line: 127 | split = line.split(":") 128 | srcLine = int(split[-1]) 129 | file = split[0] 130 | c.execute("INSERT INTO sites VALUES (?,?,?,?,?,?,?)", (site, type, comment, file, funcName, srcLine, "Unknown")) 131 | 132 | 133 | def readTrials(c, filePrefix, customParser = None): 134 | """Parses an output file of a fault injection trial for injections, 135 | detections, and system level events such as raised signals. 136 | 137 | Parameters 138 | ---------- 139 | c : object 140 | sqlite3 database handle that is open to a valid filled database 141 | filePrefix : str 142 | path to a fault injection run output file including the first 143 | part of the file name 144 | customParser : function pointer 145 | function the user defines to allow for custom parsing of 146 | run output file 147 | """ 148 | print "\n\nReading trials with file prefix: ", filePrefix 149 | for trial in range(0, int(numTrials)): 150 | 151 | # determine if trial exists 152 | path = filePrefix + "_" + str(trial)#".txt" 153 | 154 | if not os.path.exists(path): 155 | path += ".txt" 156 | if not os.path.exists(path): 157 | continue 158 | print "\t", path 159 | 160 | # grab information about the injection(s) 161 | t = open(path).readlines() 162 | llvmInj = injCount = crashed = detected = signal = arithFP = 0 163 | 164 | c.execute("INSERT INTO trials(trial,path) VALUES (?,?)", (trial, path)) 165 | # look at certain lines in output 166 | i = 0 167 | while i < len(t): 168 | l = t[i] 169 | if siteMessage in l: 170 | injCount += 1 171 | inj = [] 172 | i += 1 173 | l = t[i] 174 | while siteEndMessage not in l: 175 | if l != "\n": 176 | inj.append(l.split(" ")) 177 | i += 1 178 | l = t[i] 179 | 180 | # grab info stored in 'inj' 181 | if "IEEE" in inj[0]: 182 | arithFP = 1 183 | rank = int(inj[1][-1]) 184 | bit = int(inj[3][-1]) 185 | site = int(inj[4][-1]) 186 | prob = float(inj[5][-1]) 187 | c.execute("SELECT * FROM sites WHERE site=?", (site,)) 188 | result = c.fetchone() 189 | if result == None: 190 | print "Unable to locate site #", site, " in database" 191 | sys.exit(1) 192 | type = result[1] 193 | if "Arithmetic" in type: 194 | if arithFP: 195 | type = "Arith-FP" 196 | else: 197 | type = "Arith-Fix" 198 | c.execute("UPDATE sites SET type = ? WHERE site=?",(type,site)) 199 | llvmInj = int(inj[7][-1]) 200 | dynCycle = llvmInj 201 | c.execute("INSERT INTO injections VALUES (?,?,?,?,?,?,?)", (trial, site, rank, prob, bit, dynCycle, 'NULL')) 202 | 203 | for j in range(8, len(inj)): 204 | customParser(c, inj[j], trial) 205 | 206 | 207 | if detectMessage in l: 208 | detected = True 209 | c.execute("INSERT INTO detections VALUES (?,?,?)", (trial, -1, "---")) 210 | 211 | if assertMessage in l: 212 | signal = True 213 | crashed = True 214 | c.execute("INSERT INTO signals VALUES (?,?)", (trial, 6)) 215 | 216 | if busError in l: 217 | signal = True 218 | crashed = True 219 | c.execute("INSERT INTO signals VALUES (?,?)", (trial, 10)) 220 | 221 | if segError in l: 222 | signal = True 223 | crashed = True 224 | c.execute("INSERT INTO signals VALUES (?,?)", (trial, 11)) 225 | 226 | if customParser != None: 227 | customParser(c, l, trial) 228 | 229 | i += 1 230 | c.execute("UPDATE trials SET numInj=? WHERE trials.trial=?", (injCount, trial)) 231 | c.execute("UPDATE trials SET crashed=? WHERE trials.trial=?", (crashed, trial)) 232 | c.execute("UPDATE trials SET detection=? WHERE trials.trial=?", (detected, trial)) 233 | c.execute("UPDATE trials SET signal=? WHERE trials.trial=?", (signal, trial)) 234 | 235 | def finalize(): 236 | """Cleans up fault injection visualization 237 | """ 238 | print "Finalizing fault injection visualization..." 239 | #conn.commit() 240 | #conn.close() 241 | -------------------------------------------------------------------------------- /examples/mpi/visualization/analysis/main.py: -------------------------------------------------------------------------------- 1 | from matplotlib import pyplot as plot 2 | from database import init, finalize 3 | from visualize import initVis, visClassifications, visFunctions, visCrashes,\ 4 | visSignals, visDetections, visDetectedInjections, visDetectionLatency 5 | from custom import customInit, customParser 6 | #import analysis_config 7 | from analysis_config import * 8 | 9 | def visualize (c, more_detail_funcs = None): 10 | """Driver function to visulize a fault injection campaign. 11 | Parameters 12 | ---------- 13 | c : object 14 | sqlite3 database handle that is open to a valid filled database 15 | 16 | more_detail_funcs : list of str 17 | function names to generate extra analysis of injections inside them 18 | Notes 19 | ---------- 20 | Allows for user custom visualzations after first 'plot.show()' 21 | """ 22 | initVis(c) 23 | visClassifications(c, more_detail_funcs) 24 | visFunctions(c, more_detail_funcs) 25 | visCrashes(c) 26 | visSignals(c) 27 | visDetections(c, more_detail_funcs) 28 | visDetectedInjections(c) 29 | visDetectionLatency(c) 30 | plot.show() 31 | 32 | # add custom plotting function below 33 | plot.show() 34 | 35 | 36 | if __name__ == "__main__": 37 | c = init(database, LLVM_log_path, trial_path +"/"+ trial_prefix,\ 38 | customFuncs=(customInit, customParser)) 39 | visualize(c, more_detail_funcs) 40 | finalize() 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /examples/mpi/visualization/analysis/migrate.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | """Converts run output files to the formate expected by the flipit analysis 5 | scripts 6 | 7 | Parameters 8 | argv[1] : str 9 | file prefix of the run files to look for e.g. foo for run outfiles 10 | such as foo.oe139493 11 | argv[2] : str 12 | path to where the run files are located 13 | 14 | Notes 15 | ----- 16 | Keeps the original run ouput files. 17 | Places the newly generated run output files in the same directory 18 | as the orginals. 19 | """ 20 | # usage: python migrate.py 21 | # e.g. python migrate.py faultInjectionTrial /path/to/run/files/ 22 | if __name__ == '__main__': 23 | prefix = sys.argv[1] 24 | path = sys.argv[2] 25 | files = [] 26 | 27 | # cache all the file names 28 | for p, s, f in os.walk(path): 29 | for name in f: 30 | if prefix in name: 31 | print "Adding ", name, len(files) 32 | files.append(name) 33 | 34 | #order the file names and then append the trial number 35 | files.sort() 36 | for i in xrange(0, len(files): 37 | os.system("cp " + path + "/" + f + " " + path +"/" + prefix + "_" + str(i)) 38 | -------------------------------------------------------------------------------- /examples/mpi/visualization/analysis/visualize.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | from matplotlib import pyplot as plot 3 | import numpy as np 4 | import matplotlib 5 | from analysis_config import * 6 | 7 | 8 | numFigs = 0 9 | numTrials = 0 10 | numTrialsInj = 0 11 | colors = ['g','b', 'y', 'm', 'c', 'r'] 12 | TYPES = ["Arith-FP", "Pointer", "Arith-Fix", "Ctrl-Loop", "Ctrl-Branch"] 13 | TYPES_LONG = ["Floating-Point", "Pointer", "Fixed-Point", "Control-Loop", "Control-Branch"] 14 | typeIdx= {"Arith-FP":0, "Arithmetic":0, "Control": 6, "Pointer":1, "Arith-Fix":2, "Control-Loop":3, "Control-Branch":4} 15 | nClassifications = len(TYPES) 16 | 17 | def initVis(c): 18 | """Perform database operations to cache some values needed in later 19 | analysis. 20 | Parameters 21 | ---------- 22 | c : object 23 | sqlite3 database handle that is open to a valid filled database 24 | """ 25 | 26 | global numTrialsInj, numTrials 27 | c.execute("SELECT * FROM trials WHERE trials.numInj > 0") 28 | numTrialsInj = 1. * len(c.fetchall()) 29 | c.execute("SELECT * FROM trials") 30 | numTrials = 1. * len(c.fetchall()) 31 | if numTrialsInj == 0: 32 | print "No injections found to visualize..." 33 | sys.exit(1) 34 | print "Visualizing ", numTrials, " fault injection trials ("\ 35 | , numTrialsInj,") with faults" 36 | 37 | # wrapper around creating a pie chart 38 | def barchart(bins, values, xlabel, ylabel, title, name=None, ticks=None): 39 | """Wapper around the matplotlib bar function. Useful when we need bars 40 | from multiple trends. 41 | 42 | Parameters 43 | ---------- 44 | bins : np.array 45 | x values of where the bars should reside 1-D array 46 | values : np.array 47 | heights of the bars 2-D array [# trends][ len(bins)] 48 | xlabel : str 49 | label to display on the x axis 50 | ylabel : str 51 | label to display on the y axis 52 | title : str 53 | title of the figure 54 | name : list str 55 | trend names of length len(values) # trends 56 | ticks : list str 57 | x axis ticks to display of length len(bins) 58 | 59 | See Also 60 | ---------- 61 | histo() 62 | """ 63 | global numFigs 64 | plot.figure(numFigs) 65 | width = 1./len(values) 66 | if name == None: 67 | name = ["" for i in xrange(len(values))] 68 | for set in range(0, len(values)): 69 | plot.bar(bins+width*set, values[set][:], width, label=name[set], color=colors[set]) 70 | plot.xlabel(xlabel) 71 | plot.ylabel(ylabel) 72 | plot.legend(fancybox = True, shadow=True) 73 | if ticks != None: 74 | plot.xticks(bins+.5, ticks, rotation=60) 75 | plot.title(title) 76 | plot.tight_layout() 77 | numFigs += 1 78 | 79 | def piechart(percents, labels, title): 80 | """Wrapper around the matplotlib function pie 81 | 82 | Parameters 83 | ---------- 84 | percents : array like 85 | values to plot as percentages 86 | labels : list of str 87 | trend names corresponding to the percentages in percents 88 | title : str 89 | title of the pie chart 90 | """ 91 | 92 | global numFigs 93 | plot.figure(numFigs) 94 | patches, texts, autotexts = plot.pie(percents, labels=labels, autopct='%1.1f%%', colors=colors) 95 | for i in range(0, len(autotexts)): 96 | autotexts[i].set_color('w') 97 | autotexts[i].set_weight('bold') 98 | #autotexts[i].set_fontsize(16) 99 | plot.title(title) 100 | ax = plot.axis() 101 | v = (ax[0] - (ax[1] - ax[0])/4., ax[1] + (ax[1] - ax[0])/4., ax[2], ax[3]) 102 | plot.axis(v) 103 | plot.tight_layout() 104 | numFigs += 1 105 | 106 | def histo(values, bins, xlabel, ylabel, title, ticks=None, label=None, c=None): 107 | """Wrapper around the matplotlib function bar. Useful for a single trend 108 | 109 | Parameters 110 | ---------- 111 | values : array like 112 | heights of the bars 1-D 113 | bins : array like 114 | x values of where the bars should reside 1-D array 115 | xlabel : str 116 | label to display on the x axis 117 | ylabel : str 118 | label to display on the y axis 119 | title : str 120 | title of the figure 121 | ticks : list str 122 | x axis ticks to display of length len(bins) 123 | label : list str 124 | trend name of the data being graphed 125 | c : char 126 | color of the trend 127 | 128 | See Also 129 | --------- 130 | barchart 131 | """ 132 | global numFigs 133 | fig = plot.figure(numFigs) 134 | width = .8 135 | if c != None and label != None: 136 | plot.bar(bins, values, width, align ='center', label=label, color=c) 137 | else: 138 | plot.bar(bins, values, width, align = 'center') 139 | plot.xlabel(xlabel) 140 | plot.ylabel(ylabel) 141 | if ticks != None: 142 | plot.xticks(bins, ticks, rotation=60) 143 | #plot.xticks(bins+.5, ticks, rotation=60) 144 | plot.legend(loc='upper left',fancybox = True, shadow=True) 145 | plot.title(title) 146 | plot.tight_layout() 147 | numFigs += 1 148 | 149 | def visClassifications(c, moreDetail=None): 150 | """Graphs of what types of faults were injected. Classification based 151 | on FlipIt classification. 152 | 153 | Parameters 154 | ---------- 155 | c : object 156 | sqlite3 database handle that is open to a valid filled database 157 | moreDetail : list of str 158 | function names to generate extra analysis of injections inside them 159 | Notes 160 | ---------- 161 | More detail currently not implimented. 162 | """ 163 | typeBuckets = np.zeros(nClassifications + 1) 164 | bits = np.zeros((nClassifications, 64)) 165 | c.execute("SELECT site, bit FROM injections") 166 | injs = c.fetchall() 167 | if len(injs) == 0: 168 | print "Error in visClassifications: No Injections\n" 169 | return 170 | maximum = max(injs)[0] +1 171 | locs = np.zeros((nClassifications, maximum)) 172 | 173 | c.execute("SELECT type FROM sites INNER JOIN injections ON sites.site = injections.site") 174 | types = c.fetchall() 175 | 176 | for i in range(len(injs)): 177 | type = types[i][0] 178 | site = injs[i][0] 179 | bit = injs[i][1] 180 | #print type 181 | #print typeIdx 182 | if type in typeIdx: 183 | idx = typeIdx[type] 184 | if idx == 6: 185 | print "Warning: mapping type (", type,\ 186 | ") to type ( Control-Branch )" 187 | idx = 4 188 | typeBuckets[idx] += 1 189 | locs[idx][site] += 1 190 | bits[idx][bit] += 1 191 | else: 192 | print "VIZ: not classified = ", i 193 | typeBuckets[nClassifications] += 1 194 | fracs = typeBuckets/np.sum(typeBuckets) 195 | piechart(fracs[0:-1], TYPES_LONG, "Classification of Injections Based on Type") 196 | barchart(np.linspace(0,64,num=64), bits, "Bit Location", "Frequency", "Injected bit", TYPES) 197 | plot.xlim((0,64)) 198 | 199 | 200 | 201 | 202 | def visFunctions(c, moreDetail=None): 203 | """Graphs percentages of what functions faults were injection into 204 | 205 | Parameters 206 | ---------- 207 | c : object 208 | sqlite3 database handle that is open to a valid filled database 209 | moreDetail : list of str 210 | function names to generate extra analysis of injections inside them 211 | """ 212 | global numFigs 213 | c.execute("SELECT DISTINCT function FROM sites INNER JOIN injections ON injections.site = sites.site") 214 | funcs = c.fetchall() 215 | values = [] 216 | for i in funcs: 217 | c.execute("SELECT COUNT(trial) FROM injections INNER JOIN sites ON sites.site = injections.site AND sites.function = ?", i) 218 | values.append(1. * c.fetchone()[0]) 219 | piechart(np.array(values)/sum(values), [i[0] for i in funcs], "Injected Functions") 220 | 221 | ind = 0 222 | width = .5 223 | fig = plot.figure(numFigs) 224 | ax = plot.subplot(111) 225 | for i in funcs: 226 | i = i[0] 227 | c.execute("SELECT type FROM sites INNER JOIN injections ON sites.site = injections.site AND sites.function = ?", (i,)) 228 | types = c.fetchall() 229 | 230 | tot = float(len(types)) 231 | per = np.zeros(nClassifications) 232 | per = [ 0 for i in xrange(nClassifications)] 233 | for t in types: 234 | #per[typeIdx[t[0]]] += 1. 235 | idx = typeIdx[t[0]] 236 | if idx == 6: 237 | print "Warning: mapping type ( Control ) to type "\ 238 | "( Control-Branch )" 239 | idx = 4 240 | per[idx] += 1 241 | per = np.array(per)/tot * 100 242 | btm = 0 243 | legend = [] 244 | for t in xrange(0,nClassifications): 245 | p1 = ax.bar(ind, per[t], width, align='center', color=colors[t], bottom=btm) 246 | btm += per[t] 247 | legend.append(p1) 248 | ind += 1 249 | ax.set_xticks(np.arange(len(funcs))) 250 | ax.set_xticklabels([f[0] for f in funcs], rotation=60, ha='center') 251 | numFigs += 1 252 | 253 | ax.set_ylim((0,100)) 254 | ax.set_ylabel("Percent") 255 | 256 | # shrink graph to add legend and title at top 257 | plot.tight_layout() 258 | box = ax.get_position() 259 | ax.set_position([box.x0, box.y0, 260 | box.width, box.height * 0.8]) 261 | ax.legend(legend, TYPES, loc='upper center', bbox_to_anchor=(0.5, 1.15), 262 | fancybox=True, shadow=True, ncol=5) 263 | plot.setp(plot.gca().get_legend().get_texts(), fontsize='x-small') 264 | plot.text(0.5, 1.15, "Breakdown of Injection Type per Function", 265 | horizontalalignment='center', fontsize=14, transform = ax.transAxes) 266 | 267 | # more detail for a function creates an html file with the source 268 | # code colored based on injection percentatge 269 | if moreDetail != None: 270 | visInjectionsInCode(c, moreDetail) 271 | 272 | def visInjectionsInCode(c, functions): 273 | """Creates an html file with the source code colored based on injection 274 | percentages 275 | 276 | Parameters 277 | ---------- 278 | c : object 279 | sqlite3 database handle that is open to a valid filled database 280 | functions : list of str 281 | function names to generate extra analysis of injections inside them 282 | """ 283 | outfile = open("more.html", 'w') 284 | outfile.write("\n\n\n") 285 | for func in functions: 286 | # grab all injections in this function 287 | c.execute("SELECT file, line FROM sites INNER JOIN injections ON sites.site = injections.site AND sites.function = ?", (func,)) 288 | result = c.fetchall() 289 | if len(result) == 0: 290 | print "Warning (visInjectionsInCode): no injections in target function -- ", func 291 | continue 292 | 293 | # locate the min and max source line num to shrink output file size 294 | # we only want to show the section of code that we inject in 295 | lines = [i[1] for i in result] 296 | file = result[0][0] 297 | if ".LLVM.txt" in file: 298 | file = result[-1][0] 299 | minimum = np.min(lines)-1 300 | minimum = minimum if minimum >= 0 else 0 301 | maximum = np.max(lines)+1 302 | bins = np.arange(minimum, maximum+1) 303 | values, bins = np.histogram(lines, bins, density=False) # <------------ check here 304 | bins = np.arange(minimum, maximum) 305 | values = 1.*values/np.sum(values)*100 # percents 306 | histo(values, bins, "Source Line Number", "Percent",\ 307 | "Injections mapped to source line numbers for function: " + func) 308 | 309 | outfile.write("

" + func + "()

\n\n") 310 | if minimum == 0: 311 | outfile.write("Unable to assign " + str(values[0]) + "\% of injections to source code.\n") 312 | minimum = np.min(np.trim_zeros(lines)) - 1 313 | values = values[minimum:] 314 | outfile.write("
\n") 315 | if os.path.isfile(file): 316 | srcPath = "" 317 | if not os.path.isfile(srcPath+file): 318 | print "Warning (visInjectionsInCode): source file not found -- ", srcPath + file 319 | continue 320 | print "\nRelating injections to source code in file: ", srcPath+file 321 | FILE = open(srcPath+file, "r") 322 | function = FILE.readlines()[minimum:maximum] 323 | FILE.close() 324 | 325 | 326 | for i in range(1,len(function)): 327 | color = "bgcolor=\"" + getColor(values[i]) +"\"" 328 | outfile.write("\n\n\n\n\n") 331 | outfile.write("
"+ str(minimum+i) +\ 329 | "" + str2html(function[i-1]) + ""\ 330 | + str(values[i]) + "
\n") 332 | 333 | outfile.write("\n\n") 334 | outfile.close() 335 | 336 | def str2html(s): 337 | """Replaces '<', '>', and '&' with html equlivants 338 | 339 | Parameters 340 | ---------- 341 | s : str 342 | string to convert to a vaild html string to display properly 343 | """ 344 | return s.replace("&", "&").replace(">", ">").replace("<", "<") 345 | 346 | def getColor(x): 347 | """Selects an html color based on 0 <= x <= 100 348 | 349 | Parameters 350 | ---------- 351 | x : float 352 | percent of injection to color visually. Higher the percent the darker 353 | the color 354 | Returns 355 | ---------- 356 | html color name useful for classifying 357 | """ 358 | if x >= 75: 359 | return "red" 360 | elif x >= 50: 361 | return "orange" 362 | elif x >= 25: 363 | return "yellow" 364 | elif x >= 5: 365 | return "lime" 366 | else: 367 | return "white" 368 | 369 | 370 | # graphs percentage of trials that crashed 371 | def visCrashes(c): 372 | """Graph percentage of trials that crashed, and bit location and type 373 | of the corresponding injection 374 | 375 | Parameters 376 | ---------- 377 | c : object 378 | sqlite3 database handle that is open to a valid filled database 379 | 380 | Notes 381 | ---------- 382 | Only considers trials with injections when calculating percentages 383 | """ 384 | 385 | bits = np.zeros((nClassifications, 64)) 386 | c.execute("SELECT type FROM sites INNER JOIN injections ON sites.site = injections.site INNER JOIN trials ON trials.trial = injections.trial AND trials.crashed = 1") 387 | crash = c.fetchall() 388 | crashed = float(len(crash)) 389 | c.execute("SELECT site, bit FROM injections INNER JOIN trials ON injections.trial = trials.trial AND trials.crashed = 1") 390 | sitesBits = c.fetchall() 391 | for i in range(len(sitesBits)): 392 | type = crash[i][0] 393 | bit = sitesBits[i][1] 394 | #bits[typeIdx[type]][bit] += 1 395 | idx = typeIdx[type] 396 | if idx == 6: 397 | print "Warning: mapping type ( Control ) to type "\ 398 | "( Control-Branch )" 399 | idx = 4 400 | bits[idx][bit] += 1 401 | 402 | piechart([(numTrialsInj - crashed)/numTrialsInj, crashed/numTrialsInj],\ 403 | ["Didn't Crash", "Crashed"], "Unexpected Termination") 404 | barchart(np.linspace(0,64,num=64), bits, "Bit Location", "Frequency", "Unexpected Termination: Injected bit", TYPES) 405 | plot.legend(loc='upper left', fancybox = True, shadow=True) 406 | plot.xlim((0,64)) 407 | 408 | for i in range(nClassifications): 409 | if np.sum(bits[i][:]) > 0: 410 | histo(bits[i][:], np.linspace(0, 64, num=64), "Bit Location", "Frequency", "Unexpected Termination", None, TYPES[i], colors[i]) 411 | plot.xlim((0,64)) 412 | #plot.legend('upper left') 413 | 414 | # graphs percent of trials that threw at least 1 assert 415 | def visAsserts(c): 416 | """Graphs percent of trials that threw at least 1 assert 417 | 418 | Parameters 419 | ---------- 420 | c : object 421 | sqlite3 database handle that is open to a valid filled database 422 | Notes 423 | ---------- 424 | Only considers trials with injections when calculating percentages 425 | """ 426 | c.execute("SELECT DISTINCT trial from signal WHERE num == 6") 427 | asserts = len(c.fetchall()) 428 | piechart([asserts/numTrialsInj, (numTrials - asserts)/numTrialsInj],\ 429 | ["Failed Assert(s)", "Didn't Assert"], "Trials with Injections Asserting") 430 | 431 | # graphs percent of trials that generated at a certian signal type that is reported in the output file 432 | def visSignals(c): 433 | """Graphs the percent of trials that generated a certian signal type 434 | reported in the output file 435 | 436 | Parameters 437 | ---------- 438 | c : object 439 | sqlite3 database handle that is open to a valid filled database 440 | 441 | Notes 442 | ---------- 443 | If a trial generates multiple signals, e.g. each rank asserts, we regard 444 | this as a single signal for the trial. 445 | """ 446 | numSigs = 0. 447 | sigs = {} 448 | 449 | c.execute("SELECT DISTINCT trial, num FROM signals") 450 | #build histogram for what signals were raised 451 | signals = c.fetchall() 452 | for pair in signals: 453 | s = pair[1] 454 | numSigs += 1 455 | if s in sigs:# and s != 11: 456 | sigs[s] += 1 457 | else: 458 | sigs[s] = 1. 459 | 460 | fracs = [(numTrials - numSigs)/numTrialsInj] 461 | labels = ["No Signal"] 462 | for s in sigs: 463 | fracs.append(sigs[s]/numTrialsInj) 464 | labels.append("Signal " + str(s)) 465 | c.execute("SELECT DISTINCT trial from signals") 466 | unique = len(c.fetchall()) 467 | piechart(fracs, labels, str(unique) + " Trials Signaling") 468 | 469 | def visDetections(c, moreDetail=None): 470 | """Graphs the percentage of trials that generate detection 471 | 472 | Parameters 473 | ---------- 474 | c : object 475 | sqlite3 database handle that is open to a valid filled database 476 | moreDetail : list of str 477 | function names to generate extra analysis of detections inside them 478 | Notes 479 | ---------- 480 | Assumes one injection per trial. 481 | TODO: add graphs for more detail option 482 | """ 483 | #if moreDetail != None: 484 | # print "TODO: implement more detail option for 'visDetections'" 485 | c.execute("SELECT COUNT(trial) FROM trials WHERE detection = 1") 486 | detected = float(c.fetchone()[0]) 487 | c.execute("SELECT SUM(numInj) FROM trials") 488 | numInj = float(c.fetchone()[0]) 489 | 490 | piechart([detected/numInj, (numInj - detected)/numInj],\ 491 | ["Detected", "Didn't Detect"], "Number of Trials with Detection ("+str(detected)+")") 492 | 493 | 494 | def visDetectedInjections(c, moreDetail=None): 495 | """Graphs bit locations and type of what injections were detected 496 | 497 | Parameters 498 | ---------- 499 | c : object 500 | sqlite3 database handle that is open to a valid filled database 501 | 502 | moreDetail : list of str 503 | function names to generate extra analysis of detections inside them 504 | Notes 505 | ---------- 506 | TODO: add graphs for more detail option 507 | TODO: visualize injection sites detected 508 | TODO: visualize injection types detected 509 | Allows for user custom visualzations after first 'plot.show()' 510 | """ 511 | #if moreDetail != None: 512 | # print "TODO: implement more detail option for 'visDetectedInjections'" 513 | bits = np.zeros((nClassifications,64)) 514 | c.execute("SELECT site, bit FROM injections INNER JOIN trials ON injections.trial = trials.trial AND trials.detection = 1") 515 | injs = c.fetchall() 516 | c.execute("SELECT type FROM sites INNER JOIN injections ON sites.site = injections.site INNER JOIN trials ON injections.trial = trials.trial AND trials.detection = 1") 517 | types = c.fetchall() 518 | 519 | for i in range(len(injs)): 520 | type = types[i][0] 521 | site = injs[i][0] 522 | bit = injs[i][1] 523 | #bits[typeIdx[type]][bit] += 1 524 | idx = typeIdx[type] 525 | if idx == 6: 526 | print "Warning: mapping type ( Control ) to type "\ 527 | "( Control-Branch )" 528 | idx = 4 529 | bits[idx][bit] += 1 530 | 531 | barchart(np.linspace(0,64,num=64), bits, "Injected bit", "Frequency", "Detected Injection Bit Location", TYPES) 532 | plot.xlim((0,64)) 533 | 534 | 535 | 536 | def visDetectionLatency(c): 537 | """Visualizes the detection latency of an injection in the form of 538 | a bar chart with the x-axis as number of instruction executed after 539 | injection. 540 | 541 | Parameters 542 | ---------- 543 | c : object 544 | sqlite3 database handle that is open to a valid filled database 545 | 546 | Notes 547 | ---------- 548 | Assumes the user modifed the latency value in the detections table. It can 549 | be calucated by the 550 | 'LLVM_dynamic_inst_of_detection - LLVM_dynamic_inst_of_injection'. 551 | The later can be obtained from the injection table for the trial, and the 552 | former can be obtained at detection time though the FlipIt API call 553 | 'FLIPIT_GetDynInstCount()'. 554 | """ 555 | #TODO: Extend to look at latency for each detector 556 | c.execute("SELECT latency FROM detections") 557 | 558 | buckets = [-1, 0, 1, 2, 3, 4, 5, 10, 1e2, 1e3, 1e9, 1e13] 559 | data = [ i[0] for i in c.fetchall()] 560 | values, bins = np.histogram(data, buckets, normed=False) 561 | xlabel = "# of instrumented LLVM instructions till detection" 562 | ylabel = "Frequency" 563 | title = "Detection Latency" 564 | ticks = ["-1", "0", "1", "2", "3", "4", "5->", "10->", "1e2->", "1e3->", "1e9->"] 565 | bins = np.arange(0,11) 566 | histo(values, bins, xlabel, ylabel, title, ticks) 567 | 568 | -------------------------------------------------------------------------------- /examples/mpi/visualization/config.py: -------------------------------------------------------------------------------- 1 | ############### Injector Parameters ################## 2 | # 3 | # config - config file used by the compiler pass 4 | # funcList - list of functions that are faulty 5 | # prob - probability that instuction is faulty 6 | # byte - which byte is faulty (0-7) -1 random 7 | # singleInj - one injection per active rank (0 or 1) 8 | # ptr - add code to inject into pointers (0 or 1) 9 | # arith - add code to inject into mathematics (0 or 1) 10 | # ctrl - add code to inject into control (0 or 1) 11 | # stateFile - unique counter for fault site index; 12 | # should differ based on application 13 | # 14 | ##################################################### 15 | 16 | config = "jacobi.config" 17 | funcList = "\"\"" 18 | prob = 1e-5 19 | byte = -1 20 | singleInj = 1 21 | ptr = 1 22 | arith = 1 23 | ctrl = 1 24 | stateFile = "jacobi" 25 | 26 | ############# Library Parameters ##################### 27 | # 28 | # FLIPIT_PATH - Path to FlipIt repo 29 | # SHOW - libraries and path wraped by mpicc 30 | # 31 | ##################################################### 32 | import os 33 | FLIPIT_PATH = os.environ['FLIPIT_PATH'] 34 | LLVM_BUILD_PATH = os.environ['LLVM_BUILD_PATH'] 35 | SHOW = "" 36 | 37 | 38 | ########### Files to NOT inject inside ############### 39 | notInject = [" ", " "] 40 | 41 | ############ Default Compiler ################# 42 | cc = "mpicc" 43 | 44 | ############ Verbose compiler output ############## 45 | verbose = False 46 | 47 | -------------------------------------------------------------------------------- /examples/mpi/visualization/jacobi.c: -------------------------------------------------------------------------------- 1 | #include "jacobi.h" 2 | 3 | void jacobi(int rank) 4 | { 5 | int value, size, errcnt, toterr, i, j, itcnt; 6 | int i_first, i_last; 7 | MPI_Status status; 8 | double diffnorm, gdiffnorm; 9 | double xlocal[(12/4)+2][12]; 10 | double xnew[(12/3)+2][12]; 11 | 12 | MPI_Comm_size( MPI_COMM_WORLD, &size ); 13 | 14 | if (size != 4) MPI_Abort( MPI_COMM_WORLD, 1 ); 15 | 16 | /* xlocal[][0] is lower ghostpoints, xlocal[][maxn+2] is upper */ 17 | 18 | /* Note that top and bottom processes have one less row of interior 19 | points */ 20 | i_first = 1; 21 | i_last = maxn/size; 22 | if (rank == 0) i_first++; 23 | if (rank == size - 1) i_last--; 24 | 25 | /* Fill the data as specified */ 26 | for (i=1; i<=maxn/size; i++) 27 | for (j=0; j 0) 42 | MPI_Recv( xlocal[0], maxn, MPI_DOUBLE, rank - 1, 0, 43 | MPI_COMM_WORLD, &status ); 44 | /* Send down unless I'm at the bottom */ 45 | if (rank > 0) 46 | MPI_Send( xlocal[1], maxn, MPI_DOUBLE, rank - 1, 1, 47 | MPI_COMM_WORLD ); 48 | if (rank < size - 1) 49 | MPI_Recv( xlocal[maxn/size+1], maxn, MPI_DOUBLE, rank + 1, 1, 50 | MPI_COMM_WORLD, &status ); 51 | 52 | /* Compute new values (but not on boundary) */ 53 | itcnt ++; 54 | diffnorm = 0.0; 55 | for (i=i_first; i<=i_last; i++) 56 | for (j=1; j 1.0e-8 && itcnt < 1000); 73 | } -------------------------------------------------------------------------------- /examples/mpi/visualization/jacobi.config: -------------------------------------------------------------------------------- 1 | INSTRUCTIONS: 2 | #add=1e-8 3 | #fadd=1e-8 4 | #sub=1e-8 5 | #fsub=1e-8 6 | #mul=1e-8 7 | #fmul=1e-8 8 | #udiv=1e-8 9 | #sdiv=1e-8 10 | #fdiv=1e-8 11 | #urem=1e-8 12 | #srem=1e-8 13 | #frem=1e-8 14 | #shl=1e-8 15 | #lshr=1e-8 16 | #ashr=1e-8 17 | #and=1e-8 18 | #or=1e-8 19 | #xor=1e-8 20 | #alloca=1e-8 21 | #load=1e-8 22 | #store=1e-8 23 | #getelementptr=1e-8 24 | #icmp=1e-8 25 | #fcmp=1e-8 26 | #call=1e-8 27 | FUNCTIONS: 28 | FLIPIT_Init=0 29 | FLIPIT_Finalize=0 30 | FLIPIT_SetInjector=0 31 | FLIPIT_SetRankInject=0 32 | FLIPIT_SetFaultProbability=0 33 | FLIPIT_SetCustomLogger=0 34 | 35 | -------------------------------------------------------------------------------- /examples/mpi/visualization/jacobi.h: -------------------------------------------------------------------------------- 1 | #ifndef JACOBI_H 2 | #define JACOBI_H 3 | 4 | #include 5 | #include 6 | #include 7 | #define maxn 12 8 | void jacobi(int rank); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /examples/mpi/visualization/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "jacobi.h" 5 | #include "FlipIt/corrupt/corrupt.h" 6 | 7 | /* This example handles a 12 x 12 mesh, on 4 processors only. */ 8 | 9 | 10 | int main(int argc, char** argv) 11 | { 12 | int rank; 13 | int seed = 233; 14 | MPI_Init(&argc, &argv); 15 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); 16 | 17 | FLIPIT_Init(rank, argc, argv, time(NULL)); 18 | jacobi(rank); 19 | FLIPIT_Finalize(NULL); 20 | 21 | MPI_Finalize(); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /examples/mpi/visualization/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | #make a directory for the run output and run jacobi 25 times 5 | mkdir run_data 6 | cd run_data 7 | for i in {0..25} 8 | do 9 | #in a real run we would want to set the faulty rank a random 10 | echo $i 11 | mpirun -n 4 ../jacobi --numberFaulty 1 --faulty 3 &> run_$i.txt 12 | done 13 | -------------------------------------------------------------------------------- /examples/pass/Foo/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Foo pass 2 | 3 | ##################################################################### 4 | # 5 | # This file is licensed under the University of Illinois/NCSA Open 6 | # Source License. See LICENSE.TXT for details. 7 | # 8 | ##################################################################### 9 | 10 | CXX=$(LLVM_BUILD_PATH)/bin/clang 11 | LLVM_CONFIG=$(LLVM_BUILD_PATH)/bin/llvm-config 12 | 13 | CXXFLAGS= -Wall -O2 -g -std=c++11 -fno-rtti -I$(FLIPIT_PATH)/include 14 | CXXFLAGS += $(shell $(LLVM_CONFIG) --cxxflags) -fPIC 15 | #CXXFLAGS += -DCOMPILE_PASS 16 | 17 | LDFLAGS = $(shell $(LLVM_CONFIG) --ldflags) -L$(FLIPIT_PATH)/lib -lFlipIt 18 | 19 | ifeq ($(shell uname),Darwin) 20 | SHARED_LIB_OPT = -bundle -undefined dynamic_lookup 21 | else 22 | SHARED_LIB_OPT = -shared -Wl, -O1 23 | endif 24 | 25 | all: libFooPass.so 26 | 27 | libFooPass.so:foo.cpp 28 | $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(SHARED_LIB_OPT) $< 29 | 30 | 31 | clean: 32 | rm -rf *.o *.so 33 | 34 | -------------------------------------------------------------------------------- /examples/pass/Foo/createPass.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##################################################################### 4 | # 5 | # This file is licensed under the University of Illinois/NCSA Open 6 | # Source License. See LICENSE.TXT for details. 7 | # 8 | ##################################################################### 9 | 10 | ##################################################################### 11 | # 12 | # Name: createPass.sh 13 | # 14 | # Description: Compiles the LLVM compiler pass Foo that calls Flipit 15 | # from inside the pass to corrupt certain instructions. 16 | # 17 | ##################################################################### 18 | 19 | make clean 20 | make -f Makefile 21 | 22 | -------------------------------------------------------------------------------- /examples/pass/Foo/foo.cpp: -------------------------------------------------------------------------------- 1 | #include "foo.h" 2 | 3 | bool Food::Foo::runOnModule(Module &M) { 4 | errs() << "Inside Foo::runOnModule\n\n"; 5 | /* 6 | Command line arguments to FlipIt pass are the arguments of the constructor: 7 | string funcList (-funcList) 8 | string configPath (-config) 9 | double siteProb (-prob) 10 | int byte_val (-byte) 11 | int singleInj (-singleInj) 12 | bool arith_err (-arith) 13 | bool ctrl_err (-ctrl) 14 | bool ptr_err (-ptr) 15 | string srcFile (-srcFile) 16 | string statFiel (-stateFile) 17 | */ 18 | std::string srcFile = "none.c"; 19 | std::string stateFile = "foo"; 20 | DynamicFaults* flipit = new DynamicFaults("", "FlipIt.config", 0.95, 0, 1, 1, 1, 1, srcFile, stateFile, &M); 21 | 22 | for (auto F = M.getFunctionList().begin(), 23 | E = M.getFunctionList().end(); F != E; F++) { 24 | 25 | // select certain instution from this fucntion to corrupt 26 | if (F->getName().str() == "work") { 27 | errs() << "\n Calling FlipIt's corruptInstruction on every other" 28 | "instruction in function " << F->getName() << "\n"; 29 | int i = 0; 30 | for (auto BB = F->begin(), BBe = F->end(); BB !=BBe; BB++) { 31 | for (auto I = BB->begin(), Ie = BB->end(); I != Ie; I++ ) { 32 | if ( (isa(I) || isa(I) 33 | || isa(I) || isa(I) 34 | || isa(I) || isa(I) 35 | || isa(I)) ) { 36 | 37 | // corrupt every other instruction inside the "work" function 38 | if (i % 2 == 0) 39 | flipit->corruptInstruction(I); 40 | i++; 41 | } 42 | } 43 | } 44 | } 45 | } 46 | 47 | delete flipit; 48 | return false; 49 | } 50 | 51 | void Food::Foo::display() 52 | { 53 | errs() << "Food::Foo:display\n"; 54 | if (potato) 55 | errs() << "You like potatos\n"; 56 | if (carrot) 57 | errs() << "You like carrots\n"; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /examples/pass/Foo/foo.h: -------------------------------------------------------------------------------- 1 | /***********************************************************************************************/ 2 | /* This file is licensed under the University of Illinois/NCSA Open Source License. */ 3 | /* See LICENSE.TXT for details. */ 4 | /***********************************************************************************************/ 5 | 6 | /***********************************************************************************************/ 7 | /* */ 8 | /* Name: foo.h */ 9 | /* */ 10 | /* Description: Header file for an example compiler pass that uses FlipIt to corrupt certain */ 11 | /* instructinos. */ 12 | /* */ 13 | /***********************************************************************************************/ 14 | 15 | #include 16 | using std::vector; 17 | #include "llvm/Pass.h" 18 | #include "llvm/IR/Function.h" 19 | #include "llvm/IR/Module.h" 20 | #include "llvm/Support/raw_ostream.h" 21 | #include 22 | #include "llvm/IR/Instruction.h" 23 | //#include 24 | #include 25 | using namespace llvm; 26 | 27 | #include "FlipIt/pass/faults.h" 28 | using namespace FlipIt; 29 | 30 | 31 | static cl::opt potato("potato", cl::desc("Do you like potatos?"), cl::value_desc("0/1"), cl::init(1), cl::ValueRequired); 32 | static cl::opt carrot("carrot", cl::desc("Do you like carrots?"), cl::value_desc("0/1"), cl::init(1), cl::ValueRequired); 33 | 34 | namespace Food{ 35 | 36 | 37 | class Foo : public ModulePass { 38 | 39 | public: 40 | static char ID; 41 | Foo(): ModulePass(ID) { } 42 | 43 | bool runOnModule(Module &M); 44 | void display(); 45 | }; 46 | } 47 | 48 | char Food::Foo::ID = 0; 49 | static RegisterPass F1("Foo", "Pass demonstrating how to use FlipIt from inside of a pass"); 50 | 51 | -------------------------------------------------------------------------------- /examples/pass/Foo/main.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include 3 | #include "FlipIt/corrupt/corrupt.h" 4 | 5 | int work() { 6 | int a = 3; 7 | int x = rand()%100; 8 | 9 | return x*x + x + a; 10 | } 11 | 12 | void display() { 13 | printf("Hello, World! %d\n", work()); 14 | } 15 | 16 | int main(int argc, char** argv) { 17 | FLIPIT_Init(0, argc, argv, 0); 18 | display(); 19 | FLIPIT_Finalize(NULL); 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/pass/Foo/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##################################################################### 4 | # 5 | # This file is licensed under the University of Illinois/NCSA Open 6 | # Source License. See LICENSE.TXT for details. 7 | # 8 | ##################################################################### 9 | 10 | ##################################################################### 11 | # 12 | # Name: test.sh 13 | # 14 | # Description: Compiles main.c running the pass 'Foo' over the 15 | # LLVM IR which inturn called FlipIt to corrupt 16 | # certain instructions. 17 | # 18 | ##################################################################### 19 | 20 | echo " 21 | ############ COMPILING main.c ############ 22 | 23 | " 24 | $LLVM_BUILD_PATH/bin/clang -g -I$FLIPIT_PATH/include -emit-llvm -o main.bc -c main.c 25 | $LLVM_BUILD_PATH/bin/llvm-link $FLIPIT_PATH/src/corrupt/corrupt.bc main.bc -o crpt.bc 26 | $LLVM_BUILD_PATH/bin/opt -load ./libFooPass.so -Foo crpt.bc -o final.bc 27 | $LLVM_BUILD_PATH/bin/clang final.bc -L$FLIPIT_PATH/lib -lcorrupt 28 | 29 | echo " 30 | 31 | ############ RUNNING PROGRAM ############" 32 | ./a.out 33 | rm *.bc 34 | -------------------------------------------------------------------------------- /examples/pass/setupPassExample.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##################################################################### 4 | # 5 | # This file is licensed under the University of Illinois/NCSA Open 6 | # Source License. See LICENSE.TXT for details. 7 | # 8 | ##################################################################### 9 | 10 | ##################################################################### 11 | # 12 | # Name: setupPassExample.sh 13 | # 14 | # Description: Compiles the LLVM compiler pass Foo that calls Flipit 15 | # from inside the pass to corrupt certain instructions 16 | # and runs an example to demonstrate it works. 17 | # 18 | ##################################################################### 19 | 20 | cd $FLIPIT_PATH/scripts/ 21 | ./findLLVMHeaders.py $FLIPIT_PATH/examples/pass/Foo/foo.h 22 | cd $FLIPIT_PATH/examples/pass/Foo 23 | 24 | ./createPass.sh 25 | ./test.sh 26 | -------------------------------------------------------------------------------- /examples/seq/countdown/Makefile: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | # 3 | # Example that shows how to use the "flip-cc" compiler script. 4 | # In addition, it shows how to use the countdown timer for injection. 5 | # 6 | ##################################################################### 7 | 8 | CC=gcc 9 | CFLAGS = -g -I$(FLIPIT_PATH)/include 10 | 11 | FILIB= -L$(FLIPIT_PATH)/lib -lcorrupt 12 | FIPASS= $(FLIPIT_PATH)/lib/libFlipItPass.so 13 | LFLAGS = $(FILIB) 14 | 15 | long: matmul.o main.o 16 | $(CC) -o long matmul.o main.o $(LFLAGS) 17 | 18 | matmul.o: matmul.c 19 | $(LLVM_BUILD_PATH)/bin/clang -fPIC $(CFLAGS) -emit-llvm matmul.c -c -o matmul.bc 20 | $(LLVM_BUILD_PATH)/bin/llvm-link $(FLIPIT_PATH)/include/FlipIt/corrupt/corrupt.bc matmul.bc -o crpt_matmul.bc 21 | $(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 "" -stateFile "countdown" crpt_matmul.bc -o final.bc 22 | $(LLVM_BUILD_PATH)/bin/clang -fPIC -c final.bc -o matmul.o 23 | 24 | main.o: main.c 25 | $(CC) $(CFLAGS) -o main.o -c main.c 26 | 27 | 28 | 29 | short: _matmul.o _main.o 30 | $(CC) -o short _matmul.o _main.o $(LFLAGS) 31 | 32 | _matmul.o: matmul.c 33 | $(FLIPIT_PATH)/scripts/flipit-cc $(CFLAGS) -o _matmul.o -c matmul.c 34 | 35 | _main.o: main.c 36 | $(FLIPIT_PATH)/scripts/flipit-cc $(CFLAGS) -o _main.o -c main.c 37 | 38 | 39 | clean: 40 | rm -f *.bc 41 | rm -f *.o 42 | rm -f *.LLVM.bin 43 | rm -f *.pyc 44 | rm -f long 45 | rm -f short 46 | -------------------------------------------------------------------------------- /examples/seq/countdown/config.py: -------------------------------------------------------------------------------- 1 | ############### Injector Parameters ################## 2 | # 3 | # config - config file used by the compiler pass 4 | # funcList - list of functions that are faulty 5 | # prob - probability that instuction is faulty 6 | # byte - which byte is faulty (0-7) -1 random 7 | # singleInj - one injection per active rank (0 or 1) 8 | # ptr - add code to inject into pointers (0 or 1) 9 | # arith - add code to inject into mathematics (0 or 1) 10 | # ctrl - add code to inject into control (0 or 1) 11 | # stateFile - unique counter for fault site index; 12 | # should differ based on application 13 | # 14 | ##################################################### 15 | 16 | config = "matmul_countdown.config" 17 | funcList = "\"\"" 18 | prob = 1e-8 19 | byte = -1 20 | bit = -1 21 | ptr = 1 22 | arith = 1 23 | ctrl = 1 24 | stateFile = "countdown" 25 | 26 | ############# Library Parameters ##################### 27 | # 28 | # FLIPIT_PATH - Path to FlipIt repo 29 | # SHOW - libraries and path wraped by mpicc 30 | # 31 | ##################################################### 32 | import os 33 | FLIPIT_PATH = os.environ['FLIPIT_PATH'] 34 | LLVM_BUILD_PATH = os.environ['LLVM_BUILD_PATH'] 35 | SHOW = "" # not needed for this example (No MPI) 36 | CPP_LIB = "" # not needed for this example (C program) 37 | 38 | 39 | ########### Files to NOT inject inside ############### 40 | notInject = [" ", " "] 41 | 42 | ############ Default Compiler ################# 43 | cc = "gcc" 44 | 45 | ############ Verbose compiler output ############## 46 | verbose = False 47 | 48 | ############ Generate a histogram of fault site traversals ######### 49 | histogram = False 50 | -------------------------------------------------------------------------------- /examples/seq/countdown/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "matmul.h" 3 | #include "FlipIt/corrupt/corrupt.h" 4 | 5 | int main(int argc, char** argv) 6 | { 7 | int n = 100, numIncorrect = 0, seed = 533, i, j; 8 | double* a = (double*) malloc(n*n*sizeof(double)); 9 | double* b = (double*) malloc(n*n*sizeof(double)); 10 | double* c = (double*) malloc(n*n*sizeof(double)); 11 | double* c_golden = (double*) malloc(n*n*sizeof(double)); 12 | 13 | /* Initialize arrays */ 14 | for (i=0; i 2 | #include "matmul.h" 3 | #include "FlipIt/corrupt/corrupt.h" 4 | 5 | int main(int argc, char** argv) 6 | { 7 | int n = 100, numIncorrect = 0, seed = 533, i, j; 8 | double* a = (double*) malloc(n*n*sizeof(double)); 9 | double* b = (double*) malloc(n*n*sizeof(double)); 10 | double* c = (double*) malloc(n*n*sizeof(double)); 11 | double* c_golden = (double*) malloc(n*n*sizeof(double)); 12 | 13 | /* Initialize arrays */ 14 | for (i=0; i 11 | #include \"FlipIt/corrupt/corrupt.h\" 12 | 13 | int work(int a, int b); 14 | 15 | int main(int argc, char** argv) 16 | { 17 | int a = 2, b=2; 18 | int rank = 0; 19 | int seed = 7; 20 | FLIPIT_Init(rank, argc, argv, seed); 21 | printf(\"Should be corrupted: %d + %d = %d\n\", a, b, work(a, b)); 22 | FLIPIT_Finalize(NULL); 23 | return 0; 24 | }" > main.c 25 | 26 | echo "int work(int a, int b) 27 | { 28 | return a + b; 29 | }" > work.c 30 | 31 | 32 | # compile work.c 33 | $LLVM_BUILD_PATH/bin/clang -g -emit-llvm work.c -c -o work.bc 34 | $LLVM_BUILD_PATH/bin/llvm-link $FLIPIT_PATH/include/FlipIt/corrupt/corrupt.bc work.bc -o crpt_work.bc 35 | $LLVM_BUILD_PATH/bin/opt -load $FLIPIT_PATH/lib/libFlipItPass.so -FlipIt -srcFile "work.c" -singleInj 1 -prob 0.95 -byte -1 -bit 0 -arith 1 -ctrl 0 -ptr 0 -funcList "" crpt_work.bc -o final.bc 36 | $LLVM_BUILD_PATH/bin/clang -fPIC -g -c final.bc -o final.o 37 | 38 | # display the compiler log file for work.LLVM.txt 39 | python $FLIPIT_PATH/scripts/binary2ascii.py work.c.LLVM.bin -o work.c.LLVM.txt 40 | cat work.c.LLVM.txt 41 | 42 | # build the executable 43 | gcc -I$FLIPIT_PATH/include -o main.o -c main.c 44 | gcc -o test final.o main.o -L$FLIPIT_PATH/lib/ -lcorrupt 45 | ./test 46 | -------------------------------------------------------------------------------- /scripts/analysis/README: -------------------------------------------------------------------------------- 1 | Information 2 | ----------- 3 | 4 | Basic analysis scripts that combine injection site, source code, and runtime 5 | injection information to generate graphs about the fault injection campaign. 6 | The scripts read the compiler log files and run output files to store key 7 | information into a database that is used when visualizing the fault injection 8 | campaign. 9 | 10 | Such graphs include: 11 | - Classification of injections based on instruction type 12 | - Percent of injections based on function (includes type information 13 | - Signals generated 14 | - Trials with detection (includes bit locations and types) 15 | - Latency of detection 16 | - Trials that unexpectedly terminate (includes bit locations and types) 17 | 18 | The scripts are extensible with user defined functions placed in 'custom.py'. 19 | The user can collect information from the run output files being parsed, 20 | e.g. application progress, SDC detector performance, by extending the 21 | database's tables or creating their own, and visualize their data, or 22 | combine data that is already collected into new visualizations. 23 | 24 | 25 | 26 | 27 | Usage 28 | ----- 29 | 30 | These scripts depend on 'numpy', 'matplotlib', and 'sqlite3'. 31 | 32 | To use these scripts: 33 | 34 | 1.) modify 'analysis_config.py' 35 | 2.) python 'main.py' 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /scripts/analysis/analysis_config.py: -------------------------------------------------------------------------------- 1 | """Name of the database file on disk to visualize, or if it does not exist 2 | create it and populate with injection information 3 | """ 4 | database = "campaign.db" 5 | 6 | """Boolean that specifies if we should rebuild the database on each execution 7 | """ 8 | rebuild_database = True 9 | 10 | """Path to where the LLVM log files, (*.LLVM.bin), generated by FlipIt exist. 11 | 12 | Notes 13 | ---- 14 | analysis scripts recursilvely search this directory for the logs 15 | """ 16 | LLVM_log_path = "../llvm" 17 | 18 | """Determines what type of log files to look for and parse. 19 | 20 | Notes 21 | ---- 22 | Options are "Binary" or "ASCII" 23 | """ 24 | LLVM_log_type = "Binary" 25 | 26 | """Path to where the output files of the run(s) are stored. Each output file 27 | should a seperate fault injection run of the application. 28 | 29 | Notes 30 | ----- 31 | 1) assumes files from a fault injection campaign end in _# or _#.txt 32 | where # is the trial number e.g. foo_1 or foo_1.txt 33 | 2) stdout and stderr are in the same file 34 | 35 | See Also 36 | -------- 37 | migrate.py to suffix _# or _#.txt to existing run output files 38 | """ 39 | trial_path = "../trials" 40 | 41 | """Begining of the trial file name e.g. foo for trials foo_1 or foo_1.txt 42 | """ 43 | trial_prefix = "foo" 44 | 45 | """Path to source code. 46 | 47 | Notes 48 | ----- 49 | assumes stdout and stderr are in the same file 50 | """ 51 | srcPath = "../src/" 52 | 53 | """Number of fault injection trials to read 54 | """ 55 | numTrials = 100. 56 | 57 | """Names of functions that a more detailed analysis should be conducted for 58 | 59 | Notes 60 | ----- 61 | A more detailed analysis includes color coding source code based on 62 | injection frequency 63 | """ 64 | more_detail_funcs = ["foobar"] 65 | 66 | """Snipits of system generated messages. These SHOULD be changed based on 67 | your system 68 | """ 69 | busError = "exit signal Bus error" 70 | assertMessage = "Assertion" 71 | segError = "Sig 11" 72 | 73 | """Snipit of a detection message. This SHOULD be changed based on your 74 | detection scheme 75 | """ 76 | detectMessage = "Foo Check" 77 | 78 | """FlipIt Injection markers. You SHOULD NOT need to change these. 79 | """ 80 | bitMessage = "Bit position" 81 | siteMessage = "/*********************************Start**************************************/" 82 | siteEndMessage = "/*********************************End**************************************/" 83 | -------------------------------------------------------------------------------- /scripts/analysis/binaryParser.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | NEW_FILE_MASK = 0x8000 4 | currSize = 0 5 | def unpack(binary, fmt, size = None): 6 | """Reads a value from a binary file 'binary'. 7 | Parameters 8 | ---------- 9 | binary : open binary file 10 | open binary file to read from 11 | fmt : single character 12 | format code for the data type to read from the binary file 13 | size : int 14 | used when reading strings from the binary file as the size of the 15 | string that should be read 16 | """ 17 | 18 | global currSize 19 | value = None 20 | 21 | if fmt == 'B': 22 | #print len(binary) 23 | #print "reading byte[", currSize, "] = ", binary[currSize] 24 | #tmplue = struct.unpack(fmt, binary[currSize])[0] 25 | value = struct.unpack(fmt, bytes([binary[currSize]]))[0] 26 | #value = struct.unpack(fmt, binary[currSize])[0] 27 | currSize += 1 28 | elif fmt == 'H': 29 | value = struct.unpack(fmt, binary[currSize:currSize+2])[0] 30 | currSize += 2 31 | elif fmt == 'L': 32 | value = struct.unpack(fmt, binary[currSize:currSize+8])[0] 33 | currSize += 8 34 | elif fmt == 's': 35 | value = binary[currSize:currSize + size].decode("utf-8") 36 | currSize += size 37 | 38 | return value 39 | 40 | 41 | class INJ_TYPE: 42 | ARITHMETIC_FP = 0 43 | POINTER = 1 44 | ARITHMETIC_FIX = 2 45 | CONTROL_LOOP = 3 46 | CONTROL_BRANCH = 4 47 | UNKNOWN_INJ = 5 48 | 49 | 50 | class INJ_INFO_TYPE: 51 | RESULT = 0 52 | VALUE = RESULT 53 | ADDRESS = 1 54 | UNKNOWN_INJ_TYPE = 30 55 | 56 | class INST_TYPE: 57 | Unknown = 0 58 | 59 | # Terminator Instructions 60 | Ret = 1 61 | Br = 2 62 | Switch = 3 63 | IndirectBr = 4 64 | Invoke = 5 65 | Resume = 6 66 | Unreachable = 7 67 | 68 | # Standard binary operators... 69 | Add = 8 70 | FAdd = 9 71 | Sub = 10 72 | FSub = 11 73 | Mul = 12 74 | FMul = 13 75 | UDiv = 14 76 | SDiv = 15 77 | FDiv = 16 78 | URem = 17 79 | SRem = 18 80 | FRem = 19 81 | 82 | # Logical operators... 83 | Shl = 20 84 | LShr = 21 85 | Ashr = 22 86 | And = 23 87 | Or = 24 88 | Xor = 25 89 | 90 | #Memory operators... 91 | Alloca = 26 92 | Load = 27 93 | Store = 28 94 | GetElementPtr = 29 95 | Fence = 30 96 | AtomicCmpXchg = 31 97 | AtomicRMW = 32 98 | 99 | # Cast operators ... 100 | Truc = 33 101 | ZExt = 34 102 | SExt = 35 103 | FPToUI = 36 104 | FPToSI = 37 105 | UIToFP = 38 106 | SIToFP = 39 107 | FPTrunc = 40 108 | FPExt = 41 109 | PtrToInt = 42 110 | IntToPtr = 43 111 | BitCast = 44 112 | AddrSpaceCast = 45 113 | 114 | # Other operators... 115 | ICmp = 46 116 | FCmp = 47 117 | PHI = 48 118 | Call = 49 119 | Select = 50 120 | UserOp1 = 51 121 | UserOp2 = 52 122 | VAArg = 53 123 | ExtractElement = 54 124 | InsertElement = 55 125 | ShuffleVector = 56 126 | ExtractValue = 57 127 | InsertValue = 58 128 | LandingPad = 59 129 | 130 | INST_STR = ["Unknown", "Ret", "Br", "Switch", "IndirectBr", "Invoke", "Resume",\ 131 | "Unreachable", "Add", "FAdd", "Sub", "FSub", "Mul", "FMul", "UDiv", "SDiv",\ 132 | "FDiv", "URem", "SRem", "FRem", "Shl", "LShr", "Ashr", "And", "Or", "Xor", \ 133 | "Alloca", "Load", "Store", "GetElementPtr", "Fence", "AtomicCmpXchg", \ 134 | "AtomicRMW", "Truc", "ZExt", "SExt", "FPToUI", "FPToSI", "UIToFP", "SIToFP",\ 135 | "FPTrunc", "FPExt", "PtrToInt", "IntToPtr", "BitCast", "AddrSpaceCast", \ 136 | "ICmp", "FCmp", "PHI", "Call", "Select", "UserOp1", "UserOp2", "VAArg", \ 137 | "ExtractElement", "InsertElement", "ShuffleVector", "ExtractValue", \ 138 | "InsertValue", "LandingPad"] 139 | 140 | 141 | def info2Str(info, opstr): 142 | """Converts injection site info encoded as an integer into an ASCII string. 143 | Parameters 144 | ---------- 145 | info : int 146 | injection type incoded as an integer to express as a string 147 | opstr : string 148 | opcode string from the same fault site that 'info' comes from, and is 149 | used to better specify the injection 150 | """ 151 | 152 | if info == INJ_INFO_TYPE.RESULT: 153 | if opstr == "Store": 154 | return "Value" 155 | else: 156 | return "Result" 157 | elif info == INJ_INFO_TYPE.UNKNOWN_INJ_TYPE: 158 | return "Unknown" 159 | else: 160 | return "Arg " + str(info-1) 161 | 162 | 163 | def type2Str(ty): 164 | """Converts an injection type encoded as an integer into an ASCII string. 165 | Parameters 166 | ---------- 167 | ty : int 168 | injection type incoded as an integer to express as a string 169 | """ 170 | 171 | if ty == INJ_TYPE.ARITHMETIC_FP: 172 | return "Arith-FP" 173 | elif ty == INJ_TYPE.POINTER: 174 | return "Pointer" 175 | elif ty == INJ_TYPE.ARITHMETIC_FIX: 176 | return "Arith-Fix" 177 | elif ty == INJ_TYPE.CONTROL_LOOP: 178 | return "Control-Loop" 179 | elif ty == INJ_TYPE.CONTROL_BRANCH: 180 | return "Control-Branch" 181 | else: 182 | return "Unknown" 183 | 184 | def opcode2Str(opcode): 185 | """Converts an opcode into an ASCII string. 186 | Parameters 187 | ---------- 188 | opcode : int 189 | opcode to express as a string 190 | """ 191 | 192 | if opcode < len(INST_STR): 193 | return INST_STR[opcode] 194 | else: 195 | return INST_STR[0] 196 | 197 | 198 | def parseBinaryLogFile(c, filename, outfile = None): 199 | """Reads FLipIt LLVM log file and adds fault injection site 200 | information into the database. 201 | Parameters 202 | ---------- 203 | c : object 204 | sqlite3 database handle that is open to a valid filled database 205 | filename : str 206 | absolute name of the LLVM log file 207 | outfile : any 208 | if value is not 'None' then this function will write an ASCII 209 | version of the log file to disk with the name 'filename' but 210 | use the extension .txt 211 | """ 212 | 213 | global currSize 214 | currSize = 0 215 | if outfile != None: 216 | name = outfile 217 | if name == "": 218 | name = filename 219 | if name[-3:] == "bin": 220 | name = name[0:-3] + "txt" 221 | 222 | outfile = open(name, "w") 223 | with open(filename, "rb") as f: 224 | logfile = f.read() 225 | #print logfile 226 | fileVersion = unpack(logfile, 'B') 227 | nameSize = unpack(logfile, 'H') 228 | srcFile = unpack(logfile, 's', nameSize) 229 | siteIdx = 0 230 | funcName = "" 231 | 232 | 233 | if outfile != None: 234 | outfile.write("File Version #: "+ str(fileVersion)) 235 | outfile.write("\nFile Name: " + str(srcFile)) 236 | 237 | # loop over all functions and fault locations 238 | while currSize < len(logfile): # for rest of file 239 | #print "GET OPCODE" 240 | opcode = unpack(logfile, 'B') #read function header 241 | if opcode != 255: 242 | # opcode(1 byte), Types/Info(1 byte [3,5 bits]), Location (2+ bytes) 243 | info_type = unpack(logfile, 'B') 244 | ty = info_type >> 5 245 | info = info_type & 0x1F 246 | lineNum = unpack(logfile, 'H') 247 | comment = info2Str(info, opcode2Str(opcode)) 248 | #print "opcode= ", opcode, " info= ", info, " ty= ", ty, " lineNum= ", lineNum 249 | msg = "\n#" + str(siteIdx) + "\t" + opcode2Str(opcode) + "\t" + info2Str(info, opcode2Str(opcode))\ 250 | + "\t" + type2Str(ty) 251 | 252 | # if the MSB bit in lineNum is set then lineNum is the size of 253 | # a new filename string and we must read a new lineNum 254 | #print "AND=", lineNum & NEW_FILE_MASK 255 | if lineNum & NEW_FILE_MASK != 0: 256 | size = lineNum & 0x7FFF 257 | lineNum = unpack(logfile, 'H', 2) 258 | srcFile = unpack(logfile, 's', size) 259 | #print "size=", size, " new file: ", srcFile, ":", lineNum #unpack(logfile, 's', size & 0x7F) 260 | #else: 261 | # print "old file: ", srcFile, ":", lineNum 262 | msg += "\t" + srcFile + ":" + str(lineNum) 263 | if c != None: 264 | #print msg 265 | c.execute("INSERT INTO sites VALUES (?,?,?,?,?,?,?)", (siteIdx, type2Str(ty), comment, srcFile, funcName, lineNum, opcode)) 266 | if outfile != None: 267 | outfile.write(msg) 268 | siteIdx += 1 269 | else: # start of function 270 | size = unpack(logfile, 'B') 271 | funcName = unpack(logfile, 's', size) 272 | if outfile != None: 273 | #funcName = unpack(logfile, 's', size) 274 | outfile.write("\n\nFunction Name: " + funcName) 275 | outfile.write("\n------------------------------------------------------------------------------") 276 | #print funcName 277 | siteIdx = unpack(logfile, 'L') 278 | #print "Fault Site Idx: ", siteIdx 279 | #print currSize 280 | 281 | if outfile != None: 282 | outfile.write("\n") 283 | outfile.close() 284 | 285 | #parseBinaryLogFile("work.c.LLVM.bin", "OUT.c.LLVM.txt") 286 | #parseBinaryLogFile("/home/aperson40/research/compilerSDC/HPCCG-1.0/ddot.cpp.LLVM.bin", "DD.c.LLVM.txt") 287 | 288 | -------------------------------------------------------------------------------- /scripts/analysis/custom.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from matplotlib import pyplot as plot 3 | from analysis_config import * 4 | from visualize import * 5 | 6 | def customInit(c): 7 | """User defined function to initialize the fault injection campaign 8 | database. 9 | 10 | Parameters 11 | ---------- 12 | c : object 13 | sqlite3 database handle that is open to a valid filled database 14 | Notes 15 | ---------- 16 | Users will want to use this funcction to extend current tables or 17 | add there own tables to the data. 18 | 19 | Example 20 | ------- 21 | c.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='custom'") 22 | if len(c.fetchall()) == 0: 23 | c.execute("CREATE TABLE custom (trial int, site, iter int, rank int, level int, direction int)") 24 | c.execute("ALTER TABLE trials ADD COLUMN iter int") 25 | c.execute("ALTER TABLE trials ADD COLUMN converged int") 26 | """ 27 | 28 | def customParser(c, line, trial): 29 | """Parses the output of a fault injection trial for items interested to the user 30 | Parameters 31 | ---------- 32 | c : object 33 | sqlite3 database handle that is open to a valid filled database 34 | 35 | line : str 36 | Single line from the output file of a fault injection trial 37 | trial: int 38 | number of fault injection trial. obtained from filename 39 | Notes 40 | ---------- 41 | Users will want to fill out this function to parse both the custom 42 | injection log and any other lines such as detection messages or 43 | algorithm progress that may be visualized later. 44 | 45 | Example 46 | ------- 47 | if numIterationMessage in l: 48 | iter = int(l.split(" ")[-1]) 49 | c.execute("UPDATE trials SET iter = ? WHERE trials.trial = ?", (iter, trial)) 50 | if notConvergedMsg in l: 51 | c.execute("UPDATE trials SET converged = ? WHERE trials.trial = ?", (0,trial)) 52 | """ 53 | 54 | -------------------------------------------------------------------------------- /scripts/analysis/database.py: -------------------------------------------------------------------------------- 1 | import sqlite3, os, sys 2 | from analysis_config import * 3 | from binaryParser import * 4 | 5 | 6 | 7 | def init(db, LLVMPath, trialPath, customFuncs = None): 8 | """Sets up the fault injection campaign visualization database 9 | by reading log files generated by FlipIt and run output files 10 | containing injection information. 11 | Parameters 12 | ---------- 13 | db : str 14 | Path to an existing sqlite3 database or the name of a database to 15 | create. 16 | LLVMPath : str 17 | Path to where the LLVM log files (*.LLVM.txt) generated by FlipIt exist. 18 | trialPath : str 19 | Path to where the output files of the run(s) are stored. Each output file 20 | should a seperate fault injection run of the application. 21 | customFuncs : tuple of function pointers 22 | Tuple of customs parsing functions (initcustomparsing(), customparser()) 23 | 24 | Return 25 | --------- 26 | sqlite3 database connection handle that is open 27 | 28 | Notes 29 | ---------- 30 | Searched recursively in LLVMPath for log files. 31 | customFuncs can be None. In that case, no user parseing is done. 32 | """ 33 | 34 | if rebuild_database: 35 | os.system("rm -rf " + db) 36 | exists = os.path.isfile(db) 37 | conn = sqlite3.connect(db) 38 | c = conn.cursor() 39 | if customFuncs == None: 40 | customFuncs = (None, None) 41 | if not exists: 42 | createTables(c) 43 | if customFuncs[0] != None: 44 | customFuncs[0](c) 45 | readLLVM(c, LLVMPath) 46 | if customFuncs != None and len(customFuncs) == 2: 47 | readTrials(c, trialPath, customFuncs[1]) 48 | else: 49 | readTrials(c, trialPath) 50 | 51 | c.execute("SELECT name FROM sqlite_master WHERE type='table';") 52 | conn.commit() 53 | return c 54 | 55 | def createTables(c): 56 | """Add tables into the database need when parsing run output files 57 | Parameters 58 | ---------- 59 | c : object 60 | sqlite3 database handle that is open to a valid filled database 61 | """ 62 | c.execute("CREATE TABLE sites (site int, type text, comment text, file text, function text, line int, opcode text)") 63 | c.execute("CREATE TABLE trials (trial int, numInj int, crashed int, detection int, path text, signal int)") 64 | c.execute("CREATE TABLE injections (trial int, site int, rank int, prob double, bit int, cycle int, notes text)") 65 | c.execute("CREATE TABLE signals (trial int, num int)") 66 | c.execute("CREATE TABLE detections (trial int, latency int, detector text)") 67 | #c.execute("CREATE TABLE ()") 68 | 69 | 70 | def readLLVM(c, LLVMPath): 71 | """Searches through the directory structure and collect 72 | fault injection site information and add it to the database 73 | 74 | Parameters 75 | ---------- 76 | c : object 77 | sqlite3 database handle that is open to a valid filled database 78 | LLVMPath : str 79 | Path to where the LLVM log files (*.LLVM.bin) generated by FlipIt exist. 80 | """ 81 | print "\n\nReading LLVM log files:" 82 | end = "LLVM.bin" 83 | if LLVM_log_type == "ASCII": 84 | end = "LLVM.txt" 85 | for path, subdirs, files in os.walk(LLVMPath): 86 | for name in files: 87 | if str(name).endswith(end): 88 | print "\t", name 89 | if LLVM_log_type == "Binary": 90 | parseBinaryLogFile(c, os.path.join(path, name)) 91 | else: 92 | parseInjLog(c, path, name) 93 | 94 | 95 | def parseInjLog(c, path, file): 96 | """Reads FLipIt LLVM log file and adds fault injection site 97 | information into the database. 98 | Parameters 99 | ---------- 100 | c : object 101 | sqlite3 database handle that is open to a valid filled database 102 | path : str 103 | path to where the LLVM log file resides 104 | file : str 105 | name of the LLVM log file to read 106 | """ 107 | 108 | fullPath = os.path.join(path, file) 109 | rawlog = open(fullPath).readlines() 110 | funcName = "" 111 | 112 | for i in range(0, len(rawlog)): 113 | if "Function Name: " in rawlog[i]: 114 | funcName = rawlog[i].split(" ")[-1].strip() 115 | 116 | if rawlog[i][0] == "#": 117 | # break line: "#NUM TYPE TXT TXT" to grab NUM 118 | split = rawlog[i].split("\t") 119 | site = int( split[0][1:] ) 120 | type = split[1] 121 | comment = split[-2] 122 | line = split[-1] 123 | srcLine = 0 124 | 125 | # compiled with -g and we know the src line number 126 | if ":" in line: 127 | split = line.split(":") 128 | srcLine = int(split[-1]) 129 | file = split[0] 130 | c.execute("INSERT INTO sites VALUES (?,?,?,?,?,?,?)", (site, type, comment, file, funcName, srcLine, "Unknown")) 131 | 132 | 133 | def readTrials(c, filePrefix, customParser = None): 134 | """Parses an output file of a fault injection trial for injections, 135 | detections, and system level events such as raised signals. 136 | 137 | Parameters 138 | ---------- 139 | c : object 140 | sqlite3 database handle that is open to a valid filled database 141 | filePrefix : str 142 | path to a fault injection run output file including the first 143 | part of the file name 144 | customParser : function pointer 145 | function the user defines to allow for custom parsing of 146 | run output file 147 | """ 148 | print "\n\nReading trials with file prefix: ", filePrefix 149 | for trial in range(0, int(numTrials)): 150 | 151 | # determine if trial exists 152 | path = filePrefix + "_" + str(trial)#".txt" 153 | 154 | if not os.path.exists(path): 155 | path += ".txt" 156 | if not os.path.exists(path): 157 | continue 158 | print "\t", path 159 | 160 | # grab information about the injection(s) 161 | t = open(path).readlines() 162 | llvmInj = injCount = crashed = detected = signal = arithFP = 0 163 | 164 | c.execute("INSERT INTO trials(trial,path) VALUES (?,?)", (trial, path)) 165 | # look at certain lines in output 166 | i = 0 167 | while i < len(t): 168 | l = t[i] 169 | if siteMessage in l: 170 | injCount += 1 171 | inj = [] 172 | i += 1 173 | l = t[i] 174 | while siteEndMessage not in l: 175 | if l != "\n": 176 | inj.append(l.split(" ")) 177 | i += 1 178 | l = t[i] 179 | 180 | # grab info stored in 'inj' 181 | arithFP = 0 182 | if "IEEE" in " ".join(inj[0]): 183 | arithFP = 1 184 | rank = int(inj[1][-1]) 185 | bit = int(inj[3][-1]) 186 | site = int(inj[4][-1]) 187 | prob = float(inj[5][-1]) 188 | c.execute("SELECT * FROM sites WHERE site=?", (site,)) 189 | result = c.fetchone() 190 | if result == None: 191 | print "Unable to locate site #", site, " in database" 192 | sys.exit(1) 193 | ty = result[1] 194 | if "Arith" in ty: 195 | if arithFP == 1: 196 | ty = "Arith-FP" 197 | else: 198 | ty = "Arith-Fix" 199 | c.execute("UPDATE sites SET type = ? WHERE site=?", (ty,site)) 200 | llvmInj = int(inj[7][-1]) 201 | dynCycle = llvmInj 202 | c.execute("INSERT INTO injections VALUES (?,?,?,?,?,?,?)", (trial, site, rank, prob, bit, dynCycle, 'NULL')) 203 | 204 | for j in range(8, len(inj)): 205 | customParser(c, " ".join(inj[j]), trial) 206 | 207 | 208 | if detectMessage in l: 209 | detected = True 210 | c.execute("SELECT * FROM DETECTIONS WHERE trial = ?", (trial,)) 211 | if c.fetchall() == []: 212 | c.execute("INSERT INTO detections VALUES (?,?,?)", (trial, -1, "---")) 213 | 214 | if assertMessage in l: 215 | signal = True 216 | crashed = True 217 | c.execute("INSERT INTO signals VALUES (?,?)", (trial, 6)) 218 | 219 | if busError in l: 220 | signal = True 221 | crashed = True 222 | c.execute("INSERT INTO signals VALUES (?,?)", (trial, 10)) 223 | 224 | if segError in l: 225 | signal = True 226 | crashed = True 227 | c.execute("INSERT INTO signals VALUES (?,?)", (trial, 11)) 228 | 229 | if customParser != None: 230 | customParser(c, l, trial) 231 | 232 | i += 1 233 | c.execute("UPDATE trials SET numInj=? WHERE trials.trial=?", (injCount, trial)) 234 | c.execute("UPDATE trials SET crashed=? WHERE trials.trial=?", (crashed, trial)) 235 | c.execute("UPDATE trials SET detection=? WHERE trials.trial=?", (detected, trial)) 236 | c.execute("UPDATE trials SET signal=? WHERE trials.trial=?", (signal, trial)) 237 | 238 | def finalize(): 239 | """Cleans up fault injection visualization 240 | """ 241 | print "Finalizing fault injection visualization..." 242 | #conn.commit() 243 | #conn.close() 244 | -------------------------------------------------------------------------------- /scripts/analysis/main.py: -------------------------------------------------------------------------------- 1 | from matplotlib import pyplot as plot 2 | from database import init, finalize 3 | from visualize import initVis, visClassifications, visFunctions, visCrashes,\ 4 | visSignals, visDetections, visDetectedInjections, visDetectionLatency 5 | from custom import customInit, customParser 6 | #import analysis_config 7 | from analysis_config import * 8 | 9 | def visualize (c, more_detail_funcs = None): 10 | """Driver function to visulize a fault injection campaign. 11 | Parameters 12 | ---------- 13 | c : object 14 | sqlite3 database handle that is open to a valid filled database 15 | 16 | more_detail_funcs : list of str 17 | function names to generate extra analysis of injections inside them 18 | Notes 19 | ---------- 20 | Allows for user custom visualzations after first 'plot.show()' 21 | """ 22 | initVis(c) 23 | visClassifications(c, more_detail_funcs) 24 | visFunctions(c, more_detail_funcs) 25 | visCrashes(c) 26 | visSignals(c) 27 | visDetections(c, more_detail_funcs) 28 | visDetectedInjections(c) 29 | visDetectionLatency(c) 30 | plot.show() 31 | 32 | # add custom plotting function below 33 | plot.show() 34 | 35 | 36 | if __name__ == "__main__": 37 | c = init(database, LLVM_log_path, trial_path +"/"+ trial_prefix,\ 38 | customFuncs=(customInit, customParser)) 39 | visualize(c, more_detail_funcs) 40 | finalize() 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /scripts/analysis/migrate.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | """Converts run output files to the formate expected by the flipit analysis 5 | scripts 6 | 7 | Parameters 8 | argv[1] : str 9 | file prefix of the run files to look for e.g. foo for run outfiles 10 | such as foo.oe139493 11 | argv[2] : str 12 | path to where the run files are located 13 | 14 | Notes 15 | ----- 16 | Keeps the original run ouput files. 17 | Places the newly generated run output files in the same directory 18 | as the orginals. 19 | """ 20 | # usage: python migrate.py 21 | # e.g. python migrate.py faultInjectionTrial /path/to/run/files/ 22 | if __name__ == '__main__': 23 | prefix = sys.argv[1] 24 | path = sys.argv[2] 25 | files = [] 26 | 27 | # cache all the file names 28 | for p, s, f in os.walk(path): 29 | for name in f: 30 | if prefix in name: 31 | print "Adding ", name, len(files) 32 | files.append(name) 33 | 34 | #order the file names and then append the trial number 35 | files.sort() 36 | for i in xrange(0, len(files): 37 | os.system("cp " + path + "/" + f + " " + path +"/" + prefix + "_" + str(i)) 38 | -------------------------------------------------------------------------------- /scripts/analysis/visualize.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | from matplotlib import pyplot as plot 3 | import numpy as np 4 | import matplotlib 5 | from analysis_config import * 6 | 7 | 8 | numFigs = 0 9 | numTrials = 0 10 | numTrialsInj = 0 11 | colors = ['g','b', 'y', 'm', 'c', 'r'] 12 | TYPES = ["Arith-FP", "Pointer", "Arith-Fix", "Ctrl-Loop", "Ctrl-Branch"] 13 | TYPES_LONG = ["Floating-Point", "Pointer", "Fixed-Point", "Control-Loop", "Control-Branch"] 14 | typeIdx= {"Arith-FP":0, "Arithmetic":0, "Control": 6, "Pointer":1, "Arith-Fix":2, "Control-Loop":3, "Control-Branch":4} 15 | nClassifications = len(TYPES) 16 | 17 | def initVis(c): 18 | """Perform database operations to cache some values needed in later 19 | analysis. 20 | Parameters 21 | ---------- 22 | c : object 23 | sqlite3 database handle that is open to a valid filled database 24 | """ 25 | 26 | global numTrialsInj, numTrials 27 | c.execute("SELECT * FROM trials WHERE trials.numInj > 0") 28 | numTrialsInj = 1. * len(c.fetchall()) 29 | c.execute("SELECT * FROM trials") 30 | numTrials = 1. * len(c.fetchall()) 31 | if numTrialsInj == 0: 32 | print "No injections found to visualize..." 33 | sys.exit(1) 34 | print "Visualizing ", numTrials, " fault injection trials ("\ 35 | , numTrialsInj,") with faults" 36 | 37 | # wrapper around creating a pie chart 38 | def barchart(bins, values, xlabel, ylabel, title, name=None, ticks=None): 39 | """Wapper around the matplotlib bar function. Useful when we need bars 40 | from multiple trends. 41 | 42 | Parameters 43 | ---------- 44 | bins : np.array 45 | x values of where the bars should reside 1-D array 46 | values : np.array 47 | heights of the bars 2-D array [# trends][ len(bins)] 48 | xlabel : str 49 | label to display on the x axis 50 | ylabel : str 51 | label to display on the y axis 52 | title : str 53 | title of the figure 54 | name : list str 55 | trend names of length len(values) # trends 56 | ticks : list str 57 | x axis ticks to display of length len(bins) 58 | 59 | See Also 60 | ---------- 61 | histo() 62 | """ 63 | global numFigs 64 | plot.figure(numFigs) 65 | width = 1./len(values) 66 | if name == None: 67 | name = ["" for i in xrange(len(values))] 68 | for set in range(0, len(values)): 69 | plot.bar(bins+width*set, values[set][:], width, label=name[set], color=colors[set]) 70 | plot.xlabel(xlabel) 71 | plot.ylabel(ylabel) 72 | plot.legend(fancybox = True, shadow=True) 73 | if ticks != None: 74 | plot.xticks(bins+.5, ticks, rotation=60) 75 | plot.title(title) 76 | plot.tight_layout() 77 | numFigs += 1 78 | 79 | def piechart(percents, labels, title): 80 | """Wrapper around the matplotlib function pie 81 | 82 | Parameters 83 | ---------- 84 | percents : array like 85 | values to plot as percentages 86 | labels : list of str 87 | trend names corresponding to the percentages in percents 88 | title : str 89 | title of the pie chart 90 | """ 91 | 92 | global numFigs 93 | plot.figure(numFigs) 94 | patches, texts, autotexts = plot.pie(percents, labels=labels, autopct='%1.1f%%', colors=colors) 95 | for i in range(0, len(autotexts)): 96 | autotexts[i].set_color('w') 97 | autotexts[i].set_weight('bold') 98 | #autotexts[i].set_fontsize(16) 99 | plot.title(title) 100 | ax = plot.axis() 101 | v = (ax[0] - (ax[1] - ax[0])/4., ax[1] + (ax[1] - ax[0])/4., ax[2], ax[3]) 102 | plot.axis(v) 103 | plot.tight_layout() 104 | numFigs += 1 105 | 106 | def histo(values, bins, xlabel, ylabel, title, ticks=None, label=None, c=None): 107 | """Wrapper around the matplotlib function bar. Useful for a single trend 108 | 109 | Parameters 110 | ---------- 111 | values : array like 112 | heights of the bars 1-D 113 | bins : array like 114 | x values of where the bars should reside 1-D array 115 | xlabel : str 116 | label to display on the x axis 117 | ylabel : str 118 | label to display on the y axis 119 | title : str 120 | title of the figure 121 | ticks : list str 122 | x axis ticks to display of length len(bins) 123 | label : list str 124 | trend name of the data being graphed 125 | c : char 126 | color of the trend 127 | 128 | See Also 129 | --------- 130 | barchart 131 | """ 132 | global numFigs 133 | fig = plot.figure(numFigs) 134 | width = .8 135 | if c != None and label != None: 136 | plot.bar(bins, values, width, align ='center', label=label, color=c) 137 | else: 138 | plot.bar(bins, values, width, align = 'center') 139 | plot.xlabel(xlabel) 140 | plot.ylabel(ylabel) 141 | if ticks != None: 142 | plot.xticks(bins, ticks, rotation=60) 143 | #plot.xticks(bins+.5, ticks, rotation=60) 144 | plot.legend(loc='upper left',fancybox = True, shadow=True) 145 | plot.title(title) 146 | plot.tight_layout() 147 | numFigs += 1 148 | 149 | def visClassifications(c, moreDetail=None): 150 | """Graphs of what types of faults were injected. Classification based 151 | on FlipIt classification. 152 | 153 | Parameters 154 | ---------- 155 | c : object 156 | sqlite3 database handle that is open to a valid filled database 157 | moreDetail : list of str 158 | function names to generate extra analysis of injections inside them 159 | Notes 160 | ---------- 161 | More detail currently not implimented. 162 | """ 163 | typeBuckets = np.zeros(nClassifications + 1) 164 | bits = np.zeros((nClassifications, 64)) 165 | c.execute("SELECT site, bit FROM injections") 166 | injs = c.fetchall() 167 | if len(injs) == 0: 168 | print "Error in visClassifications: No Injections\n" 169 | return 170 | maximum = max(injs)[0] +1 171 | locs = np.zeros((nClassifications, maximum)) 172 | 173 | c.execute("SELECT type FROM sites INNER JOIN injections ON sites.site = injections.site") 174 | types = c.fetchall() 175 | 176 | for i in range(len(injs)): 177 | type = types[i][0] 178 | site = injs[i][0] 179 | bit = injs[i][1] 180 | #print type 181 | #print typeIdx 182 | if type in typeIdx: 183 | idx = typeIdx[type] 184 | if idx == 6: 185 | print "Warning: mapping type (", type,\ 186 | ") to type ( Control-Branch )" 187 | idx = 4 188 | typeBuckets[idx] += 1 189 | locs[idx][site] += 1 190 | bits[idx][bit] += 1 191 | else: 192 | print "VIZ: not classified = ", i 193 | typeBuckets[nClassifications] += 1 194 | fracs = typeBuckets/np.sum(typeBuckets) 195 | piechart(fracs[0:-1], TYPES_LONG, "Classification of Injections Based on Type") 196 | barchart(np.linspace(0,64,num=64), bits, "Bit Location", "Frequency", "Injected bit", TYPES) 197 | plot.xlim((0,64)) 198 | 199 | 200 | 201 | 202 | def visFunctions(c, moreDetail=None): 203 | """Graphs percentages of what functions faults were injection into 204 | 205 | Parameters 206 | ---------- 207 | c : object 208 | sqlite3 database handle that is open to a valid filled database 209 | moreDetail : list of str 210 | function names to generate extra analysis of injections inside them 211 | """ 212 | global numFigs 213 | c.execute("SELECT DISTINCT function FROM sites INNER JOIN injections ON injections.site = sites.site") 214 | funcs = c.fetchall() 215 | values = [] 216 | for i in funcs: 217 | c.execute("SELECT COUNT(trial) FROM injections INNER JOIN sites ON sites.site = injections.site AND sites.function = ?", i) 218 | values.append(1. * c.fetchone()[0]) 219 | piechart(np.array(values)/sum(values), [i[0] for i in funcs], "Injected Functions") 220 | 221 | ind = 0 222 | width = .5 223 | fig = plot.figure(numFigs) 224 | ax = plot.subplot(111) 225 | for i in funcs: 226 | i = i[0] 227 | c.execute("SELECT type FROM sites INNER JOIN injections ON sites.site = injections.site AND sites.function = ?", (i,)) 228 | types = c.fetchall() 229 | 230 | tot = float(len(types)) 231 | per = np.zeros(nClassifications) 232 | per = [ 0 for i in xrange(nClassifications)] 233 | for t in types: 234 | #per[typeIdx[t[0]]] += 1. 235 | idx = typeIdx[t[0]] 236 | if idx == 6: 237 | print "Warning: mapping type ( Control ) to type "\ 238 | "( Control-Branch )" 239 | idx = 4 240 | per[idx] += 1 241 | per = np.array(per)/tot * 100 242 | btm = 0 243 | legend = [] 244 | for t in xrange(0,nClassifications): 245 | p1 = ax.bar(ind, per[t], width, align='center', color=colors[t], bottom=btm) 246 | btm += per[t] 247 | legend.append(p1) 248 | ind += 1 249 | ax.set_xticks(np.arange(len(funcs))) 250 | ax.set_xticklabels([f[0] for f in funcs], rotation=60, ha='center') 251 | numFigs += 1 252 | 253 | ax.set_ylim((0,100)) 254 | ax.set_ylabel("Percent") 255 | 256 | # shrink graph to add legend and title at top 257 | plot.tight_layout() 258 | box = ax.get_position() 259 | ax.set_position([box.x0, box.y0, 260 | box.width, box.height * 0.8]) 261 | ax.legend(legend, TYPES, loc='upper center', bbox_to_anchor=(0.5, 1.15), 262 | fancybox=True, shadow=True, ncol=5) 263 | plot.setp(plot.gca().get_legend().get_texts(), fontsize='x-small') 264 | plot.text(0.5, 1.15, "Breakdown of Injection Type per Function", 265 | horizontalalignment='center', fontsize=14, transform = ax.transAxes) 266 | 267 | # more detail for a function creates an html file with the source 268 | # code colored based on injection percentatge 269 | if moreDetail != None: 270 | visInjectionsInCode(c, moreDetail) 271 | 272 | def visInjectionsInCode(c, functions): 273 | """Creates an html file with the source code colored based on injection 274 | percentages 275 | 276 | Parameters 277 | ---------- 278 | c : object 279 | sqlite3 database handle that is open to a valid filled database 280 | functions : list of str 281 | function names to generate extra analysis of injections inside them 282 | """ 283 | outfile = open("more.html", 'w') 284 | outfile.write("\n\n\n") 285 | for func in functions: 286 | # grab all injections in this function 287 | c.execute("SELECT file, line FROM sites INNER JOIN injections ON sites.site = injections.site AND sites.function = ?", (func,)) 288 | result = c.fetchall() 289 | if len(result) == 0: 290 | print "Warning (visInjectionsInCode): no injections in target function -- ", func 291 | continue 292 | 293 | # locate the min and max source line num to shrink output file size 294 | # we only want to show the section of code that we inject in 295 | lines = [i[1] for i in result] 296 | file = result[0][0] 297 | if ".LLVM.txt" in file: 298 | file = result[-1][0] 299 | minimum = np.min(lines)-1 300 | minimum = minimum if minimum >= 0 else 0 301 | maximum = np.max(lines)+1 302 | bins = np.arange(minimum, maximum+1) 303 | values, bins = np.histogram(lines, bins, density=False) # <------------ check here 304 | bins = np.arange(minimum, maximum) 305 | values = 1.*values/np.sum(values)*100 # percents 306 | histo(values, bins, "Source Line Number", "Percent",\ 307 | "Injections mapped to source line numbers for function: " + func) 308 | 309 | outfile.write("

" + func + "()

\n\n") 310 | if minimum == 0: 311 | outfile.write("Unable to assign " + str(values[0]) + "\% of injections to source code.\n") 312 | minimum = np.min(np.trim_zeros(lines)) - 1 313 | values = values[minimum:] 314 | outfile.write("
\n") 315 | if os.path.isfile(file): 316 | srcPath = "" 317 | if not os.path.isfile(srcPath+file): 318 | print "Warning (visInjectionsInCode): source file not found -- ", srcPath + file 319 | continue 320 | print "\nRelating injections to source code in file: ", srcPath+file 321 | FILE = open(srcPath+file, "r") 322 | function = FILE.readlines()[minimum:maximum] 323 | FILE.close() 324 | 325 | 326 | for i in range(1,len(function)): 327 | color = "bgcolor=\"" + getColor(values[i]) +"\"" 328 | outfile.write("\n\n\n\n\n") 331 | outfile.write("
"+ str(minimum+i) +\ 329 | "" + str2html(function[i-1]) + ""\ 330 | + str(values[i]) + "
\n") 332 | 333 | outfile.write("\n\n") 334 | outfile.close() 335 | 336 | def str2html(s): 337 | """Replaces '<', '>', and '&' with html equlivants 338 | 339 | Parameters 340 | ---------- 341 | s : str 342 | string to convert to a vaild html string to display properly 343 | """ 344 | return s.replace("&", "&").replace(">", ">").replace("<", "<") 345 | 346 | def getColor(x): 347 | """Selects an html color based on 0 <= x <= 100 348 | 349 | Parameters 350 | ---------- 351 | x : float 352 | percent of injection to color visually. Higher the percent the darker 353 | the color 354 | Returns 355 | ---------- 356 | html color name useful for classifying 357 | """ 358 | if x >= 75: 359 | return "red" 360 | elif x >= 50: 361 | return "orange" 362 | elif x >= 25: 363 | return "yellow" 364 | elif x >= 5: 365 | return "lime" 366 | else: 367 | return "white" 368 | 369 | 370 | # graphs percentage of trials that crashed 371 | def visCrashes(c): 372 | """Graph percentage of trials that crashed, and bit location and type 373 | of the corresponding injection 374 | 375 | Parameters 376 | ---------- 377 | c : object 378 | sqlite3 database handle that is open to a valid filled database 379 | 380 | Notes 381 | ---------- 382 | Only considers trials with injections when calculating percentages 383 | """ 384 | 385 | bits = np.zeros((nClassifications, 64)) 386 | c.execute("SELECT type FROM sites INNER JOIN injections ON sites.site = injections.site INNER JOIN trials ON trials.trial = injections.trial AND trials.crashed = 1") 387 | crash = c.fetchall() 388 | crashed = float(len(crash)) 389 | c.execute("SELECT site, bit FROM injections INNER JOIN trials ON injections.trial = trials.trial AND trials.crashed = 1") 390 | sitesBits = c.fetchall() 391 | for i in range(len(sitesBits)): 392 | type = crash[i][0] 393 | bit = sitesBits[i][1] 394 | #bits[typeIdx[type]][bit] += 1 395 | idx = typeIdx[type] 396 | if idx == 6: 397 | print "Warning: mapping type ( Control ) to type "\ 398 | "( Control-Branch )" 399 | idx = 4 400 | bits[idx][bit] += 1 401 | 402 | piechart([(numTrialsInj - crashed)/numTrialsInj, crashed/numTrialsInj],\ 403 | ["Didn't Crash", "Crashed"], "Unexpected Termination") 404 | barchart(np.linspace(0,64,num=64), bits, "Bit Location", "Frequency", "Unexpected Termination: Injected bit", TYPES) 405 | plot.legend(loc='upper left', fancybox = True, shadow=True) 406 | plot.xlim((0,64)) 407 | 408 | for i in range(nClassifications): 409 | if np.sum(bits[i][:]) > 0: 410 | histo(bits[i][:], np.linspace(0, 64, num=64), "Bit Location", "Frequency", "Unexpected Termination", None, TYPES[i], colors[i]) 411 | plot.xlim((0,64)) 412 | #plot.legend('upper left') 413 | 414 | # graphs percent of trials that threw at least 1 assert 415 | def visAsserts(c): 416 | """Graphs percent of trials that threw at least 1 assert 417 | 418 | Parameters 419 | ---------- 420 | c : object 421 | sqlite3 database handle that is open to a valid filled database 422 | Notes 423 | ---------- 424 | Only considers trials with injections when calculating percentages 425 | """ 426 | c.execute("SELECT DISTINCT trial from signal WHERE num == 6") 427 | asserts = len(c.fetchall()) 428 | piechart([asserts/numTrialsInj, (numTrials - asserts)/numTrialsInj],\ 429 | ["Failed Assert(s)", "Didn't Assert"], "Trials with Injections Asserting") 430 | 431 | # graphs percent of trials that generated at a certian signal type that is reported in the output file 432 | def visSignals(c): 433 | """Graphs the percent of trials that generated a certian signal type 434 | reported in the output file 435 | 436 | Parameters 437 | ---------- 438 | c : object 439 | sqlite3 database handle that is open to a valid filled database 440 | 441 | Notes 442 | ---------- 443 | If a trial generates multiple signals, e.g. each rank asserts, we regard 444 | this as a single signal for the trial. 445 | """ 446 | numSigs = 0. 447 | sigs = {} 448 | 449 | c.execute("SELECT DISTINCT trial, num FROM signals") 450 | #build histogram for what signals were raised 451 | signals = c.fetchall() 452 | for pair in signals: 453 | s = pair[1] 454 | numSigs += 1 455 | if s in sigs:# and s != 11: 456 | sigs[s] += 1 457 | else: 458 | sigs[s] = 1. 459 | 460 | fracs = [(numTrials - numSigs)/numTrialsInj] 461 | labels = ["No Signal"] 462 | for s in sigs: 463 | fracs.append(sigs[s]/numTrialsInj) 464 | labels.append("Signal " + str(s)) 465 | c.execute("SELECT DISTINCT trial from signals") 466 | unique = len(c.fetchall()) 467 | piechart(fracs, labels, str(unique) + " Trials Signaling") 468 | 469 | def visDetections(c, moreDetail=None): 470 | """Graphs the percentage of trials that generate detection 471 | 472 | Parameters 473 | ---------- 474 | c : object 475 | sqlite3 database handle that is open to a valid filled database 476 | moreDetail : list of str 477 | function names to generate extra analysis of detections inside them 478 | Notes 479 | ---------- 480 | Assumes one injection per trial. 481 | TODO: add graphs for more detail option 482 | """ 483 | #if moreDetail != None: 484 | # print "TODO: implement more detail option for 'visDetections'" 485 | c.execute("SELECT COUNT(trial) FROM trials WHERE detection = 1") 486 | detected = float(c.fetchone()[0]) 487 | c.execute("SELECT SUM(numInj) FROM trials") 488 | numInj = float(c.fetchone()[0]) 489 | 490 | piechart([detected/numInj, (numInj - detected)/numInj],\ 491 | ["Detected", "Didn't Detect"], "Number of Trials with Detection ("+str(detected)+")") 492 | 493 | 494 | def visDetectedInjections(c, moreDetail=None): 495 | """Graphs bit locations and type of what injections were detected 496 | 497 | Parameters 498 | ---------- 499 | c : object 500 | sqlite3 database handle that is open to a valid filled database 501 | 502 | moreDetail : list of str 503 | function names to generate extra analysis of detections inside them 504 | Notes 505 | ---------- 506 | TODO: add graphs for more detail option 507 | TODO: visualize injection sites detected 508 | TODO: visualize injection types detected 509 | Allows for user custom visualzations after first 'plot.show()' 510 | """ 511 | #if moreDetail != None: 512 | # print "TODO: implement more detail option for 'visDetectedInjections'" 513 | bits = np.zeros((nClassifications,64)) 514 | c.execute("SELECT site, bit FROM injections INNER JOIN trials ON injections.trial = trials.trial AND trials.detection = 1") 515 | injs = c.fetchall() 516 | c.execute("SELECT type FROM sites INNER JOIN injections ON sites.site = injections.site INNER JOIN trials ON injections.trial = trials.trial AND trials.detection = 1") 517 | types = c.fetchall() 518 | 519 | for i in range(len(injs)): 520 | type = types[i][0] 521 | site = injs[i][0] 522 | bit = injs[i][1] 523 | #bits[typeIdx[type]][bit] += 1 524 | idx = typeIdx[type] 525 | if idx == 6: 526 | print "Warning: mapping type ( Control ) to type "\ 527 | "( Control-Branch )" 528 | idx = 4 529 | bits[idx][bit] += 1 530 | 531 | barchart(np.linspace(0,64,num=64), bits, "Injected bit", "Frequency", "Detected Injection Bit Location", TYPES) 532 | plot.xlim((0,64)) 533 | 534 | 535 | 536 | def visDetectionLatency(c): 537 | """Visualizes the detection latency of an injection in the form of 538 | a bar chart with the x-axis as number of instruction executed after 539 | injection. 540 | 541 | Parameters 542 | ---------- 543 | c : object 544 | sqlite3 database handle that is open to a valid filled database 545 | 546 | Notes 547 | ---------- 548 | Assumes the user modifed the latency value in the detections table. It can 549 | be calucated by the 550 | 'LLVM_dynamic_inst_of_detection - LLVM_dynamic_inst_of_injection'. 551 | The later can be obtained from the injection table for the trial, and the 552 | former can be obtained at detection time though the FlipIt API call 553 | 'FLIPIT_GetDynInstCount()'. 554 | """ 555 | #TODO: Extend to look at latency for each detector 556 | c.execute("SELECT latency FROM detections") 557 | 558 | buckets = [-1, 0, 1, 2, 3, 4, 5, 10, 1e2, 1e3, 1e9, 1e13] 559 | data = [ i[0] for i in c.fetchall()] 560 | values, bins = np.histogram(data, buckets, normed=False) 561 | xlabel = "# of instrumented LLVM instructions till detection" 562 | ylabel = "Frequency" 563 | title = "Detection Latency" 564 | ticks = ["-1", "0", "1", "2", "3", "4", "5->", "10->", "1e2->", "1e3->", "1e9->"] 565 | bins = np.arange(0,11) 566 | histo(values, bins, xlabel, ylabel, title, ticks) 567 | 568 | -------------------------------------------------------------------------------- /scripts/binary2ascii.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ##################################################################### 3 | # 4 | # This file is licensed under the University of Illinois/NCSA Open 5 | # Source License. See LICENSE.TXT for details. 6 | # 7 | ##################################################################### 8 | 9 | ##################################################################### 10 | # 11 | # Name: binary2ascii.py 12 | # 13 | # Description: Converts a binary log file into a human readable ASCII 14 | # format. You can use the -o argument to change the output file 15 | # name from foo.LLVM.txt to a user provied name. 16 | # 17 | # e.g. binary2ascii.py foo.LLVM.bin -o bar.LLVM.txt 18 | # 19 | ##################################################################### 20 | 21 | import sys 22 | import os 23 | 24 | # get binary parsing functions from the analysis scripts 25 | FLIPIT_PATH = os.environ['FLIPIT_PATH'] 26 | sys.path.insert(0, FLIPIT_PATH + "/scripts/analysis") 27 | from binaryParser import * 28 | 29 | #parse arguments 30 | outfile = "" 31 | if "-o" in sys.argv: 32 | idx = sys.argv.index("-o") 33 | if idx+1 >= len(sys.argv): 34 | print ("Unknown output file name.") 35 | sys.exit(1) 36 | outfile = sys.argv[idx + 1] 37 | 38 | infile = sys.argv[1] 39 | if not os.path.isfile(infile): 40 | print ("File not found", infile) 41 | sys.exit(1) 42 | 43 | parseBinaryLogFile(None, infile, outfile) 44 | -------------------------------------------------------------------------------- /scripts/config.py: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | # 3 | # This file is licensed under the University of Illinois/NCSA Open 4 | # Source License. See LICENSE.TXT for details. 5 | # 6 | ##################################################################### 7 | 8 | ##################################################################### 9 | # 10 | # Name: config.py 11 | # 12 | # Description: Default configuration file that is read by flipit-cc 13 | # flipit-cc will look in the cwd when compiling for this 14 | # file, and if not found it will use the one in the 15 | # FlipIt repo. 16 | # 17 | ##################################################################### 18 | 19 | ############ LLVM BUILD TYPE ################ 20 | BUILD_TYPE = "Debug+Asserts" 21 | #BUILD_TYPE = "Release+Asserts" 22 | 23 | ############### Injector Parameters ################## 24 | # 25 | # config - config file used by the compiler pass 26 | # funcList - list of functions that are faulty 27 | # prob - probability that instuction is faulty 28 | # byte - which byte is faulty (0-7) -1 random 29 | # singleInj - one injection per active rank (0 or 1) 30 | # ptr - add code to inject into pointers (0 or 1) 31 | # arith - add code to inject into mathematics (0 or 1) 32 | # ctrl - add code to inject into control (0 or 1) 33 | # stateFile - unique counter for fault site index; 34 | # should differ based on application 35 | # 36 | ##################################################### 37 | config = "FlipIt.config" 38 | funcList = "\"\"" 39 | prob = 1e-8 40 | byte = -1 41 | bit = -1 42 | ptr = 1 43 | arith = 1 44 | ctrl = 1 45 | stateFile = "FlipItState" 46 | 47 | ############# Library Parameters ##################### 48 | # 49 | # FLIPIT_PATH - Path to FlipIt repo 50 | # LLVM_BULID_PATH - Path to LLVM build directory 51 | # SHOW - libraries and paths wraped by mpicc 52 | # 53 | ##################################################### 54 | 55 | import os 56 | FLIPIT_PATH = os.environ['FLIPIT_PATH'] 57 | LLVM_BUILD_PATH = os.environ['LLVM_BUILD_PATH'] 58 | SHOW = "" 59 | CPP_LIB = " -ldl -L/usr/lib/ -lm -lstdc++ " 60 | 61 | ########### Files to NOT inject inside ############### 62 | notInject = [" ", " "] 63 | 64 | ############ Default Compiler ######################## 65 | cc = "mpicc" 66 | 67 | ############ Verbose compiler output ################ 68 | verbose = True 69 | 70 | ############ Generate a histogram of fault site traversals ######### 71 | histogram = False 72 | -------------------------------------------------------------------------------- /scripts/createPass.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##################################################################### 4 | # 5 | # This file is licensed under the University of Illinois/NCSA Open 6 | # Source License. See LICENSE.TXT for details. 7 | # 8 | ##################################################################### 9 | 10 | ##################################################################### 11 | # 12 | # Name: createPass.sh 13 | # 14 | # Description: Compiles the LLVM compiler pass of FlipIt 15 | # 16 | ##################################################################### 17 | 18 | make clean 19 | 20 | echo " 21 | Making Compiler Pass Library:" 22 | make -f Makefile-Lib 23 | rm -rf Debug+Asserts 24 | 25 | echo " 26 | Making Compiler Pass:" 27 | make -f Makefile 28 | 29 | -------------------------------------------------------------------------------- /scripts/findLLVMHeaders.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | ##################################################################### 4 | # 5 | # This file is licensed under the University of Illinois/NCSA Open 6 | # Source License. See LICENSE.TXT for details. 7 | # 8 | ##################################################################### 9 | 10 | ##################################################################### 11 | # 12 | # Name: findLLVMHeaders.py 13 | # 14 | # Description: Searches the $LLVM_REPO_PATH for the location of the 15 | # header files needed by the compiler pass and updates 16 | # the '#includes' in the file 'faults.h'. With never 17 | # verisons of LLVM these paths may change. 18 | # 19 | ##################################################################### 20 | 21 | import os 22 | import sys 23 | import subprocess 24 | 25 | #get location of LLVM header files 26 | LLVM_BUILD_PATH = os.environ['LLVM_BUILD_PATH'] 27 | #LLVM_REPO_PATH = os.environ['LLVM_REPO_PATH'] 28 | os.system(LLVM_BUILD_PATH + "/bin/llvm-config --includedir > .tmp.tmp") 29 | LLVM_REPO_PATH = open(".tmp.tmp").read().strip() 30 | os.system("rm .tmp.tmp") 31 | 32 | # DOES NOT WORK ON BW 33 | #cmd = [LLVM_BUILD_PATH + "/bin/llvm-config", "--includedir"] 34 | #proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) 35 | #LLVM_REPO_PATH = proc.communicate()[0].strip() 36 | 37 | if LLVM_REPO_PATH == "": 38 | LLVM_REPO_PATH = LLVM_BUILD_PATH + "/include/" 39 | 40 | # header files used by the complier pass in 'faults.h' 41 | # might should grab this information from 'faults.h' and build at runtime. 42 | flipitHeaders = {'Pass.h': "#include ",\ 43 | 'ArrayRef.h': "#include ",\ 44 | 'Function.h': "#include ",\ 45 | 'Module.h': "#include ",\ 46 | 'User.h': "#include ",\ 47 | 'IRBuilder.h': "#include ",\ 48 | 'Instructions.h': "#include ",\ 49 | 'raw_ostream.h': "#include ",\ 50 | 'Statistic.h': "#include ",\ 51 | #'MachineOperand.h': "#include ",\ 52 | 'CommandLine.h': "#include ",\ 53 | #'LoopPass.h': "#include ",\ 54 | 'InstIterator.h': "#include ",\ 55 | 'PassManager.h': "#include ",\ 56 | 'CallingConv.h': "#include ",\ 57 | 'Verifier.h': "#include ",\ 58 | #'PrintModulePass.h': "#include ",\ 59 | 'DebugInfo.h': "#include ",\ 60 | 'Instruction.h': "#include ",\ 61 | 'TypeBuilder.h': "#include "} 62 | 63 | # replace header files in 'faults.h' with the correct headers for the version 64 | #of LLVM at $LLVM_REPO_PATH 65 | filePath = sys.argv[1] #os.environ['FLIPIT_PATH'] + "/src/pass/faults.h" 66 | infile= open(filePath) 67 | headerFile = infile.readlines() 68 | infile.close() 69 | for path, subdirs, files in os.walk(LLVM_REPO_PATH + "/llvm"): 70 | for name in files: 71 | if name in flipitHeaders.keys(): 72 | newInclude = "#include <" + os.path.join( path[path.find("include")+8:], name) +">" 73 | #os.system("sed -i '/" + flipitHeaders[name] + "/c\\" + newInclude + "' " + filePath) 74 | for i in range(len(headerFile)): 75 | line = headerFile[i] 76 | if "#include" in line and name in line: 77 | headerFile[i] = newInclude +"\n" 78 | flipitHeaders.pop(name, None) 79 | 80 | # remove the header files for files not found to eliminate compiler errors 81 | if len(flipitHeaders.keys()) > 0: 82 | print ("\n\nWARNING: Unable to locate the following header file(s). " \ 83 | "Compiliation of the compiler pass may not be successful.") 84 | 85 | for name in flipitHeaders.keys(): 86 | print ("\t", flipitHeaders[name]) 87 | #os.system("sed -i '/" +flipitHeaders[name] +"/c\\ ' " + filePath) 88 | for i in range(len(headerFile)): 89 | line = headerFile[i] 90 | if "#include" in line and name in line: 91 | headerFile[i] = "\n" 92 | print ("\n\n") 93 | 94 | outfile = open(filePath, "w") 95 | for i in headerFile: 96 | outfile.write(i) 97 | outfile.close() 98 | 99 | -------------------------------------------------------------------------------- /scripts/flipit-cc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ##################################################################### 3 | # 4 | # This file is licensed under the University of Illinois/NCSA Open 5 | # Source License. See LICENSE.TXT for details. 6 | # 7 | ##################################################################### 8 | 9 | ##################################################################### 10 | # 11 | # Name: flipit-cc 12 | # 13 | # Description: Wrapper script to hide the process of compilation for 14 | # fault injection. Use it like you would a regular 15 | # compiler. 16 | # 17 | # 1.) Compile source code to LLVM IR 18 | # 2.) Link other LLVM IR files needed for compilation 19 | # 3.) Run the compiler pass on this linked IR to instrment code 20 | # - generate a log file that can be used to relate fault injection 21 | # locations to source lines 22 | # 4.) Compile the transformed IR into object code 23 | # 24 | ##################################################################### 25 | import sys 26 | import os 27 | import glob 28 | 29 | # If there is a flipit-cc config file in the current 30 | # directory, use that if not use the one in the flipit directory 31 | if os.path.isfile("config.py"): 32 | sys.path.insert(0, os.getcwd()) 33 | from config import * 34 | 35 | argc = len(sys.argv) 36 | 37 | 38 | def shouldInject(argv, notInject): 39 | for i in notInject: 40 | if i in argv: 41 | return False 42 | 43 | if "-V" in argv or "--version" in argv: 44 | return False 45 | if "-c" not in argv: 46 | return False 47 | return True 48 | 49 | def addFlipItLinkage(cmd): 50 | if " -c " not in cmd: 51 | if histogram == False: 52 | cmd += " -L" + FLIPIT_PATH + "/lib -lcorrupt " 53 | else: 54 | cmd += " -L" + FLIPIT_PATH + "/lib -lcorrupt_histo " 55 | return cmd 56 | 57 | def removeLinking(flags): 58 | noLinker = " " 59 | for i in flags.split(" "): 60 | if i[0:2] == "-L" or i[0:2] =="-l" or i[0:2] == "-Z": 61 | continue 62 | else: 63 | noLinker += i + " " 64 | #print "LINKING: ", noLinker 65 | return noLinker 66 | 67 | def setConfig(argv): 68 | configs = glob.glob('*.config') 69 | if len(configs) > 0: 70 | config = configs[0] 71 | 72 | if (shouldInject(sys.argv, notInject)): 73 | 74 | setConfig(sys.argv) 75 | 76 | step1 = LLVM_BUILD_PATH + "/bin/clang -fPIC -emit-llvm -I" + FLIPIT_PATH + "/include " 77 | step2 = LLVM_BUILD_PATH + "/bin/llvm-link " + FLIPIT_PATH +"/include/FlipIt/corrupt/corrupt.bc " 78 | step3 = LLVM_BUILD_PATH + "/bin/opt -load "+ FLIPIT_PATH + "/lib/libFlipItPass.so -FlipIt " \ 79 | + " -config " + config \ 80 | + " -prob " + str(prob) \ 81 | + " -byte " + str(byte) \ 82 | + " -bit " + str(bit) \ 83 | + " -ptr " + str(ptr) \ 84 | + " -ctrl " + str(ctrl) \ 85 | + " -arith " + str(arith) \ 86 | + " -funcList " + funcList \ 87 | + " -stateFile " + stateFile 88 | step4 = LLVM_BUILD_PATH + "/bin/clang++ " 89 | fileName = "" 90 | fileNameBC = "" 91 | fileObj = "" 92 | 93 | 94 | #loop over argv and assign values as needed 95 | i = 1 96 | while i < argc: #sys.argv: 97 | arg = sys.argv[i] 98 | if arg == "-O2" or arg == "-O3" or arg =="-O5": 99 | arg = "-g -O2 "#-emit-llvm " 100 | #step4 += "-01 " 101 | elif ".c" in arg: 102 | fileName = arg#[0:-2]# grab file name and path 103 | elif "-o" == arg: 104 | step1 += arg + " " 105 | arg = sys.argv[i+1] 106 | fileObj = arg 107 | fileNameBC = arg[0:-2] + ".bc" #modify to generate .bc 108 | arg = fileNameBC 109 | i += 1 110 | #append 111 | step1 += arg + " " 112 | i += 1 113 | 114 | if SHOW != "": 115 | step1 += removeLinking(SHOW) 116 | #make sure the bitcode file name is set 117 | if fileNameBC == "": 118 | fileNameBC = fileName[0:fileName.rfind(".")] + ".bc" 119 | path = fileName[0:fileNameBC.rfind("/")] 120 | 121 | #grab the path the the file we are compiling to place the object file in the correct location 122 | pos = fileObj.rfind("/", 0, len(fileObj)) 123 | filePath = "./" 124 | if pos != -1: 125 | filePath += fileObj[0:pos] + "/" 126 | 127 | #build commands to launch 128 | step2 += fileNameBC + " -o " + fileName + ".crpt.bc" 129 | #step2 += fileNameBC + " " + filePath + "corrupt.bc" + " -o " + fileName + ".crpt.bc" 130 | #step3 += " < " + fileName + ".crpt.bc > " + fileName + ".final.bc 2> " + fileName + ".LLVM.txt" 131 | step3 += " -srcFile " + fileName + " " + fileName + ".crpt.bc -o " + fileName + ".final.bc "#2> " + fileName + ".LLVM.txt" 132 | step4 += "-O2 -fPIC -c " + fileName + ".final.bc -o " 133 | 134 | #name the object file what a normal compiler would name it 135 | if fileObj == "": 136 | step4 += fileName[0:fileObj.rfind(".")-1] + ".o" 137 | else: 138 | step4 += fileObj 139 | 140 | #remove temporary files 141 | if os.path.isfile(fileNameBC): 142 | os.system("rm " + fileNameBC) 143 | if os.path.isfile(fileName + ".crpt.bc"): 144 | os.system("rm " + fileName + ".crpt.bc") 145 | if os.path.isfile(fileName + ".final.bc"): 146 | os.system("rm " + fileName + ".final.bc") 147 | 148 | 149 | #check if we need to compile based on modified times 150 | if not (os.path.isfile(fileObj) and\ 151 | (os.path.getmtime(fileObj) > os.path.getmtime(fileName))): 152 | if verbose == True: 153 | print ("\n\n========== Compiling file: ", fileName, " ==========\n\n", step1) 154 | os.system(step1) 155 | if verbose == True: 156 | print (step2) 157 | os.system(step2) 158 | if verbose == True: 159 | print (step3) 160 | os.system(step3) 161 | if verbose == True: 162 | print (step4) 163 | os.system(step4) 164 | else: 165 | if "-V" in sys.argv or "--version" in sys.argv: 166 | print ("FlipIt Compiler wrapper around:\n") 167 | os.system(LLVM_BUILD_PATH + "/bin/clang --version") 168 | else: 169 | sys.argv[0] = cc + " -I" + FLIPIT_PATH + "/include " 170 | sys.argv[-1] += CPP_LIB 171 | print (addFlipItLinkage(' '.join(sys.argv))) 172 | os.system( addFlipItLinkage(' '.join(sys.argv)) ) 173 | -------------------------------------------------------------------------------- /scripts/genBC.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ##################################################################### 3 | # 4 | # This file is licensed under the University of Illinois/NCSA Open 5 | # Source License. See LICENSE.TXT for details. 6 | # 7 | ##################################################################### 8 | 9 | ##################################################################### 10 | # 11 | # Name: genBC.py 12 | # 13 | # Description: Generates a bitcode header file that allows multiple 14 | # source files to be compiled with FlipIt at the same 15 | # time. 16 | # 17 | ##################################################################### 18 | 19 | import os 20 | import subprocess 21 | import string 22 | 23 | FLIPIT_PATH = os.environ['FLIPIT_PATH'] 24 | LLVM_BUILD_PATH = os.environ['LLVM_BUILD_PATH'] 25 | # compile corrupt.c to LLVM bitcode 26 | os.system(LLVM_BUILD_PATH + "/bin/clang -emit-llvm -c -o tmp.bc " + FLIPIT_PATH +"/src/corrupt/corrupt.c") 27 | 28 | #doesn't work correctly on BW 29 | #cmd = [LLVM_BUILD_PATH + "/bin/llvm-link", "-d", "tmp.bc"] 30 | #p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 31 | #out, err = p.communicate() 32 | os.system(LLVM_BUILD_PATH + "/bin/llvm-dis tmp.bc -o tmp.ll") 33 | err = open("tmp.ll").read() 34 | 35 | # extract the function signitures and other info needed for the header file 36 | # since they are defined in the IR we need to replace define with declare to make a header file 37 | outfile = open(FLIPIT_PATH + "/src/corrupt/corrupt.ll", "w") 38 | attributes = [] 39 | for l in err.split("\n"): 40 | if "define" in l: 41 | s = l.replace("define", "declare", 1) 42 | s = s.replace( "internal", "", 1) 43 | outfile.write(s[0:-2]) 44 | outfile.write("\n") 45 | a = s[0:-2].split(" ")[-1] 46 | if a not in attributes: 47 | attributes.append(a) 48 | elif "%struct._IO" == l[0:11] or "%struct.__s" == l[0:11]: 49 | outfile.write(l +"\n") 50 | elif "target datalayout = " in l or "target triple = " in l: 51 | outfile.write(l + "\n") 52 | else: 53 | for i in attributes: 54 | if "attributes " +i in l: 55 | outfile.write(l +"\n") 56 | outfile.close() 57 | 58 | os.system(LLVM_BUILD_PATH + "/bin/clang -emit-llvm -c -o " + FLIPIT_PATH + "/src/corrupt/corrupt.bc " + FLIPIT_PATH+"/src/corrupt/corrupt.ll") 59 | os.system("rm tmp.bc tmp.ll") 60 | -------------------------------------------------------------------------------- /scripts/library.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##################################################################### 4 | # 5 | # This file is licensed under the University of Illinois/NCSA Open 6 | # Source License. See LICENSE.TXT for details. 7 | # 8 | ##################################################################### 9 | 10 | ##################################################################### 11 | # 12 | # Name: library.sh 13 | # 14 | # Description: Generates the corruption library that the program is 15 | # linked against. This library holds the user accessable 16 | # functions of FlipIt as well as the internal functions 17 | # that flip bits. 18 | # 19 | ##################################################################### 20 | 21 | 22 | # Without Histogram 23 | if [[ -e $FLIPIT_PATH/lib/libcorrupt.a ]] 24 | then 25 | rm $FLIPIT_PATH/lib/libcorrupt.a 26 | fi 27 | 28 | gcc -O3 -fPIC -c $FLIPIT_PATH/src/corrupt/corrupt.c 29 | ar -cvq libcorrupt.a corrupt.o 30 | if [[ -e corrupt.o ]]; then 31 | rm corrupt.o 32 | fi 33 | 34 | 35 | # With Histogram 36 | if [[ -e $FLIPIT_PATH/lib/libcorrupt_histo.a ]] 37 | then 38 | rm $FLIPIT_PATH/lib/libcorrupt_histo.a 39 | fi 40 | 41 | gcc -O3 -fPIC -DFLIPIT_HISTOGRAM -c $FLIPIT_PATH/src/corrupt/corrupt.c -o corrupt_histogram.o 42 | ar -cvq libcorrupt_histo.a corrupt_histogram.o 43 | if [[ -e corrupt_histogram.o ]]; then 44 | rm corrupt_histogram.o 45 | fi 46 | -------------------------------------------------------------------------------- /scripts/resetFaultIndex.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##################################################################### 4 | # 5 | # This file is licensed under the University of Illinois/NCSA Open 6 | # Source License. See LICENSE.TXT for details. 7 | # 8 | ##################################################################### 9 | 10 | ##################################################################### 11 | # 12 | # Name: resetFaultIndex.sh 13 | # 14 | # Description: Resets the fault site indexing- i.e., the next time 15 | # FlipIt complies code it will start with fault index 0, 1, 2, ... 16 | # 17 | ##################################################################### 18 | 19 | if [ [ -a ~/.FlipItState] ] 20 | then 21 | rm ~/.FlipItState 22 | fi 23 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##################################################################### 4 | # 5 | # This file is licensed under the University of Illinois/NCSA Open 6 | # Source License. See LICENSE.TXT for details. 7 | # 8 | ##################################################################### 9 | 10 | ##################################################################### 11 | # 12 | # Name: setup.sh 13 | # 14 | # Description: Sets up and and reconfigures existing LLVM build, 15 | # $LLVM_PATH, with the fault injector FlitIt, $FLIPIT_PATH. 16 | # 17 | ##################################################################### 18 | # setup.sh 19 | 20 | 21 | echo " 22 | 23 | Creating pass..." 24 | cd $FLIPIT_PATH/scripts/ 25 | python ./findLLVMHeaders.py $FLIPIT_PATH/src/pass/faults.h 26 | #cd $LLVM_BUILD_PATH/lib/Transforms/FlipIt 27 | #./createPass.sh 28 | 29 | 30 | echo " 31 | 32 | Copying headers to include dir" 33 | cd $FLIPIT_PATH 34 | mkdir -p -v include/FlipIt/corrupt 35 | mkdir -p -v include/FlipIt/pass 36 | cp src/pass/faults.h include/FlipIt/pass/ 37 | cp src/pass/Logger.h include/FlipIt/pass/ 38 | 39 | echo " 40 | 41 | Compiling FlipIt pass and library" 42 | cd $FLIPIT_PATH/src/pass 43 | make -f Makefile 44 | if ! [[ -d $FLIPIT_PATH/lib/ ]]; then 45 | mkdir $FLIPIT_PATH/lib/ 46 | fi 47 | 48 | if ! [[ -e libFlipItPass.so ]]; then 49 | echo "ERROR: Unable to build library FlipIt LLVM pass. setup.sh terminating...." 50 | exit 51 | fi 52 | 53 | if ! [[ -e libFlipIt.so ]]; then 54 | echo "WARNING: Unable to build library version of FlipIt to be called from custom LLVM pass." 55 | fi 56 | mv *.so $FLIPIT_PATH/lib 57 | echo "Done!" 58 | 59 | # Modify examples have correct #inlcude "corrupt.h" 60 | #echo " 61 | # 62 | #Updating headers in examples..." 63 | cd $FLIPIT_PATH 64 | #sed -i '/#include "\/path\/to\/flipit\/src\/corrupt\/corrupt.h"/c\#include "'$FLIPIT_PATH'/src/corrupt/corrupt.h"' ./examples/seq/matmul/main.c 65 | #sed -i '/#include "\/path\/to\/flipit\/src\/corrupt\/corrupt.h"/c\#include "'$FLIPIT_PATH'/src/corrupt/corrupt.h"' ./examples/mpi/jacobi/main.c 66 | #sed -i '/#include "\/path\/to\/flipit\/src\/corrupt\/corrupt.h"/c\#include "'$FLIPIT_PATH'/src/corrupt/corrupt.h"' ./examples/pass/Foo/main.c 67 | #echo "Done!" 68 | 69 | # Build corrupting library 70 | #mkdir $FLIPIT_PATH/lib 71 | echo " 72 | 73 | Building the corruption library..." 74 | cd $FLIPIT_PATH/scripts/ 75 | ./library.sh 76 | python ./genBC.py 77 | 78 | 79 | 80 | if [[ -e libcorrupt.a ]]; then 81 | cp libcorrupt.a $FLIPIT_PATH/lib/ 82 | if [[ -e libcorrupt_histo.a ]]; then 83 | cp libcorrupt_histo.a $FLIPIT_PATH/lib/ 84 | fi 85 | 86 | # copy the library to a location that is in the library path 87 | if [ "$(whoami)" != "root" ]; then 88 | echo "Warning: Unable to copy corruption library to '/usr/local/lib'" 89 | echo "" 90 | echo "You can link to the corruption library using:" 91 | else 92 | cp libcorrupt.a /usr/local/lib 93 | echo "You can link to the corruption library using:" 94 | echo " -lcorrupt" 95 | fi 96 | rm libcorrupt.a 97 | 98 | echo " -L$FLIPIT_PATH/lib -lcorrupt" 99 | else 100 | echo "Error: Unable to make corruption library!" 101 | fi 102 | 103 | echo " 104 | 105 | Copying headers to include dir" 106 | cd $FLIPIT_PATH 107 | cp src/corrupt/*.h include/FlipIt/corrupt/ 108 | cp src/corrupt/corrupt.bc include/FlipIt/corrupt/ 109 | echo "Done!" 110 | echo "" 111 | echo "setup.sh terminating..." 112 | -------------------------------------------------------------------------------- /src/corrupt/corrupt.c: -------------------------------------------------------------------------------- 1 | /***********************************************************************************************/ 2 | /* This file is licensed under the University of Illinois/NCSA Open Source License. */ 3 | /* See LICENSE.TXT for details. */ 4 | /***********************************************************************************************/ 5 | 6 | /***********************************************************************************************/ 7 | /* */ 8 | /* Name: corrupt.c */ 9 | /* */ 10 | /* Description: User-callable FlipIt function as well as the definition of the functions */ 11 | /* inserted by the compiler pass (faults.cpp). These corruption functions corrupt */ 12 | /* a single bit in the supplied value if we are to inject. */ 13 | /* */ 14 | /***********************************************************************************************/ 15 | 16 | #include "corrupt.h" 17 | 18 | #define FAULT_IDX_MASK 0x00FFFFFF 19 | 20 | static uint32_t FLIPIT_MaxInjections = 1; 21 | static uint32_t FLIPIT_State = 0; 22 | 23 | 24 | /*fault injection count*/ 25 | static uint32_t FLIPIT_InjectionCount = 0; 26 | static uint64_t FLIPIT_Attempts = 0; 27 | static uint64_t FLIPIT_InjCountdown = 0; 28 | static uint64_t FLIPIT_TotalInsts = 0; 29 | 30 | /*Fault Injection Statistics*/ 31 | static uint64_t* FLIPIT_Histogram; 32 | static uint32_t FLIPIT_MAX_LOC = 20000; 33 | static char* FLIPIT_StateFile = NULL; 34 | 35 | static uint32_t FLIPIT_MAX_INJECT_LINES = 33554432; 36 | static uint32_t FLIPIT_REMAIN_INJECT_COUNT = 1; 37 | static uint32_t FLIPIT_char_type_size = sizeof(char); 38 | 39 | /* MPI injections */ 40 | static uint32_t FLIPIT_Rank = 0; 41 | static uint32_t FLIPIT_RankInject = 0; 42 | 43 | /* Selective Injections */ 44 | static uint32_t* FLIPIT_FaultSites = NULL; 45 | static int32_t FLIPIT_NumFaultSites = -1; 46 | 47 | 48 | static void (*FLIPIT_CustomLogger)(FILE*) = NULL; 49 | static void (*FLIPIT_CountdownCustomLogger)(FILE*) = NULL; 50 | static double (*FLIPIT_FaultProb)() = NULL; 51 | 52 | static void flipit_parseArgs(uint32_t argc, char** argv); 53 | static uint8_t flipit_shouldInjectNoCheck(); 54 | static uint8_t flipit_checkActiveFaultSite(uint32_t fault_index); 55 | static void flipit_print_injectedErr(char* type, unsigned int bPos, int fault_index, double prob, 56 | double p); 57 | static double flipit_countdown(); 58 | static void flipit_countdownLogger(FILE*); 59 | 60 | /***********************************************************************************************/ 61 | /* The functions below are the functions that should be called by a user of FlipIt */ 62 | /***********************************************************************************************/ 63 | 64 | void FLIPIT_Init(uint32_t myRank, uint32_t argc, char** argv, uint64_t seed) { 65 | FILE* infile; 66 | FLIPIT_Rank = myRank; 67 | int amount; 68 | flipit_parseArgs(argc, argv); 69 | 70 | if (FLIPIT_Rank == 0) 71 | printf("Fault injector seed: %llu\n", (unsigned long long)seed+myRank); 72 | 73 | infile = fopen(FLIPIT_StateFile, "r"); 74 | 75 | if (infile) { 76 | int ret = fscanf(infile, "%d", &amount); 77 | if (amount > FLIPIT_MAX_LOC) 78 | FLIPIT_MAX_LOC = amount; 79 | fclose(infile); 80 | } 81 | #ifdef FLIPIT_HISTOGRAM 82 | FLIPIT_Histogram = (uint64_t*) calloc(FLIPIT_MAX_LOC, sizeof(uint64_t)); 83 | #endif 84 | #ifdef FLIPIT_DEBUG 85 | printf("Rank %d alloced an FLIPIT_Histogram of length: %d\n", FLIPIT_Rank, FLIPIT_MAX_LOC); 86 | #endif 87 | FLIPIT_State = FLIPIT_ON; 88 | srand(seed + myRank); 89 | srand48(seed + myRank); 90 | FLIPIT_SetFaultProbability(drand48); 91 | } 92 | 93 | void FLIPIT_Finalize(char* fname) { 94 | int i; 95 | FILE* outfile; 96 | #ifdef FLIPIT_HISTOGRAM 97 | if (fname != NULL) { 98 | char filename[500]; 99 | char tmp[15]; 100 | strcpy(filename, fname); 101 | strcat(filename, "_"); 102 | sprintf(tmp, "%d", FLIPIT_Rank); 103 | strcat(filename, tmp); 104 | 105 | outfile = fopen(filename, "w"); 106 | for (i = 0; i < FLIPIT_MAX_LOC; i++) 107 | fprintf(outfile, "Location %i: %lu\n", i, FLIPIT_Histogram[i]); 108 | fclose(outfile); 109 | } 110 | 111 | free(FLIPIT_Histogram); 112 | #endif 113 | if (FLIPIT_FaultSites != NULL) 114 | free(FLIPIT_FaultSites); 115 | } 116 | 117 | void FLIPIT_SetInjector(int state) { 118 | if (state == FLIPIT_ON || state == FLIPIT_OFF) 119 | FLIPIT_State = state; 120 | } 121 | 122 | 123 | void FLIPIT_SetRankInject(int state) { 124 | if (state == FLIPIT_ON || state == FLIPIT_OFF) 125 | FLIPIT_RankInject = state; 126 | } 127 | 128 | 129 | void FLIPIT_SetFaultProbability(double (prob)()) { 130 | FLIPIT_FaultProb = prob; 131 | } 132 | 133 | 134 | void FLIPIT_SetCustomLogger(void (logger)(FILE*)) { 135 | if (FLIPIT_InjCountdown != 0) { 136 | FLIPIT_CountdownCustomLogger = logger; 137 | FLIPIT_CustomLogger = flipit_countdownLogger; 138 | } 139 | else { 140 | FLIPIT_CustomLogger = logger; 141 | } 142 | } 143 | 144 | void FLIPIT_CountdownTimer(unsigned long numInstructions) { 145 | FLIPIT_InjCountdown = numInstructions; 146 | FLIPIT_SetFaultProbability(flipit_countdown); 147 | 148 | FLIPIT_CountdownCustomLogger = FLIPIT_CustomLogger; 149 | FLIPIT_CustomLogger = flipit_countdownLogger; 150 | } 151 | 152 | unsigned long long FLIPIT_GetExecutedInstructionCount() { 153 | return FLIPIT_TotalInsts; 154 | } 155 | 156 | int FLIPIT_GetInjectionCount() { 157 | return FLIPIT_InjectionCount; 158 | } 159 | 160 | void FLIPIT_SetMaxInjections(int n) 161 | { 162 | if (n < 0) 163 | printf("Warning: Attempting to set Max Injections to negative value %d. Defaulting to 1.\n", n); 164 | n = 1; 165 | 166 | // set max number of injections for this rank; 167 | // then calculate the remaing number of injections if any 168 | FLIPIT_MaxInjections = n; 169 | if (FLIPIT_MaxInjections > FLIPIT_InjectionCount) 170 | FLIPIT_REMAIN_INJECT_COUNT = FLIPIT_MaxInjections - FLIPIT_InjectionCount; 171 | else 172 | FLIPIT_REMAIN_INJECT_COUNT = 0; 173 | 174 | assert(FLIPIT_REMAIN_INJECT_COUNT >= 0 175 | && "ERROR: NEGATIVE NUMBER OF REMAINING INJECTIONS!!!"); 176 | } 177 | 178 | int FLIPIT_GetMaxInjections() 179 | { 180 | return FLIPIT_MaxInjections; 181 | } 182 | /***********************************************************************************************/ 183 | /* User callable function for FORTRAN wrapper */ 184 | /***********************************************************************************************/ 185 | int flipit_init_ftn_(int* myRank, int* argc, char*** argv, unsigned long long* seed) { 186 | if (argv == NULL) 187 | FLIPIT_Init(*myRank, 0, NULL, *seed); 188 | else 189 | FLIPIT_Init(*myRank, *argc, *argv, *seed); 190 | 191 | return 0; 192 | } 193 | 194 | int flipit_finalize_ftn_(char** filename) { 195 | if (filename != NULL) 196 | FLIPIT_Finalize(*filename); 197 | else 198 | FLIPIT_Finalize(NULL); 199 | 200 | return 0; 201 | } 202 | 203 | int flipit_setinjector_ftn_(int* state) { 204 | FLIPIT_SetInjector(*state); 205 | 206 | return 0; 207 | } 208 | 209 | int flipit_setrankinject_ftn_(int* state) { 210 | FLIPIT_SetRankInject(*state); 211 | 212 | return 0; 213 | } 214 | 215 | int flipit_countdowntimer_ftn_(unsigned long* numInstructions) { 216 | FLIPIT_CountdownTimer(*numInstructions); 217 | 218 | return 0; 219 | } 220 | 221 | 222 | /***********************************************************************************************/ 223 | /* The functions below this are used internally by FlipIt */ 224 | /***********************************************************************************************/ 225 | 226 | 227 | static void flipit_parseArgs(uint32_t argc, char** argv) { 228 | int i, j; 229 | int numFaulty = -1; 230 | 231 | for (i = 1; i < argc; i++){ 232 | if (strcmp("--numberFaulty", argv[i]) == 0 || strcmp("-nF", argv[i]) == 0) 233 | numFaulty = atoi(argv[++i]); 234 | else if (strcmp("--faulty", argv[i]) == 0 || strcmp("-f", argv[i]) == 0) { 235 | for(j = 0; j < numFaulty; j++) 236 | if (atoi(argv[i + j + 1]) == FLIPIT_Rank) 237 | FLIPIT_RankInject = 1; 238 | i += j; 239 | } 240 | 241 | else if (strcmp("--numberFaultLoc", argv[i]) == 0 || strcmp("-nLOC", argv[i]) == 0) 242 | FLIPIT_NumFaultSites = atoi(argv[++i]); 243 | else if (strcmp("--faultyLoc", argv[i]) == 0 || strcmp("-fLOC", argv[i]) == 0) { 244 | FLIPIT_FaultSites = (uint32_t*) malloc( sizeof(uint32_t) * FLIPIT_NumFaultSites); 245 | for(j = 0; j < FLIPIT_NumFaultSites; j++) 246 | FLIPIT_FaultSites[j] = atoi(argv[i + j + 1]); 247 | i += j; 248 | } 249 | else if (strcmp("--stateFile", argv[i]) == 0 || strcmp("-sF", argv[i]) == 0) { 250 | int len = strlen(argv[i]) + 1; 251 | FLIPIT_StateFile = (char*) malloc(sizeof(char)*len); 252 | strcpy(FLIPIT_StateFile, argv[i]); 253 | } 254 | } 255 | 256 | // verify variables have valid values 257 | if (numFaulty == -1){ 258 | FLIPIT_RankInject = 1; 259 | } 260 | if (FLIPIT_StateFile == NULL) { 261 | char* home = getenv("HOME"); 262 | FLIPIT_StateFile = (char*) malloc(strlen(home) + strlen("/.FlipItState")+1); 263 | strcpy(FLIPIT_StateFile, home); 264 | strcat(FLIPIT_StateFile, "/.FlipItState"); 265 | 266 | } 267 | #ifdef FLIPIT_DEBUG 268 | if(FLIPIT_Rank == 0) 269 | { 270 | for (i=0; i> (bit); 303 | FLIPIT_Attempts += inject; //CS 304 | return inject; 305 | */ 306 | /* 307 | int inject_once = FLIPIT_MaxInjections == 1; 308 | int i; 309 | int inject = flipit_shouldInjectNoCheck(); 310 | FLIPIT_TotalInsts++; 311 | if (!inject) 312 | return 0; 313 | */ 314 | /* check fault index site */ 315 | int inject = 0; 316 | int i = 0; 317 | if (FLIPIT_FaultSites != NULL) { 318 | for (i = 0; i < FLIPIT_NumFaultSites; i++) 319 | if (FLIPIT_FaultSites[i] == fault_index) { 320 | inject = 1; 321 | break; 322 | } 323 | } 324 | else 325 | inject = 1; 326 | 327 | //FLIPIT_Attempts += inject; 328 | return inject; 329 | } 330 | 331 | static void flipit_print_injectedErr(char* type, unsigned int bPos, int fault_index, double prob, 332 | double p) { 333 | printf("\n/*********************************Start**************************************/\n" 334 | "\nSuccessfully injected %s error!!\nRank: %d\n" 335 | "Total # faults injected: %d\n" 336 | "Bit position is: %u\n" 337 | "Index of the fault site: %d\n" 338 | "Fault site probability: %e\n" 339 | "Chosen random probability is: %e\n" 340 | "Attempts since last injection: %lu\n", type, FLIPIT_Rank, FLIPIT_InjectionCount, 341 | bPos, fault_index, 342 | prob, p, FLIPIT_Attempts); 343 | if (FLIPIT_CustomLogger != NULL) 344 | FLIPIT_CustomLogger(stdout); 345 | printf("\n/*********************************End**************************************/\n"); 346 | } 347 | 348 | static double flipit_countdown() { 349 | return (double) --FLIPIT_InjCountdown; 350 | } 351 | 352 | static void flipit_countdownLogger(FILE* outfile) { 353 | if (FLIPIT_CountdownCustomLogger != NULL) 354 | FLIPIT_CountdownCustomLogger(outfile); 355 | FLIPIT_InjCountdown = FLIPIT_Attempts; 356 | } 357 | 358 | /***********************************************************************************************/ 359 | /* The functions below this are inserted by the compiler pass to flip a bit */ 360 | /***********************************************************************************************/ 361 | 362 | uint64_t corruptIntData_64bit(uint32_t parameter, double prob, uint64_t inst_data) 363 | { 364 | 365 | #ifdef FLIPIT_HISTOGRAM 366 | // extract fault_index, byte_val from parameter 367 | uint32_t fault_index = (uint32_t) (parameter & FAULT_IDX_MASK); 368 | FLIPIT_Histogram[fault_index]++; 369 | #endif 370 | 371 | // verify that it is the correct time to inject 372 | if (0 == flipit_shouldInjectNoCheck()) return inst_data; 373 | float p = FLIPIT_FaultProb(); 374 | if (p > prob) return inst_data; 375 | #ifndef FLIPIT_HISTOGRAM 376 | uint32_t fault_index = (uint32_t) (parameter & FAULT_IDX_MASK); 377 | #endif 378 | if (0 == flipit_checkActiveFaultSite(fault_index)) return inst_data; 379 | 380 | // determine which bit & byte should be flipped 381 | char bit = ((parameter >> 24) & 0xF); 382 | char byte = ((parameter >> 28) & 0xF); 383 | //printf("###Byte = %d, Bit = %d\n", byte, bit); 384 | 385 | if (bit == 0xF) bit = rand() % 8; //get correct bit 386 | if (byte > 7) byte = rand() % (16 - byte); 387 | 388 | //printf("Byte = %d, Bit = %d\n", byte, bit); 389 | FLIPIT_InjectionCount++; 390 | FLIPIT_REMAIN_INJECT_COUNT--; 391 | if (FLIPIT_REMAIN_INJECT_COUNT == 0) FLIPIT_RankInject = 0; 392 | 393 | flipit_print_injectedErr("Integer Data", byte*8 + bit, fault_index, prob, p); 394 | FLIPIT_Attempts = 0; 395 | return inst_data ^ ((uint64_t) 0x1L << (byte*8 + bit)); //TODO: correctly wrap for 32, 16, and 8 bit integers 396 | } 397 | 398 | //////////////////////////////////////////////////////////////////////////////////////////////////// 399 | float corruptFloatData_32bit(uint32_t parameter, double prob, float inst_data) 400 | { 401 | 402 | #ifdef FLIPIT_HISTOGRAM 403 | // extract fault_index, byte_val from parameter 404 | uint32_t fault_index = (uint32_t) (parameter & FAULT_IDX_MASK); 405 | FLIPIT_Histogram[fault_index]++; 406 | #endif 407 | 408 | //TODO: add support for CHECK() 409 | if (0 == flipit_shouldInjectNoCheck()) return inst_data; 410 | float p = FLIPIT_FaultProb(); 411 | if (p > prob) return inst_data; 412 | #ifndef FLIPIT_HISTOGRAM 413 | uint32_t fault_index = (uint32_t) (parameter & FAULT_IDX_MASK); 414 | #endif 415 | if (0 == flipit_checkActiveFaultSite(fault_index)) return inst_data; 416 | 417 | 418 | // determine which bit & byte should be flipped 419 | char bit = ((parameter >> 24) & 0xF); 420 | char byte = ((parameter >> 28) & 0xF); 421 | 422 | if (bit == 0xF) 423 | bit = rand() % 8; 424 | else 425 | bit = bit % 32; 426 | if (byte > 7) 427 | byte = rand() % 4; // random byte (we know the size) 428 | else 429 | byte = byte % 4; // wrap fixed byte to sizeof(float) 430 | 431 | FLIPIT_InjectionCount++; 432 | FLIPIT_REMAIN_INJECT_COUNT--; 433 | if (FLIPIT_REMAIN_INJECT_COUNT == 0) FLIPIT_RankInject = 0; 434 | 435 | flipit_print_injectedErr("32-bit IEEE Float Data", byte*8 + bit, fault_index, prob, p); 436 | FLIPIT_Attempts = 0; 437 | 438 | int* ptr = (int* ) &inst_data; 439 | int tmp = (*ptr ^ (0x1 << (bit + byte * 8))); 440 | float*pf = (float*)&tmp; 441 | return *pf; 442 | } 443 | 444 | //////////////////////////////////////////////////////////////////////////////////////////////////// 445 | double corruptFloatData_64bit(uint32_t parameter, double prob, double inst_data) 446 | { 447 | 448 | #ifdef FLIPIT_HISTOGRAM 449 | // extract fault_index, byte_val from parameter 450 | uint32_t fault_index = (uint32_t) (parameter & FAULT_IDX_MASK); 451 | FLIPIT_Histogram[fault_index]++; 452 | #endif 453 | 454 | //TODO: add support for CHECK() 455 | if (0 == flipit_shouldInjectNoCheck()) return inst_data; 456 | float p = FLIPIT_FaultProb(); 457 | if (p > prob) return inst_data; 458 | #ifndef FLIPIT_HISTOGRAM 459 | uint32_t fault_index = (uint32_t) (parameter & FAULT_IDX_MASK); 460 | #endif 461 | if (0 == flipit_checkActiveFaultSite(fault_index)) return inst_data; 462 | 463 | // determine which bit & byte should be flipped 464 | char bit = ((parameter >> 24) & 0xF); //TODO: VERIFY 465 | char byte = ((parameter >> 28) & 0xF); 466 | 467 | if (bit == 0xF) 468 | bit = rand() % 8; //TODO VEIFY TODO wrap bit 469 | if (byte > 7) 470 | byte = rand() % 8; 471 | 472 | FLIPIT_InjectionCount++; 473 | FLIPIT_REMAIN_INJECT_COUNT--; 474 | if (FLIPIT_REMAIN_INJECT_COUNT == 0) FLIPIT_RankInject = 0; 475 | 476 | flipit_print_injectedErr("64-bit IEEE Float Data", byte*8 + bit, fault_index, prob, p); 477 | FLIPIT_Attempts = 0; 478 | 479 | long long* ptr = (long long* ) &inst_data; 480 | long long tmp = (*ptr ^ (0x1L << (byte*8 + bit))); 481 | double *pf = (double*)&tmp; 482 | return *pf; 483 | } 484 | 485 | uint64_t corruptPtr2Int_64bit(uint32_t parameter, double prob, uint64_t inst_data) 486 | { 487 | 488 | #ifdef FLIPIT_HISTOGRAM 489 | // extract fault_index, byte_val from parameter 490 | uint32_t fault_index = (uint32_t) (parameter & FAULT_IDX_MASK); 491 | FLIPIT_Histogram[fault_index]++; 492 | #endif 493 | 494 | //TODO: add support for CHECK() 495 | if (0 == flipit_shouldInjectNoCheck()) return inst_data; 496 | float p = FLIPIT_FaultProb(); 497 | if (p > prob) return inst_data; 498 | #ifndef FLIPIT_HISTOGRAM 499 | uint32_t fault_index = (uint32_t) (parameter & FAULT_IDX_MASK); 500 | #endif 501 | if (0 == flipit_checkActiveFaultSite(fault_index)) return inst_data; 502 | 503 | 504 | // determine which bit & byte should be flipped 505 | char bit = ((parameter >> 24) & 0xF); //TODO: VERIFY 506 | char byte = ((parameter >> 28) & 0xF); 507 | 508 | if (bit == 0xF) bit = rand() % 8; //get correct bit 509 | if (byte > 7) byte = rand() % 8; 510 | 511 | FLIPIT_InjectionCount++; 512 | FLIPIT_REMAIN_INJECT_COUNT--; 513 | if (FLIPIT_REMAIN_INJECT_COUNT == 0) FLIPIT_RankInject = 0; 514 | 515 | flipit_print_injectedErr("Converted Pointer", byte*8 + bit, fault_index, prob, p); 516 | FLIPIT_Attempts = 0; 517 | return inst_data ^ ((uint64_t) 0x1L << (byte*8 + bit)); 518 | } 519 | 520 | 521 | -------------------------------------------------------------------------------- /src/corrupt/corrupt.h: -------------------------------------------------------------------------------- 1 | /***********************************************************************************************/ 2 | /* This file is licensed under the University of Illinois/NCSA Open Source License. */ 3 | /* See LICENSE.TXT for details. */ 4 | /***********************************************************************************************/ 5 | 6 | /***********************************************************************************************/ 7 | /* */ 8 | /* Name: corrupt.h */ 9 | /* */ 10 | /* Description: Header file for the user-callable FlipIt function as well as the definition of */ 11 | /* the functions inserted by the compiler pass (faults.cpp). These corruption */ 12 | /* functions corrupt a single bit in the supplied value if we are to inject. */ 13 | /* */ 14 | /***********************************************************************************************/ 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #ifndef CORRUPTH 21 | #define CORRUPTH 22 | 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #define FLIPIT_ON 1 36 | #define FLIPIT_OFF 0 37 | 38 | 39 | /* setting up and house keeping */ 40 | void FLIPIT_Init(uint32_t myRank, uint32_t argc, char** argv, uint64_t seed); 41 | void FLIPIT_Finalize(char* filename); 42 | void FLIPIT_SetInjector(int state); 43 | void FLIPIT_SetRankInject(int state); 44 | void FLIPIT_SetFaultProbability(double(faultProb)()); 45 | void FLIPIT_SetCustomLogger(void (customLogger)(FILE*)); 46 | void FLIPIT_CountdownTimer(unsigned long numInstructions); 47 | unsigned long long FLIPIT_GetExecutedInstructionCount(); 48 | int FLIPIT_GetInjectionCount(); 49 | void FLIPIT_SetMaxInjections(int n); 50 | int FLIPIT_GetMaxInjections(); 51 | 52 | /* FORTRAN VERSIONS (ex: CALL flipit_init_ftn(myrank, argc, argv, seed) */ 53 | int flipit_init_ftn_(int* myRank, int* argc, char*** argv, unsigned long long* seed); 54 | int flipit_finalize_ftn_(char** filename); 55 | int flipit_setinjector_ftn_(int* state); 56 | int flipit_setrankinject_ftn_(int* state); 57 | /* void flipit_setfaultprobability_ftn_(double(faultProb)()); */ 58 | /* void flipit_setcustomlogger_ftn_(void (customLogger)(FILE*)); */ 59 | int flipit_countdowntimer_ftn_(unsigned long* numInstructions); 60 | 61 | /* corrupt the data */ 62 | float corruptFloatData_32bit (uint32_t parameter, double prob, float inst_data); 63 | uint64_t corruptIntData_64bit (uint32_t parameter, double prob, uint64_t inst_data); 64 | double corruptFloatData_64bit (uint32_t parameter, double prob, double inst_data); 65 | uint64_t corruptPtr2Int_64bit (uint32_t parameter, double prob, uint64_t inst_data); 66 | #endif 67 | 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | -------------------------------------------------------------------------------- /src/pass/Logger.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGGER_H 2 | #define LOGGER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include "llvm/Support/raw_ostream.h" 11 | using namespace llvm; 12 | 13 | #define INFO_SIZE 5 14 | #define TYPE_SIZE 3 15 | short NEW_FILE_MASK = 0x8000; 16 | 17 | typedef enum { 18 | ARITHMETIC_FP = 0, 19 | POINTER, 20 | ARITHMETIC_FIX, 21 | CONTROL_LOOP, 22 | CONTROL_BRANCH, 23 | UNKNOWN_INJ 24 | } INJ_TYPES; 25 | 26 | typedef enum { 27 | RESULT = 0, 28 | VALUE = RESULT, 29 | ADDRESS, 30 | UNKNOWN_INJ_TYPE = 30 31 | } INJ_INFO_TYPES; 32 | 33 | class LogFile 34 | { 35 | public: 36 | LogFile(std::string srcName, unsigned long currentSite, std::string suffix = ".LLVM.bin", int bufSize = 8192, char version = 1) { 37 | init(srcName, currentSite, suffix, bufSize, version); 38 | } 39 | //LogFile(char* filename, string::string suffix = ".LLVM.txt", int bufSize = 8192, char version) { 40 | // init(filename, bufSize, versions); 41 | //} 42 | 43 | void init(std::string srcName, unsigned long currentSite, std::string suffix, int bufSize, char version) { 44 | srcFile = srcName; 45 | outfile.open(srcName+suffix, std::ios::out | std::ios::binary); 46 | buffer = new char[bufSize]; 47 | this->bufSize = bufSize; 48 | currSize = 0; 49 | oldSite = currentSite -1; 50 | logFileHeader(version); 51 | } 52 | 53 | ~LogFile() { 54 | // close(); 55 | delete [] buffer; 56 | } 57 | 58 | void logFunctionHeader(unsigned long site, std::string name) 59 | { 60 | //errs() << "\n\n" << name << "\n"; 61 | // make sure we have enough room 62 | if (currSize + name.size() + 1 + sizeof(site) > bufSize) 63 | write(); 64 | 65 | //function name 66 | assert(name.size() <= 255 && "Logging function with name >255.\n"); 67 | 68 | // DUMMY operand flag 69 | buffer[currSize++] = 255; 70 | buffer[currSize++] = (char) name.size(); 71 | memcpy(buffer+currSize, name.c_str(), std::min((int)name.size(), (1 << 8) -1)); 72 | currSize += std::min((int)name.size(), (1 << 8) -1); 73 | 74 | // current fault site index 75 | oldSite = site - 1; 76 | char* ptr = (char*) &site; 77 | for (unsigned i=0; i < sizeof(site); i++) { 78 | buffer[currSize++] = *(ptr + i); 79 | } 80 | 81 | } 82 | void logInst(unsigned long site, int injType, int comment, Instruction* I) 83 | { 84 | // make sure we have enough room 85 | if (currSize + 5 > bufSize) // 5 bytes compressed data 86 | write(); 87 | 88 | // operand 89 | buffer[currSize++] = (char) I->getOpcode(); // Assumes < 255 insts 90 | 91 | //errs() << site << " " << (int)I->getOpcode() << " " << (int)getType(injType) 92 | // << " " << (int)getInfo(comment) << "(" << comment << ") "; 93 | assert(oldSite + 1 == site && "Sites differ > 1.\n"); 94 | // Type and info 95 | char type_info = (getType(injType) << INFO_SIZE) | getInfo(comment); 96 | buffer[currSize++] = type_info; 97 | oldSite = site; 98 | 99 | // location in file 100 | logFileLocation(I); 101 | } 102 | inline bool needsWriting() { return currSize > 0; } 103 | void write() { 104 | if (needsWriting()) { 105 | outfile.write(buffer, currSize); 106 | currSize = 0; 107 | } 108 | } 109 | void close() { 110 | if (outfile.is_open()) { 111 | if (needsWriting()){ 112 | write(); 113 | } 114 | outfile.close(); 115 | } 116 | } 117 | 118 | private: 119 | void logFileHeader(char version) 120 | { 121 | // file version 122 | buffer[currSize++] = version; 123 | 124 | //source file properties 125 | oldFile = srcFile; 126 | unsigned short size = srcFile.size(); 127 | char* ptr = (char*)&(size); 128 | buffer[currSize++] = *ptr; 129 | buffer[currSize++] = *(ptr+1); 130 | memcpy(buffer+currSize, srcFile.c_str(), std::min((int)size, (1 << 16) -1)); 131 | currSize += std::min((int)size, (1 << 16) -1); 132 | } 133 | 134 | unsigned char getType(int injType) 135 | { 136 | if (injType < ARITHMETIC_FP && injType > CONTROL_BRANCH) 137 | injType = UNKNOWN_INJ; 138 | return (unsigned char)injType; 139 | } 140 | 141 | unsigned char getInfo(int comment) 142 | { 143 | if (comment < ARITHMETIC_FP && comment > UNKNOWN_INJ_TYPE) 144 | comment = UNKNOWN_INJ_TYPE; 145 | return (unsigned char)comment; 146 | } 147 | void logFileLocation(Instruction* I) 148 | { 149 | unsigned short size = 0; 150 | unsigned short lineNum = 0; 151 | std::string location = ""; 152 | MDNode* N = I->getMetadata("dbg"); 153 | 154 | if (N != NULL) { 155 | #if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 6 156 | DILocation Loc(N); 157 | location = Loc.getDirectory().str() + "/" + Loc.getFilename().str(); 158 | lineNum = Loc.getLineNumber(); 159 | #elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 6 160 | DILocation* Loc = I->getDebugLoc(); 161 | location = Loc->getDirectory().str() + "/" + Loc->getFilename().str(); 162 | lineNum = Loc->getLine(); 163 | #endif 164 | if (oldFile != location) { 165 | size = location.size(); 166 | size |= NEW_FILE_MASK;//0x80; // set MSB 167 | } 168 | } 169 | else /* no debugging information */ { 170 | location = "__NF"; 171 | if (oldFile != "__NF") { 172 | size = 4 | NEW_FILE_MASK;//0x80; 173 | } 174 | else /* no prev dbg info */ { 175 | // nothing... 176 | } 177 | } 178 | // file size if new file 179 | if (oldFile != location) { 180 | char* ptr = (char*)&(size); 181 | buffer[currSize++] = *ptr; 182 | buffer[currSize++] = *(ptr+1); 183 | } 184 | 185 | // line number 186 | char* ptr = (char*)&(lineNum); 187 | buffer[currSize++] = *ptr; 188 | buffer[currSize++] = *(ptr+1); 189 | // file name if need be 190 | if (size & NEW_FILE_MASK) { 191 | if (currSize + location.size() > bufSize) 192 | write(); 193 | 194 | memcpy(buffer+currSize, location.c_str(), std::min((int)location.size(), (1 << 16) -1)); 195 | currSize += std::min((int)location.size(), (1 << 16) -1); 196 | } 197 | oldFile = location; 198 | //errs() << size << " " << lineNum << " " << location << "\n"; 199 | } 200 | 201 | 202 | // data 203 | ofstream outfile; 204 | std::string srcFile; 205 | std::string oldFile; 206 | unsigned long oldSite; 207 | char* buffer; 208 | unsigned bufSize; 209 | unsigned currSize; 210 | }; 211 | #endif 212 | 213 | -------------------------------------------------------------------------------- /src/pass/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for faults pass 2 | 3 | ##################################################################### 4 | # 5 | # This file is licensed under the University of Illinois/NCSA Open 6 | # Source License. See LICENSE.TXT for details. 7 | # 8 | ##################################################################### 9 | 10 | #CXX=$(LLVM_BUILD_PATH)/bin/clang 11 | CXX=g++ 12 | LLVM_CONFIG=$(LLVM_BUILD_PATH)/bin/llvm-config 13 | 14 | CXXFLAGS= -Wall -O2 -g -std=c++11 -fno-rtti -I$(FLIPIT_PATH)/include 15 | CXXFLAGS += $(shell $(LLVM_CONFIG) --cxxflags) -fPIC 16 | #CXXFLAGS += -DCOMPILE_PASS 17 | 18 | GCC_MAJOR=$(shell gcc -v 2>&1 /dev/null | grep -i "gcc version" | awk -F" " '{split($$3, a, ".")} END{print a[1]}') 19 | 20 | ifneq ($(GCC_MAJOR),4) 21 | CXXFLAGS += -DUSE_OLD_ABI=1 22 | endif 23 | 24 | LDFLAGS = $(shell $(LLVM_CONFIG) --ldflags) 25 | 26 | ifeq ($(shell uname),Darwin) 27 | SHARED_LIB_OPT = -bundle -undefined dynamic_lookup 28 | else 29 | SHARED_LIB_OPT = -shared 30 | endif 31 | 32 | #all: libFlipItPass.so 33 | all: libFlipItPass.so libFlipIt.so 34 | 35 | libFlipItPass.so:faults.cpp 36 | #libFlipItPass.so:faults_new.cpp 37 | $(CXX) $(CXXFLAGS) -DCOMPILE_PASS $(LDFLAGS) -o $@ $(SHARED_LIB_OPT) $< 38 | 39 | libFlipIt.so:faults.cpp 40 | $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(SHARED_LIB_OPT) $< 41 | 42 | clean: 43 | rm -rf *.o *.so 44 | -------------------------------------------------------------------------------- /src/pass/Makefile-Lib: -------------------------------------------------------------------------------- 1 | # Makefile for faults pass library 2 | 3 | ##################################################################### 4 | # 5 | # This file is licensed under the University of Illinois/NCSA Open 6 | # Source License. See LICENSE.TXT for details. 7 | # 8 | ##################################################################### 9 | 10 | # Path to top level of LLVM hierarchy 11 | LEVEL = ../../../ 12 | 13 | # Name of the library to build 14 | LIBRARYNAME = libFlipIt 15 | 16 | 17 | # Make the shared library become a loadable module so the tools can 18 | # dlopen/dlsym on the resulting library. 19 | LOADABLE_MODULE = 0 20 | SHARED_LIBRARY = 1 21 | BUILD_ARCHIVE = 1 22 | 23 | # Include the makefile implementation stuff 24 | include $(LEVEL)/Makefile.common 25 | -------------------------------------------------------------------------------- /src/pass/faults.h: -------------------------------------------------------------------------------- 1 | /***********************************************************************************************/ 2 | /* This file is licensed under the University of Illinois/NCSA Open Source License. */ 3 | /* See LICENSE.TXT for details. */ 4 | /***********************************************************************************************/ 5 | 6 | /***********************************************************************************************/ 7 | /* */ 8 | /* Name: faults.h */ 9 | /* */ 10 | /* Description: Header file for the LLVM IR compiler pass. This pass add calls to corrupting */ 11 | /* functions that will corrupt (single bit-flip) the result of LLVM instructions */ 12 | /* with a certain probability. */ 13 | /* */ 14 | /***********************************************************************************************/ 15 | 16 | #ifndef FAULTS_H 17 | #define FAULTS_H 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | using std::string; 24 | #include 25 | using std::vector; 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | using std::ifstream; 32 | using std::ofstream; 33 | using std::ios; 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "FlipIt/pass/Logger.h" 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | 60 | 61 | //#include 62 | 63 | #ifdef COMPILE_PASS 64 | static cl::opt funcList("funcList", cl::desc("Name(s) of the function(s) to be targeted"), cl::value_desc("func1 func2 func3"), cl::init(""), cl::ValueRequired); 65 | static cl::opt configPath("config", cl::desc("Path to the FlipIt Config file"), cl::value_desc("/path/to/FlipIt.config"), cl::init("FlipIt.config")); 66 | static cl::opt siteProb("prob", cl::desc("Probability that instrution is faulty"), cl::value_desc("Any value [0,1)"), cl::init(1e-8), cl::ValueRequired); 67 | static cl::opt byte_val("byte", cl::desc("Which byte to consider for fault injection"), cl::value_desc("-1-7"), cl::init(-1), cl::ValueRequired); 68 | static cl::opt bit_val("bit", cl::desc("Which bit to consider for fault injection"), cl::value_desc("-1-63"), cl::init(-1), cl::ValueRequired); 69 | static cl::opt singleInj("singleInj", cl::desc("Inject Error Only Once"), cl::value_desc("0/1"), cl::init(1), cl::ValueRequired); 70 | static cl::opt arith_err("arith", cl::desc("Inject Faults Into Arithmetic Instructions"), cl::value_desc("0/1"), cl::init(1), cl::ValueRequired); 71 | static cl::opt ctrl_err("ctrl", cl::desc("Inject Faults Into Control Instructions"), cl::value_desc("0/1"), cl::init(1), cl::ValueRequired); 72 | static cl::opt ptr_err("ptr", cl::desc("Inject Faults Into Pointer Instructions"), cl::value_desc("0/1"), cl::init(1), cl::ValueRequired); 73 | static cl::opt srcFile("srcFile", cl::desc("Name of the source file being compiled"), cl::value_desc("e.g. foo.c, foo.cpp, or foo.f90"), cl::init("UNKNOWN"), cl::ValueRequired); 74 | static cl::opt stateFile("stateFile", cl::desc("Name of the state file being updated when compiled. Used to provide unique fault site indexes."), cl::value_desc("FlipItState"), cl::init("FlipItState"), cl::ValueRequired); 75 | #endif 76 | 77 | 78 | 79 | 80 | /*Dynamic Fault Injection LLVM Pass*/ 81 | namespace FlipIt { 82 | #ifdef COMPILE_PASS 83 | class DynamicFaults : public ModulePass { 84 | #else 85 | class DynamicFaults { 86 | std::string funcList; 87 | std::string configPath; 88 | double siteProb; 89 | int byte_val; 90 | int bit_val; 91 | int singleInj; 92 | bool arith_err; 93 | bool ctrl_err; 94 | bool ptr_err; 95 | std::string srcFile; 96 | std::string stateFile; 97 | #endif 98 | public: 99 | static char ID; 100 | 101 | #ifdef COMPILE_PASS 102 | DynamicFaults(); 103 | DynamicFaults(string funcList, string configPath, double siteProb, 104 | int byte_val, int bit_val, bool arith_err, bool ctrl_err, 105 | bool ptr_err, std::string srcFile, std::string stateFile, Module* M); 106 | #else 107 | DynamicFaults(Module* M); 108 | DynamicFaults(string funcList, string configPath, double siteProb, 109 | int byte_val, int bit_val, bool arith_err, bool ctrl_err, 110 | bool ptr_err, std::string srcFile, std::string stateFile, Module* M); 111 | 112 | #endif 113 | virtual ~DynamicFaults() 114 | { finalize(); } 115 | virtual bool runOnModule(Module &M); 116 | bool corruptInstruction(Instruction* I); 117 | 118 | private: 119 | 120 | void init(); 121 | bool finalize(); 122 | //std::vector splitAtSpace(std::string spltStr); 123 | void splitAtSpace(); 124 | int selectArgument(CallInst* callInst); 125 | void readConfig(string path); 126 | Value* getInstProb(Instruction* I); 127 | std::string demangle(std::string name); 128 | bool viableFunction(std::string name, std::vector& flist); 129 | unsigned long updateStateFile(const char* stateFile, unsigned long sum); 130 | 131 | bool injectControl(Instruction* I); 132 | bool injectArithmetic(Instruction* I); 133 | bool injectPointer(Instruction* I); 134 | bool injectCall(Instruction* I); 135 | 136 | bool injectVector(Instruction* I); 137 | bool injectControl_NEW(Instruction* I); 138 | bool injectArithmetic_NEW(Instruction* I); 139 | bool injectPointer_NEW(Instruction* I); 140 | bool injectCall_NEW(Instruction* I); 141 | bool injectResult(Instruction* I); 142 | bool injectInOperand(Instruction* I, int operand); 143 | 144 | bool inject_Store_Data(Instruction* I, CallInst* CallI); 145 | bool inject_Compare(Instruction* I, CallInst* CallI); 146 | bool inject_Generic(Instruction* I, CallInst* CallI, BasicBlock* BB); 147 | 148 | bool inject_Store_Ptr(Instruction* I, CallInst* CallI); 149 | bool inject_Load_Ptr(Instruction* I, CallInst* CallI, BasicBlock* BB); 150 | bool inject_Alloc_Ptr(Instruction* I, CallInst* CallI, BasicBlock* BB); 151 | bool inject_Call(Instruction* I, CallInst* CallI, BasicBlock* BB); 152 | bool inject_GetElementPtr_Ptr(Instruction* I, CallInst* CallI, BasicBlock* BB); 153 | 154 | bool copyMetadata(Instruction* New, Instruction* Old); 155 | unsigned long cacheFunctions(); 156 | bool injectFault(Instruction* I); 157 | 158 | Module* M; 159 | LogFile* logfile; 160 | DataLayout* Layout; 161 | 162 | Value* func_corruptIntData_8bit; 163 | Value* func_corruptIntData_16bit; 164 | Value* func_corruptIntData_32bit; 165 | Value* func_corruptIntData_64bit; 166 | Value* func_corruptPtr2Int_64bit; 167 | Value* func_corruptFloatData_32bit; 168 | Value* func_corruptFloatData_64bit; 169 | Value* func_corruptIntAdr_8bit; 170 | Value* func_corruptIntAdr_16bit; 171 | Value* func_corruptIntAdr_32bit; 172 | Value* func_corruptIntAdr_64bit; 173 | Value* func_corruptFloatAdr_32bit; 174 | Value* func_corruptFloatAdr_64bit; 175 | 176 | // used for display and analysis 177 | Type* i64Ty; 178 | std::vector args; 179 | std::map byteVal; 180 | std::map funcProbs; 181 | std::map instProbs; 182 | int comment; 183 | int injectionType; 184 | std::stringstream strStream; 185 | unsigned int oldFaultIdx; 186 | unsigned int faultIdx; 187 | unsigned int displayIdx; 188 | unsigned int parameter; 189 | std::vector flist; 190 | std::vector phis; 191 | bool simdInst; 192 | };/*end class definition*/ 193 | }/*end namespace*/ 194 | 195 | #ifdef COMPILE_PASS 196 | char FlipIt::DynamicFaults::ID = 0; 197 | static RegisterPass F0("FlipIt", "Dynamic Fault Injection emulating transient hardware error behavior"); 198 | #endif 199 | 200 | #endif 201 | --------------------------------------------------------------------------------