@@ -7,8 +7,7 @@ use rustpython_parser::parser::parse_program;
7
7
use rustpython_vm:: pyobject:: PyResult ;
8
8
use rustpython_vm:: Interpreter ;
9
9
use std:: collections:: HashMap ;
10
- use std:: path:: { Path , PathBuf } ;
11
- use std:: { fs, io} ;
10
+ use std:: path:: Path ;
12
11
13
12
fn bench_cpython_code ( b : & mut Bencher , source : & str ) {
14
13
let gil = cpython:: Python :: acquire_gil ( ) ;
@@ -50,32 +49,50 @@ pub fn benchmark_file_execution(
50
49
} ) ;
51
50
}
52
51
53
- pub fn benchmark_file_parsing ( group : & mut BenchmarkGroup < WallTime > , name : & str , contents : & String ) {
52
+ pub fn benchmark_file_parsing ( group : & mut BenchmarkGroup < WallTime > , name : & str , contents : & str ) {
54
53
group. throughput ( Throughput :: Bytes ( contents. len ( ) as u64 ) ) ;
55
54
group. bench_function ( BenchmarkId :: new ( "rustpython" , name) , |b| {
56
55
b. iter ( || parse_program ( contents) . unwrap ( ) )
57
56
} ) ;
58
57
group. bench_function ( BenchmarkId :: new ( "cpython" , name) , |b| {
59
58
let gil = cpython:: Python :: acquire_gil ( ) ;
60
- let python = gil. python ( ) ;
59
+ let py = gil. python ( ) ;
61
60
62
- let globals = None ;
63
- let locals = cpython:: PyDict :: new ( python ) ;
61
+ let code = std :: ffi :: CString :: new ( contents ) . unwrap ( ) ;
62
+ let fname = cpython:: PyString :: new ( py , name ) ;
64
63
65
- locals. set_item ( python, "SOURCE_CODE" , & contents) . unwrap ( ) ;
66
-
67
- let code = "compile(SOURCE_CODE, mode=\" exec\" , filename=\" minidom.py\" )" ;
68
- b. iter ( || {
69
- let res: cpython:: PyResult < cpython:: PyObject > =
70
- python. eval ( code, globals, Some ( & locals) ) ;
71
- if let Err ( e) = res {
72
- e. print ( python) ;
73
- panic ! ( "Error compiling source" )
74
- }
75
- } )
64
+ b. iter ( || parse_program_cpython ( py, & code, & fname) )
76
65
} ) ;
77
66
}
78
67
68
+ fn parse_program_cpython (
69
+ py : cpython:: Python < ' _ > ,
70
+ code : & std:: ffi:: CStr ,
71
+ fname : & cpython:: PyString ,
72
+ ) {
73
+ extern "C" {
74
+ fn PyArena_New ( ) -> * mut python3_sys:: PyArena ;
75
+ fn PyArena_Free ( arena : * mut python3_sys:: PyArena ) ;
76
+ }
77
+ use cpython:: PythonObject ;
78
+ let fname = fname. as_object ( ) ;
79
+ unsafe {
80
+ let arena = PyArena_New ( ) ;
81
+ assert ! ( !arena. is_null( ) ) ;
82
+ let ret = python3_sys:: PyParser_ASTFromStringObject (
83
+ code. as_ptr ( ) as _ ,
84
+ fname. as_ptr ( ) ,
85
+ python3_sys:: Py_file_input ,
86
+ std:: ptr:: null_mut ( ) ,
87
+ arena,
88
+ ) ;
89
+ if ret. is_null ( ) {
90
+ cpython:: PyErr :: fetch ( py) . print ( py) ;
91
+ }
92
+ PyArena_Free ( arena) ;
93
+ }
94
+ }
95
+
79
96
pub fn benchmark_pystone ( group : & mut BenchmarkGroup < WallTime > , contents : String ) {
80
97
// Default is 50_000. This takes a while, so reduce it to 30k.
81
98
for idx in ( 10_000 ..=30_000 ) . step_by ( 10_000 ) {
@@ -94,39 +111,35 @@ pub fn benchmark_pystone(group: &mut BenchmarkGroup<WallTime>, contents: String)
94
111
95
112
pub fn criterion_benchmark ( c : & mut Criterion ) {
96
113
let benchmark_dir = Path :: new ( "./benches/benchmarks/" ) ;
97
- let dirs : Vec < fs :: DirEntry > = benchmark_dir
114
+ let mut benches = benchmark_dir
98
115
. read_dir ( )
99
116
. unwrap ( )
100
- . collect :: < io:: Result < _ > > ( )
101
- . unwrap ( ) ;
102
- let paths: Vec < PathBuf > = dirs. iter ( ) . map ( |p| p. path ( ) ) . collect ( ) ;
103
-
104
- let mut name_to_contents: HashMap < String , String > = paths
105
- . into_iter ( )
106
- . map ( |p| {
107
- let name = p. file_name ( ) . unwrap ( ) . to_os_string ( ) ;
108
- let contents = fs:: read_to_string ( p) . unwrap ( ) ;
109
- ( name. into_string ( ) . unwrap ( ) , contents)
117
+ . map ( |entry| {
118
+ let path = entry. unwrap ( ) . path ( ) ;
119
+ (
120
+ path. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_owned ( ) ,
121
+ std:: fs:: read_to_string ( path) . unwrap ( ) ,
122
+ )
110
123
} )
111
- . collect ( ) ;
124
+ . collect :: < HashMap < _ , _ > > ( ) ;
112
125
113
126
// Benchmark parsing
114
127
let mut parse_group = c. benchmark_group ( "parse_to_ast" ) ;
115
- for ( name, contents) in name_to_contents . iter ( ) {
128
+ for ( name, contents) in & benches {
116
129
benchmark_file_parsing ( & mut parse_group, name, contents) ;
117
130
}
118
131
parse_group. finish ( ) ;
119
132
120
133
// Benchmark PyStone
121
- if let Some ( pystone_contents) = name_to_contents . remove ( "pystone.py" ) {
134
+ if let Some ( pystone_contents) = benches . remove ( "pystone.py" ) {
122
135
let mut pystone_group = c. benchmark_group ( "pystone" ) ;
123
136
benchmark_pystone ( & mut pystone_group, pystone_contents) ;
124
137
pystone_group. finish ( ) ;
125
138
}
126
139
127
140
// Benchmark execution
128
141
let mut execution_group = c. benchmark_group ( "execution" ) ;
129
- for ( name, contents) in name_to_contents . iter ( ) {
142
+ for ( name, contents) in & benches {
130
143
benchmark_file_execution ( & mut execution_group, name, contents) ;
131
144
}
132
145
execution_group. finish ( ) ;
0 commit comments