Skip to content

Commit 7071a89

Browse files
authored
Merge pull request #264 from ahoppen/reduce-documentation
Add documentation of how to reduce stress tester issues
2 parents 93fa532 + 9af432a commit 7071a89

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Reducing Stress Tester Failures
2+
3+
If the SourceKit stress tester job fails, this guide describes how to generate reduced and actionable bug reports from those failures.
4+
5+
1. Acquire a Swift toolchain that contains the failure. Usually the easiest way to do this is to wait a few days until a Swift open source toolchain is published with that failure. All upcoming steps assume that `/Library/Developer/Toolchains/swift-latest.xctoolchain` points to a Swift toolchain with the issue to reproduce. If you built a toolchain locally, adjust the steps as necessary.
6+
2. Install the SourceKit stress tester into the toolchain by running `Utilities/install-stress-tester-to-toolchain.sh`
7+
3. Reproduce the stress tester failure locally by running `Utilities/run-stress-tester-locally.py`, specifying `--project`, `--file-filter`, `--rewrite-modes` and `--offset-filter` from the failure mentioned in the CI failure log.
8+
- If this does not reproduce the failure, try removing `--offset-filter` since the failure might be caused by dependencies between the requests on the file, but it’s pretty rare.
9+
4. This should reproduce the stress tester failure locally and you should see a crashlog of SourceKitService in Console. It might print the same failure multiple times but the most important thing is, that the log contains an entry with `Reproduce with: \nsk-stress-test ...`. Copy the `sk-stress-test-command`
10+
5. Run the `sk-stress-test` command locally (`sk-stress-test` was installed to `/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/sk-stress-test` by step 2).
11+
- You can add `--print-actions` to get a better idea about the requests that `sk-stress-test` is performing.
12+
6. Add `--print-requests` to the `sk-stress-test` invocation and let it run until you see something like `sourcekit: [1:connection-event-handler:9731: 0.0000] Connection interrupt`. Copy the request YAML and save it to `/tmp/req.yml`
13+
7. Run this request standalone using `/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/sourcekit-lsp debug run-sourcekitd-request --request-file /tmp/req.yml`
14+
- If this does not reproduce the failure, the previous requests executed by `sk-stress-test` are needed to hit it. Extracting all of them (`split -p '^{' input.txt` is a good command) and then pass them to `sourcekit-lsp debug run-sourcekitd-request` by passing `--request-file` multiple times.
15+
8. If a single request hits the failure and it is a crash, `/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/sourcekit-lsp debug run-sourcekitd-request --request-file /tmp/req.yml` can automatically reduce the majority of the failure, a few manual reduction steps usually help towards the end. Otherwise you have to reduce it manually. The `--position` parameter to `sourcekit-lsp debug run-sourcekitd-request` can override the position in the request so you don’t have to do offset calculations.
16+
9. Build `sourcekitd-test` locally and create a lit test that reproduces the failure. Depending on the crash, it might be possible to reproduce the failure with `swift-frontend` alone.
17+
10. Depending on the failure, bisect the `swift` repository to find the commit that introduced the failure or determine the likely cause of the failure by looking at the git history between the last successful and the first failing stress tester run.
18+
11. File an issue with the lit test at https://github.com/swiftlang/swift and attach the `found by stress tester` label.
19+
12. Add an XFail for this issue to https://github.com/swiftlang/swift-source-compat-suite/blob/main/sourcekit-xfails.json. The original failure from the CI log has a template for the XFail.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env bash
2+
3+
cd $(dirname $0)/..
4+
swift package clean
5+
SWIFT_STRESS_TESTER_SOURCEKIT_SEARCHPATH=/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/lib/ swift build
6+
sudo ln -s ./.build/debug/sk-swiftc-wrapper /Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/ || true
7+
sudo ln -s ./.build/debug/sk-stress-test /Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/ || true
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env python3
2+
3+
import argparse
4+
import subprocess
5+
import os
6+
import pathlib
7+
8+
def parse_args() -> argparse.Namespace:
9+
parser = argparse.ArgumentParser()
10+
parser.add_argument('-p', '--project', help='The project to stress-test')
11+
parser.add_argument('-f', '--file-filter', default=None, help='Only stress-test files whose file contains this substring')
12+
parser.add_argument('-r', '--rewrite-modes', default='none insideOut concurrent', help='Perform the these rewrite modes. (default: %(default)s)')
13+
parser.add_argument('-o', '--offset-filter', help='If specified, only stress test actions at this offset')
14+
parser.add_argument('--source-compat-suite', help='Path to the swift-source-compat-suite directory')
15+
parser.add_argument('--swiftc', required=True, help='Path to the swiftc inside the toolchain to stress-test')
16+
parser.add_argument('--xcode', help='The Xcode.app whose SDK to use to compile the projects')
17+
parser.add_argument('--request-durations', default='/tmp/request-durations.json', help='A file where the measured request durations will be saved to')
18+
return parser.parse_args()
19+
20+
def main():
21+
args = parse_args()
22+
if os.path.exists(args.request_durations):
23+
os.remove(args.request_durations)
24+
if not args.xcode:
25+
args.xcode = subprocess.check_output(["xcode-select", "-p"], encoding='utf-8').strip()
26+
if not args.source_compat_suite:
27+
args.source_compat_suite = (pathlib.Path(__file__).parent.parent.parent.parent / "swift-source-compat-suite").resolve()
28+
print(args.source_compat_suite)
29+
30+
environ = dict(os.environ)
31+
if args.file_filter:
32+
environ['SK_STRESS_FILE_FILTER'] = args.file_filter
33+
environ['SK_STRESS_REWRITE_MODES'] = args.rewrite_modes
34+
environ['SK_XFAILS_PATH'] = os.path.join(args.source_compat_suite, 'sourcekit-xfails.json')
35+
environ['DEVELOPER_DIR'] = args.xcode
36+
environ['CODE_SIGN_IDENTITY'] = ''
37+
environ['CODE_SIGNING_REQUIRED'] = 'NO'
38+
environ['ENTITLEMENTS_REQUIRED'] = 'NO'
39+
environ['ENABLE_BITCODE'] = 'NO'
40+
environ['INDEX_ENABLE_DATA_STORE'] = 'NO'
41+
environ['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'NO'
42+
environ['SWIFT_TREAT_WARNINGS_AS_ERRORS'] = 'NO'
43+
environ['SK_STRESS_REQUEST_DURATIONS_FILE'] = args.request_durations
44+
if args.offset_filter:
45+
environ['SK_OFFSET_FILTER'] = args.offset_filter
46+
47+
subprocess.call([
48+
os.path.join(args.source_compat_suite, 'run_sk_stress_test'),
49+
'--filter-by-project', args.project,
50+
'--swiftc', args.swiftc,
51+
'--skip-tools-clone',
52+
'--skip-tools-build',
53+
'main'
54+
], env=environ)
55+
56+
if __name__ == '__main__':
57+
main()

0 commit comments

Comments
 (0)