• Home
Name
Date
Size
#Lines
LOC

..--

clear_interrupted_intrusive_test/12-May-2024-175105

CMakeLists.txtD12-May-2024874 2118

README.mdD12-May-20244.8 KiB9885

intrusive_test.cppD12-May-2024775 215

intrusive_test.hD12-May-20241.2 KiB4223

intrusive_test_option.hD12-May-20241.1 KiB3416

intrusive_test_suite.hD12-May-2024854 235

README.md

1Intrusive testing
2=================
3
4The basic idea is to have a possibility to find and to reproduce rare multithreading bugs, for example, data races.
5We may increase a chance to catch such bugs by controlling the order of synchronization events between different threads.
6The intrusive test relies on a special comments in a source code introducing control points where different threads are synchronized.
7Each intrusive test contains a map from control points to the testing code which controls the sequence of execution by waiting and signaling on test events.
8
9Each intrusive test consists of the following elements:
10- specification of synchronization points in ARK source code;
11- implementing synchronization points, which are source code modules with parameterized functions, performing synchronization actions on the base of synchronization point context and state of the test;
12- mapping of synchronization points - yaml module mapping synchronization points specifications to its implementations.
13
14Prerequisites for using intrusive tests:
15- python 3.7;
16- libclang 14.0.1;
17- python modules: clang, libclang, clade 3.5.1.
18
19How to create a new intrusive test
20----------------------------------
21
22Each intrusive test should have the following identifiers:
23- <INTRISIVE_TEST_NAME>, which represents index of this test (e.g., `CLASS_GET_BASE_INTRUSIVE_TEST`). This name is used in enum.
24- <intrusive_test_name>, which is the name of a directory with this test (e.g., `class_get_base_intrusive_test`).
25
26Let us consider, that directory with intrusive test set is `<INTRUSIVE_TESTS_RELATIVE_DIR>=runtime/tests/intrusive-tests`
27
281. Add synchronization points in the source code in the following format:
29```c++
30/* @sync <num>
31 * @description ...
32 */
33```
34`<num>` is an index of the given synchronization point in current file.
35
362. Add new test identifier (`<INTRISIVE_TEST_NAME>`) in enum in `<INTRUSIVE_TESTS_RELATIVE_DIR>/intrusive_test_suite.h`.
37
383. Create directory for intrusive test `<INTRUSIVE_TESTS_RELATIVE_DIR>/<intrusive_test_name>` and add there:
39- `bindings.yml`: mapping of synchronization code onto synchronization points in the following format:
40```yaml
41declaration: sync_api.h
42mapping:
43-
44  file: <file name>
45  class: <class name>
46  method: <method name>
47  index: <num>
48  code: |
49      <synchronization code, e.g. synchronization function calls>
50-
51...
52```
53- `sync_api.h` - declaration of synchronization functions, that usually implement wait/notify logic.
54They should be placed in a specific class as static methods to prevent name collisions, for example:
55```c++
56class IntrusiveTestNameAPI {
57public:
58    static void WaitForEvent(void);
59    static void NotifyOnEvent(void);
60};
61```
62- `sync_api.cpp` – implementation of synchronization functions.
63- source code of intrusive test (may be based on original test). This code should set test identifier with `SetTestId(<INTRISIVE_TEST_NAME>)`. One way to do this is:
64```c++
65RuntimeOptions options;
66...
67options.SetIntrusiveTest(<INTRISIVE_TEST_NAME>);
68Runtime::Create(options);
69```
70- `CMakeLists.txt` – describes how to build of the test. Example:
71```cmake
72if (IS_RUNTIME_INTRUSIVE_BUILD)
73  target_sources(arkrintime_static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/sync_api.cpp)
74else()
75  # sub-targets for building/running of the test
76  add_dependencies(intrusive_test <building target>)
77  add_dependencies(intrusive_test_run <running target>)
78endif()
79```
80
814. Add new targets in `<INTRUSIVE_TESTS_RELATIVE_DIR>/CMakeLists.txt`:
82```cmake
83add_subdirectory(<intrusive_test_name>);
84```
85
865. Launch the test
87```shell
88local_intrusive_testing.sh [-cr] <path_to_repo> <path_to_build_dir>
89```
90This script copies source code to <path_to_build_dir>, performs instrumentation there, and then launches intrusive test set.
91Use `-c` flag to clear existing build directory `<path_to_build_dir>` and `-r` to skip instrumentation stage and only run tests.
92If you need to add a file with TSAN suppressions for the tests, set up environment variable TSAN_SUPPRESSIONS.
93
94An example of intrusive test is located in `runtime/tests/intrusive-tests/clear_interrupted_intrusive_test` directory.
95This test checks a data race that would happen if we remove the lock in `ClearInterrupted()` method.
96Existing test `runtime/tests/intrusive-tests/clear_interrupted_intrusive_test/clear_interrupted_intrusive_test.cpp` checking `ClearInterrupted()` method, rarely finds the described data race, because one of two conflicting threads often finishes before `ClearInterrupted()` method is even called.
97Intrusive testing method helps TSAN data race checker to see this data race by organizing a thread interleaving on which the data race can be detected by TSan. This intrusive test (`runtime/tests/intrusive-tests/clear_interrupted_intrusive_test`) illustrates intrusive testing on example and can be used as a basis or starting point for new tests development.
98