Skip to content

Commit 6875d77

Browse files
authored
Merge pull request swiftlang#22016 from BalestraPatrick/create-benchmark-script
2 parents ff0d764 + 3c6b3ab commit 6875d77

File tree

4 files changed

+190
-4
lines changed

4 files changed

+190
-4
lines changed

benchmark/README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,17 @@ Adding New Benchmarks
132132

133133
The harness generator supports both single and multiple file tests.
134134

135-
To add a new single file test:
135+
To add a new single file test, execute the following script with the new of the benchmark:
136136

137+
```
138+
swift-source$ ./swift/benchmark/scripts/create_benchmark.py YourTestNameHere
139+
```
140+
141+
The script will automatically:
137142
1. Add a new Swift file (`YourTestNameHere.swift`), built according to
138143
the template below, to the `single-source` directory.
139-
2. Add the filename of the new Swift file to CMakeLists.txt
140-
3. Edit `main.swift`. Import and register your new Swift module.
144+
2. Add the filename of the new Swift file to `CMakeLists.txt`.
145+
3. Edit `main.swift` by importing and registering your new Swift module.
141146

142147
To add a new multiple file test:
143148

benchmark/scripts/Template.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===--- {name}.swift -------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import TestsUtils
14+
15+
public let {name} = [
16+
BenchmarkInfo(name: "{name}", runFunction: run_{name}, tags: [.validation, .api]),
17+
]
18+
19+
@inline(never)
20+
public func run_{name}(N: Int) {{
21+
// TODO
22+
}}

benchmark/scripts/create_benchmark.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
#!/usr/bin/env python
2+
3+
import argparse
4+
import os
5+
import re
6+
7+
8+
def main():
9+
p = argparse.ArgumentParser()
10+
p.add_argument('name', help='The name of the new benchmark to be created')
11+
args = p.parse_args()
12+
13+
# adds benchmark to `CMakeLists.txt`
14+
update_cmakelists(args.name)
15+
# create benchmark Swift file
16+
create_benchmark_file(args.name)
17+
# imports the benchmark module in `main.swift`
18+
add_import_benchmark(args.name)
19+
# registers the benchmark with the driver in `main.swift`
20+
add_register_benchmark(args.name)
21+
22+
23+
def update_cmakelists(name):
24+
"""Adds a new entry to the `CMakeLists.txt` file with the given
25+
benchmark name.
26+
"""
27+
relative_path = create_relative_path('../CMakeLists.txt')
28+
29+
file_contents = []
30+
with open(relative_path, 'r') as f:
31+
file_contents = f.readlines()
32+
33+
file_new_contents = insert_line_alphabetically(
34+
name,
35+
' single-source/' + name + '\n',
36+
file_contents,
37+
r" single-source\/([a-zA-Z]+)"
38+
)
39+
with open(relative_path, 'w') as f:
40+
for line in file_new_contents:
41+
f.write(line)
42+
43+
44+
def create_benchmark_file(name):
45+
"""Creates a new Swift file with the given name based on the template
46+
and places it in the `single-source` directory.
47+
"""
48+
49+
template_path = create_relative_path('Template.swift')
50+
benchmark_template = ''
51+
with open(template_path, 'r') as f:
52+
benchmark_template = ''.join(f.readlines())
53+
54+
# fill in template with benchmark name.
55+
formatted_template = benchmark_template.format(name=name)
56+
57+
relative_path = create_relative_path('../single-source/')
58+
source_file_path = os.path.join(relative_path, name + '.swift')
59+
with open(source_file_path, 'w') as f:
60+
f.write(formatted_template)
61+
62+
63+
def add_import_benchmark(name):
64+
"""Adds an `import` statement to the `main.swift` file for the new
65+
benchmark.
66+
"""
67+
relative_path = create_relative_path('../utils/main.swift')
68+
69+
# read current contents into an array
70+
file_contents = []
71+
with open(relative_path, 'r') as f:
72+
file_contents = f.readlines()
73+
74+
# the test dependencies are placed before all benchmarks, so we have to
75+
# insert the benchmark in the right alphabetical order after we have seen
76+
# all test dependencies.
77+
read_test_dependencies = False
78+
previous_benchmark_name = None
79+
file_new_contents = []
80+
for line in file_contents:
81+
# check if this line is a definition of a benchmark and get its name
82+
match = re.search(r"import ([a-zA-Z]+)", line)
83+
if match and match.group(1):
84+
benchmark_name = match.group(1)
85+
# find where to insert the new benchmark in the right alphabetical
86+
# order.
87+
if (name < benchmark_name and previous_benchmark_name is None or
88+
name < benchmark_name and name > previous_benchmark_name):
89+
if read_test_dependencies:
90+
file_new_contents.append('import ' + name + '\n' + line)
91+
else:
92+
# all test dependencies are first specified, so from now
93+
# on we can look where to insert the new benchmark.
94+
read_test_dependencies = True
95+
file_new_contents.append(line)
96+
else:
97+
file_new_contents.append(line)
98+
previous_benchmark_name = benchmark_name
99+
else:
100+
file_new_contents.append(line)
101+
with open(relative_path, 'w') as f:
102+
for line in file_new_contents:
103+
f.write(line)
104+
105+
106+
def add_register_benchmark(name):
107+
"""Adds an `import` statement to the `main.swift` file for the new
108+
benchmark.
109+
"""
110+
relative_path = create_relative_path('../utils/main.swift')
111+
112+
file_contents = []
113+
with open(relative_path, 'r') as f:
114+
file_contents = f.readlines()
115+
116+
file_new_contents = insert_line_alphabetically(
117+
name,
118+
'registerBenchmark(' + name + ')\n',
119+
file_contents,
120+
r"registerBenchmark\(([a-zA-Z]+)\)"
121+
)
122+
with open(relative_path, 'w') as f:
123+
for line in file_new_contents:
124+
f.write(line)
125+
126+
127+
def insert_line_alphabetically(name, new_line, lines, regex):
128+
"""Iterates through the given lines and executes the regex on each line to
129+
find where the new benchmark should be inserted with the given `new_line`.
130+
"""
131+
# the name of the previous seen benchmark in order to insert the new
132+
# one at the correct position
133+
previous_benchmark_name = None
134+
# the new contents of the file
135+
updated_lines = []
136+
for line in lines:
137+
# apply regex and get name of benchmark on this line
138+
match = re.search(regex, line)
139+
if match and match.group(1):
140+
benchmark_name = match.group(1)
141+
# check if we're at the line where we have to insert the new
142+
# benchmark in the correct alphabetical order
143+
if (name < benchmark_name and previous_benchmark_name is None or
144+
name < benchmark_name and name > previous_benchmark_name):
145+
updated_lines.append(new_line + line)
146+
else:
147+
updated_lines.append(line)
148+
previous_benchmark_name = benchmark_name
149+
else:
150+
updated_lines.append(line)
151+
return updated_lines
152+
153+
154+
def create_relative_path(file_path):
155+
return os.path.join(os.path.dirname(__file__), file_path)
156+
157+
158+
if __name__ == "__main__":
159+
main()

benchmark/utils/main.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ registerBenchmark(CharacterPropertiesStashed)
215215
registerBenchmark(CharacterPropertiesStashedMemo)
216216
registerBenchmark(CharacterPropertiesPrecomputed)
217217
registerBenchmark(Chars)
218+
registerBenchmark(Codable)
218219
registerBenchmark(Combos)
219220
registerBenchmark(CountAlgo)
220221
registerBenchmark(ClassArrayGetter)
@@ -255,7 +256,6 @@ registerBenchmark(Histogram)
255256
registerBenchmark(InsertCharacter)
256257
registerBenchmark(IntegrateTest)
257258
registerBenchmark(IterateData)
258-
registerBenchmark(Codable)
259259
registerBenchmark(Join)
260260
registerBenchmark(LazyFilter)
261261
registerBenchmark(LinkedList)

0 commit comments

Comments
 (0)