Name |
Date |
Size |
#Lines |
LOC |
||
---|---|---|---|---|---|---|
.. | - | - | ||||
clear_interrupted_intrusive_test/ | 12-May-2024 | - | 175 | 105 | ||
CMakeLists.txt | D | 12-May-2024 | 874 | 21 | 18 | |
README.md | D | 12-May-2024 | 4.8 KiB | 98 | 85 | |
intrusive_test.cpp | D | 12-May-2024 | 775 | 21 | 5 | |
intrusive_test.h | D | 12-May-2024 | 1.2 KiB | 42 | 23 | |
intrusive_test_option.h | D | 12-May-2024 | 1.1 KiB | 34 | 16 | |
intrusive_test_suite.h | D | 12-May-2024 | 854 | 23 | 5 |
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