Skip to content

Commit

Permalink
typeart compiler wrapper (#83)
Browse files Browse the repository at this point in the history
* TypeART compiler wrapper for clang/clang++ and wit MPI: mpicc/mpic++ as install targets
* demo (Makefile and CMake) rely on the wrappers
* Naming scheme now typeart-* for all installed scripts
  • Loading branch information
ahueck authored Jul 11, 2021
1 parent 0a5d109 commit 687ec30
Show file tree
Hide file tree
Showing 21 changed files with 815 additions and 198 deletions.
98 changes: 80 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ number of elements.

## Why use it?

Employ TypeART whenever you need type-related information of allocations in your program to verify some property, and
TypeART provides type-related information of allocations in your program to help verify some property, and to help
generate diagnostics if it doesn't hold.

For instance, low-level C-language APIs use `void`-pointers as generic types. Often, the user must specify its type and
length manually. This can be error prone. Examples for type unsafe APIs include the Message-Passing Interface (MPI),
length manually. This can be error-prone. Examples for type unsafe APIs include the Message-Passing Interface (MPI),
checkpointing libraries and numeric solver libraries. With TypeART, it is straightforward to verify that a `void`
-pointer argument to an API is, e.g., a type `T` array with length `n`.

Expand Down Expand Up @@ -47,7 +47,7 @@ MPI_Send((void*) array, length, MPI_DOUBLE, ...)
```
MUST and TypeART also handle MPI [derived datatypes](https://www.mpi-forum.org/docs/mpi-3.1/mpi31-report/node77.htm)
with complex underlying datastructures, see our [MPI Demo](#13-example-mpi-demo). For more details, see
with complex underlying data structures, see our [MPI Demo](#13-example-mpi-demo). For more details, see
our [publications](#references), or download the current release (1.8 or higher) of MUST on
its [project page](https://itc.rwth-aachen.de/must/).
Expand All @@ -57,7 +57,6 @@ its [project page](https://itc.rwth-aachen.de/must/).
* [1.1 Compiling a target code](#11-compiling-a-target-code)
* [1.1.1 Building with TypeART](#111-building-with-typeart)
* [1.1.2 Options for TypeART passes](#112-options-for-typeart-passes)
* [Example invocations](#example-invocations)
* [1.1.3 Serialized type information](#113-serialized-type-information)
* [1.1.4 Filtering allocations](#114-filtering-allocations)
* [1.2 Executing an instrumented target code](#12-executing-an-instrumented-target-code)
Expand All @@ -81,7 +80,10 @@ Making use of TypeART consists of two phases:
### 1.1 Compiling a target code
Our LLVM compiler pass plugins instrument allocations and also serialize the static type layouts of these allocations to
a yaml file (default name `types.yaml`).
a yaml file (default name `types.yaml`). To that end, we provide compiler [wrapper scripts](scripts/typeart-wrapper.in)
around Clang and MPI to apply TypeART in the `bin` folder of the TypeART installation prefix. By default, the wrappers
instrument heap, stack and global allocations. The MPI-wrappers also filter allocations that are not passed to an MPI
call, see [Section 1.1.4](#114-filtering-allocations).
#### 1.1.1 Building with TypeART
Expand All @@ -94,19 +96,45 @@ $> clang++ -O2 $(COMPILE_FLAGS) -c code.cpp -o code.o
$> clang++ $(LINK_FLAGS) code.o -o binary
```

With TypeART, the recipe needs to be changed, as we rely on the LLVM `opt` (optimizer) tool to load and apply our
TypeART passes to a target code based on the LLVM intermediate representation (IR):
With TypeART, the recipe needs to be changed to, e.g., use our provided compiler wrapper, as we rely on the LLVM `opt`
(optimizer) tool to load and apply our TypeART passes to a target code:

```shell
# Compile, replace direct clang++ call with wrapper of the TypeART installation:
$> typeart-clang++ -O2 $(COMPILE_FLAGS) -c code.cpp -o code.o
# Link, also with the wrapper:
$> typeart-clang++ $(LINK_FLAGS) code.o -o binary
```

In particular, the wrapper script does the following:

1. Compile the code down to LLVM IR, and pipe the output to the LLVM `opt` tool. (Keeping your original compile flags)
2. Apply heap instrumentation with TypeART through `opt`.
3. Optimize the code with -Ox using `opt`.
3. Optimize the code with your `-Ox` flag using `opt`.
4. Apply stack and global instrumentation with TypeART through `opt`.
5. Pipe the final output to LLVM `llc` to generate the final object file.
6. Finally, link the TypeART runtime library.
6. Finally, link the TypeART runtime library using your linker flags.

*Note*: We instrument heap allocations before any optimization, as the compiler may throw out type information of these
allocations (for optimization reasons).

##### Wrapper usage in CMake build systems

For plain Makefiles, the wrapper replaces the GCC/Clang compiler variables, e.g., `CC` or `MPICC`. For CMake, during the
configuration, it is advised to disable the wrapper temporarily. This is due to CMake executing internal compiler
checks, where we do not need TypeART instrumentation:

```shell
# Temporarily disable wrapper with environment flag TYPEART_WRAPPER=OFF for configuration:
$> TYPEART_WRAPPER=OFF cmake -B build -DCMAKE_C_COMPILER=*TypeART bin*/typeart-clang
# Compile with TypeART now:
$> cmake --build build --target install
```

##### Internal wrapper invocation

For reference, the wrapper script executes the following (pseudo):

```shell
# Compile: 1.Code-To-LLVM | 2.TypeART_HEAP | 3.Optimize | 4.TypeART_Stack | 5.Object-file
$> clang++ $(COMPILE_FLAGS) $(EMIT_LLVM_IR_FLAGS) code.cpp | opt $(TYPEART_PLUGIN) $(HEAP_ONLY_FLAGS) | opt -O2 -S | opt $(TYPEART_PLUGIN) $(STACK_ONLY_FLAGS) | llc $(TO_OBJECT_FILE)
Expand All @@ -116,7 +144,7 @@ $> clang++ $(LINK_FLAGS) -L$(TYPEART_LIBPATH) -ltypeart-rt code.o -o binary

#### 1.1.2 Options for TypeART passes

The main options are shown below.
For modification of the pass behavior, we provide several options.

| Flag | Default | Description |
| --- | :---: | --- |
Expand All @@ -139,8 +167,8 @@ The main options are shown below.
```
2. Input of `opt` is LLVM IR, e.g.:
```shell
# Pipe LLVM IR to console
clang++ -g -Xclang -disable-llvm-passes -S -emit-llvm -o - example.cpp
# Pipe LLVM IR to console:
$> clang++ -g -Xclang -disable-llvm-passes -S -emit-llvm -o - example.cpp
```

###### Examples
Expand All @@ -166,8 +194,6 @@ The main options are shown below.
opt $(TYPEART_PLUGIN) -typeart -typeart-alloca -call-filter
```

Also consult the [demo Makefile](demo/Makefile) for an example recipe, and flags for TypeART.

#### 1.1.3 Serialized type information

After instrumentation, the file `types.yaml` contains the static type information. Each user-defined type layout is
Expand All @@ -186,6 +212,7 @@ struct s1_t {

The TypeART pass may write a `types.yaml` file with the following content:
<!--- @formatter:off --->

```yaml
- id: 256 // struct type-id
name: struct.s1_t
Expand All @@ -195,6 +222,7 @@ The TypeART pass may write a `types.yaml` file with the following content:
types: [ 0, 10 ] // member type-ids (0->char, 10->pointer)
sizes: [ 3, 1 ] // member (array) length
```

<!--- @formatter:on --->

#### 1.1.4 Filtering allocations
Expand Down Expand Up @@ -229,8 +257,9 @@ callbacks. The library also requires access to the `types.yaml` file to correlat
layouts. To specify its path, you can use the environment variable `TA_TYPE_FILE`, e.g.:

```shell
export TA_TYPE_FILE=/shared/types.yaml
env LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(TYPEART_LIBPATH) ./binary
$> export TA_TYPE_FILE=/shared/types.yaml
# If the TypeART runtime is not resolved, LD_LIBRARY_PATH is set:
$> env LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(TYPEART_LIBPATH) ./binary
```

An example for pre-loading a TypeART-based library in the context of MPI is found in the demo,
Expand All @@ -244,14 +273,31 @@ in [tool.c](demo/tool.c). The check library uses the TypeART [runtime query inte
It overloads the required MPI calls and checks that the passed `void*` buffer is correct w.r.t. the MPI derived
datatype.

To compile and run the demo targets:

- Makefile
```shell
# Valid MPI demo:
$> MPICC=*TypeART prefix*/bin/typeart-mpicc make run-demo
# Type-error MPI demo:
$> MPICC=*TypeART prefix*/bin/typeart-mpicc make run-demo_broken
```
- CMake, likewise:
```shell
$> TYPEART_WRAPPER=OFF cmake -S demo -B build_demo -DCMAKE_C_COMPILER=*TypeART prefix*/bin/typeart-mpicc
$> cmake --build build_demo --target run-demo
$> cmake --build build_demo --target run-demo_broken
```

## 2. Building TypeART

TypeART requires LLVM version 10 and CMake version >= 3.14.

### 2.1 Optional software requirements

- MPI library: Needed for some tests, the [demo](demo), our [MPI interceptor library](lib/mpi_interceptor), and for
logging with our TypeART runtime library within an MPI target application.
- MPI library: (soft requirement) Needed for the MPI compiler wrappers, tests, the [demo](demo),
our [MPI interceptor library](lib/mpi_interceptor), and for logging with our TypeART runtime library within an MPI
target application.
- OpenMP-enabled Clang compiler: Needed for some tests.

Other smaller, external dependencies are defined within the [externals folder](externals) (depending on configuration
Expand All @@ -273,48 +319,64 @@ $> cmake --build build --target install --parallel

#### 2.2.1 CMake configuration: Options for users

##### Binaries (scripts)

<!--- @formatter:off --->
| Option | Default | Description |
| --- | :---: | --- |
| `ENABLE_MPI_WRAPPER` | `ON` | Install TypeART MPI wrapper (mpic, mpic++). Requires MPI. |
<!--- @formatter:on --->

##### Runtime

<!--- @formatter:off --->

| Option | Default | Description |
| --- | :---: | --- |
| `USE_ABSL` | `ON` | Enable usage of btree-backed map of the [Abseil project](https://abseil.io/) instead of `std::map` |
| `USE_BTREE` | `OFF` | *Deprecated*. Enable usage of a [btree-backed map](https://github.com/ahueck/cpp-btree) (alternative to Abseil) instead of `std::map` |
| `SOFTCOUNTERS` | `OFF` | Enable runtime tracking of #tracked addrs. / #distinct checks / etc. |
| `LOG_LEVEL_RT` | `0` | Granularity of runtime logger. 3 ist most verbose, 0 is least |

<!--- @formatter:on --->

###### Runtime thread-safety options

Default mode is to protect the global data structure with a (shared) mutex. Two main options exist:

<!--- @formatter:off --->

| Option | Default | Description |
| --- | :---: | --- |
| `DISABLE_THREAD_SAFETY` | `OFF` | Disable thread safety of runtime |
| `ENABLE_SAFEPTR` | `OFF` | Instead of a mutex, use a special data structure wrapper for concurrency, see [object_threadsafe](https://github.com/AlexeyAB/object_threadsafe) |

<!--- @formatter:on --->

##### LLVM passes

<!--- @formatter:off --->

| Option | Default | Description |
| --- | :---: | --- |
| `SHOW_STATS` | `ON` | Passes show compile-time summary w.r.t. allocations counts |
| `MPI_INTERCEPT_LIB` | `ON` | Library to intercept MPI calls by preloading and check whether TypeART tracks the buffer pointer |
| `MPI_LOGGER` | `ON` | Enable better logging support in MPI execution context |
| `LOG_LEVEL` | `0` | Granularity of pass logger. 3 ist most verbose, 0 is least |

<!--- @formatter:on --->

##### Testing

<!--- @formatter:off --->

| Option | Default | Description |
| --- | :---: | --- |
| `TEST_CONFIG` | `OFF` | Set (force) logging levels to appropriate levels for test runner to succeed |
| `ENABLE_CODE_COVERAGE` | `OFF` | Enable code coverage statistics using LCOV 1.14 and genhtml (gcovr optional) |
| `ENABLE_LLVM_CODE_COVERAGE` | `OFF` | Enable llvm-cov code coverage statistics (llvm-cov and llvm-profdata required) |
| `ENABLE_ASAN, TSAN, UBSAN` | `OFF` | Enable Clang sanitizers (tsan is mutually exlusive w.r.t. ubsan and asan as they don't play well together) |
<!--- @formatter:on --->
## References
Expand Down
5 changes: 4 additions & 1 deletion cmake/ToolchainOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ option(ENABLE_SAFEPTR "Use external safe_ptr map wrapper instead of mutex" OFF)
cmake_dependent_option(DISABLE_THREAD_SAFETY "Explicitly make runtime *not* thread-safe." OFF "NOT ENABLE_SAFEPTR" OFF)
cmake_dependent_option(ENABLE_ASAN "Build runtime lib and tests with fsanitize=address." OFF "NOT ENABLE_TSAN" OFF)
cmake_dependent_option(ENABLE_UBSAN "Build runtime lib and tests with fsanitize=undefined." OFF "NOT ENABLE_TSAN" OFF)
option(INSTALL_UTIL_SCRIPTS "Install single file build and run scripts" OFF)
mark_as_advanced(INSTALL_UTIL_SCRIPTS)
option(ENABLE_MPI_WRAPPER "Generate mpicc and mpic++ wrapper for TypeART" ON)

include(AddLLVM)
include(llvm-lit)
Expand All @@ -43,7 +46,7 @@ if (TEST_CONFIG)
set(LOG_LEVEL_RT 3 CACHE STRING "" FORCE)
endif ()

if (MPI_LOGGER)
if (MPI_LOGGER OR ENABLE_MPI_WRAPPER OR MPI_INTERCEPT_LIB)
find_package(MPI REQUIRED)
endif ()

Expand Down
53 changes: 2 additions & 51 deletions demo/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.14)

project(MPI_type_demo
LANGUAGES C)
Expand All @@ -8,48 +8,8 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

find_package(MPI REQUIRED)

message(STATUS "Searching here: " ${CMAKE_PREFIX_PATH})

# required to load typelib before runtime!
# (cf. https://stackoverflow.com/a/50064639)
find_package(typeart_typelib REQUIRED)
find_package(typeart_runtime REQUIRED)


find_package(typeart_llvm REQUIRED)
get_property(TYPEART_PASS_LOC TARGET typeart::typeartpass PROPERTY LOCATION)
get_property(TYPEART_MEMINST_PASS_LOC TARGET typeart::meminstfinderpass PROPERTY LOCATION)


function(make_mpi_target target)
target_link_libraries(${target} ${MPI_LIBRARIES})

set_target_properties(${target} PROPERTIES
COMPILE_FLAGS
${MPI_C_COMPILE_FLAGS}
)

set_target_properties(${target} PROPERTIES
LINK_FLAGS
${MPI_C_LINK_FLAGS}
)

target_include_directories(${target}
SYSTEM
PUBLIC
${MPI_C_INCLUDE_PATH}
)
endfunction()

function(apply_pass target)
# need to link runtime for the instrumentation function symbols, otherwise it errors out:
# target_link_libraries(${target}
# typeart::runtime
# )
set_target_properties(${target} PROPERTIES
COMPILE_FLAGS
"-Xclang -load -Xclang ${TYPEART_MEMINST_PASS_LOC} -Xclang -load -Xclang ${TYPEART_PASS_LOC} -mllvm -alloca-array-only=false -mllvm -typeart-alloca"
)
target_link_libraries(${target} PUBLIC MPI::MPI_C)
endfunction()

function(make_run_target target comment)
Expand All @@ -63,29 +23,20 @@ function(make_run_target target comment)
add_dependencies(run-${target} tool)
endfunction()



add_library(tool SHARED
tool.c
)
make_mpi_target(tool)
target_link_libraries(tool
typeart::runtime
)


add_executable(demo
01_struct_example.c
)
make_mpi_target(demo)
apply_pass(demo)
make_run_target(demo "Working demo")


add_executable(demo_broken
02_broken_struct_example.c
)
make_mpi_target(demo_broken)
apply_pass(demo_broken)
make_run_target(demo_broken "Broken demo")

Loading

0 comments on commit 687ec30

Please sign in to comment.