@@ -21,8 +21,8 @@ use ruff_python_ast::PythonVersion;
21
21
struct Case {
22
22
db : ProjectDatabase ,
23
23
fs : MemoryFileSystem ,
24
- re : File ,
25
- re_path : SystemPathBuf ,
24
+ file : File ,
25
+ file_path : SystemPathBuf ,
26
26
}
27
27
28
28
// "https://raw.githubusercontent.com/python/cpython/8e8a4baf652f6e1cee7acde9d78c4b6154539748/Lib/tomllib";
@@ -59,7 +59,7 @@ type KeyDiagnosticFields = (
59
59
Severity ,
60
60
) ;
61
61
62
- static EXPECTED_DIAGNOSTICS : & [ KeyDiagnosticFields ] = & [ (
62
+ static EXPECTED_TOMLLIB_DIAGNOSTICS : & [ KeyDiagnosticFields ] = & [ (
63
63
DiagnosticId :: lint ( "unused-ignore-comment" ) ,
64
64
Some ( "/src/tomllib/_parser.py" ) ,
65
65
Some ( 22299 ..22333 ) ,
@@ -71,7 +71,7 @@ fn tomllib_path(file: &TestFile) -> SystemPathBuf {
71
71
SystemPathBuf :: from ( "src" ) . join ( file. name ( ) )
72
72
}
73
73
74
- fn setup_case ( ) -> Case {
74
+ fn setup_tomllib_case ( ) -> Case {
75
75
let system = TestSystem :: default ( ) ;
76
76
let fs = system. memory_file_system ( ) . clone ( ) ;
77
77
@@ -112,8 +112,8 @@ fn setup_case() -> Case {
112
112
Case {
113
113
db,
114
114
fs,
115
- re,
116
- re_path,
115
+ file : re,
116
+ file_path : re_path,
117
117
}
118
118
}
119
119
@@ -135,16 +135,19 @@ fn setup_rayon() {
135
135
136
136
fn benchmark_incremental ( criterion : & mut Criterion ) {
137
137
fn setup ( ) -> Case {
138
- let case = setup_case ( ) ;
138
+ let case = setup_tomllib_case ( ) ;
139
139
140
140
let result: Vec < _ > = case. db . check ( ) . unwrap ( ) ;
141
141
142
- assert_diagnostics ( & case. db , & result) ;
142
+ assert_diagnostics ( & case. db , & result, EXPECTED_TOMLLIB_DIAGNOSTICS ) ;
143
143
144
144
case. fs
145
145
. write_file_all (
146
- & case. re_path ,
147
- format ! ( "{}\n # A comment\n " , source_text( & case. db, case. re) . as_str( ) ) ,
146
+ & case. file_path ,
147
+ format ! (
148
+ "{}\n # A comment\n " ,
149
+ source_text( & case. db, case. file) . as_str( )
150
+ ) ,
148
151
)
149
152
. unwrap ( ) ;
150
153
@@ -156,15 +159,15 @@ fn benchmark_incremental(criterion: &mut Criterion) {
156
159
157
160
db. apply_changes (
158
161
vec ! [ ChangeEvent :: Changed {
159
- path: case. re_path . clone( ) ,
162
+ path: case. file_path . clone( ) ,
160
163
kind: ChangedKind :: FileContent ,
161
164
} ] ,
162
165
None ,
163
166
) ;
164
167
165
168
let result = db. check ( ) . unwrap ( ) ;
166
169
167
- assert_eq ! ( result. len( ) , EXPECTED_DIAGNOSTICS . len( ) ) ;
170
+ assert_eq ! ( result. len( ) , EXPECTED_TOMLLIB_DIAGNOSTICS . len( ) ) ;
168
171
}
169
172
170
173
setup_rayon ( ) ;
@@ -179,20 +182,20 @@ fn benchmark_cold(criterion: &mut Criterion) {
179
182
180
183
criterion. bench_function ( "red_knot_check_file[cold]" , |b| {
181
184
b. iter_batched_ref (
182
- setup_case ,
185
+ setup_tomllib_case ,
183
186
|case| {
184
187
let Case { db, .. } = case;
185
188
let result: Vec < _ > = db. check ( ) . unwrap ( ) ;
186
189
187
- assert_diagnostics ( db, & result) ;
190
+ assert_diagnostics ( db, & result, EXPECTED_TOMLLIB_DIAGNOSTICS ) ;
188
191
} ,
189
192
BatchSize :: SmallInput ,
190
193
) ;
191
194
} ) ;
192
195
}
193
196
194
197
#[ track_caller]
195
- fn assert_diagnostics ( db : & dyn Db , diagnostics : & [ Diagnostic ] ) {
198
+ fn assert_diagnostics ( db : & dyn Db , diagnostics : & [ Diagnostic ] , expected : & [ KeyDiagnosticFields ] ) {
196
199
let normalized: Vec < _ > = diagnostics
197
200
. iter ( )
198
201
. map ( |diagnostic| {
@@ -211,8 +214,86 @@ fn assert_diagnostics(db: &dyn Db, diagnostics: &[Diagnostic]) {
211
214
)
212
215
} )
213
216
. collect ( ) ;
214
- assert_eq ! ( & normalized, EXPECTED_DIAGNOSTICS ) ;
217
+ assert_eq ! ( & normalized, expected) ;
218
+ }
219
+
220
+ fn setup_micro_case ( code : & str ) -> Case {
221
+ let system = TestSystem :: default ( ) ;
222
+ let fs = system. memory_file_system ( ) . clone ( ) ;
223
+
224
+ let file_path = "src/test.py" ;
225
+ fs. write_file_all (
226
+ SystemPathBuf :: from ( file_path) ,
227
+ ruff_python_trivia:: textwrap:: dedent ( code) ,
228
+ )
229
+ . unwrap ( ) ;
230
+
231
+ let src_root = SystemPath :: new ( "/src" ) ;
232
+ let mut metadata = ProjectMetadata :: discover ( src_root, & system) . unwrap ( ) ;
233
+ metadata. apply_cli_options ( Options {
234
+ environment : Some ( EnvironmentOptions {
235
+ python_version : Some ( RangedValue :: cli ( PythonVersion :: PY312 ) ) ,
236
+ ..EnvironmentOptions :: default ( )
237
+ } ) ,
238
+ ..Options :: default ( )
239
+ } ) ;
240
+
241
+ let mut db = ProjectDatabase :: new ( metadata, system) . unwrap ( ) ;
242
+ let file = system_path_to_file ( & db, SystemPathBuf :: from ( file_path) ) . unwrap ( ) ;
243
+
244
+ db. project ( )
245
+ . set_open_files ( & mut db, FxHashSet :: from_iter ( [ file] ) ) ;
246
+
247
+ let file_path = file. path ( & db) . as_system_path ( ) . unwrap ( ) . to_owned ( ) ;
248
+
249
+ Case {
250
+ db,
251
+ fs,
252
+ file,
253
+ file_path,
254
+ }
255
+ }
256
+
257
+ fn benchmark_many_string_assignments ( criterion : & mut Criterion ) {
258
+ setup_rayon ( ) ;
259
+
260
+ criterion. bench_function ( "red_knot_micro[many_string_assignments]" , |b| {
261
+ b. iter_batched_ref (
262
+ || {
263
+ setup_micro_case (
264
+ r#"
265
+ def f(x) -> str:
266
+ s = ""
267
+ if x.attr1:
268
+ s += "attr1"
269
+ if x.attr2:
270
+ s += "attr2"
271
+ if x.attr3:
272
+ s += "attr3"
273
+ if x.attr4:
274
+ s += "attr4"
275
+ if x.attr5:
276
+ s += "attr5"
277
+ if x.attr6:
278
+ s += "attr6"
279
+ if x.attr7:
280
+ s += "attr7"
281
+ if x.attr8:
282
+ s += "attr8"
283
+ return s
284
+ "# ,
285
+ )
286
+ } ,
287
+ |case| {
288
+ let Case { db, .. } = case;
289
+ let result = db. check ( ) . unwrap ( ) ;
290
+ assert_eq ! ( result. len( ) , 0 ) ;
291
+ } ,
292
+ BatchSize :: SmallInput ,
293
+ ) ;
294
+ } ) ;
215
295
}
216
296
217
297
criterion_group ! ( check_file, benchmark_cold, benchmark_incremental) ;
218
- criterion_main ! ( check_file) ;
298
+ criterion_group ! ( micro, benchmark_many_string_assignments) ;
299
+ criterion_main ! ( check_file, micro) ;
0 commit comments