@@ -7,8 +7,7 @@ use rustpython_parser::parser::parse_program;
77use rustpython_vm:: pyobject:: PyResult ;
88use rustpython_vm:: Interpreter ;
99use std:: collections:: HashMap ;
10- use std:: path:: { Path , PathBuf } ;
11- use std:: { fs, io} ;
10+ use std:: path:: Path ;
1211
1312fn bench_cpython_code ( b : & mut Bencher , source : & str ) {
1413 let gil = cpython:: Python :: acquire_gil ( ) ;
@@ -50,32 +49,50 @@ pub fn benchmark_file_execution(
5049 } ) ;
5150}
5251
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 ) {
5453 group. throughput ( Throughput :: Bytes ( contents. len ( ) as u64 ) ) ;
5554 group. bench_function ( BenchmarkId :: new ( "rustpython" , name) , |b| {
5655 b. iter ( || parse_program ( contents) . unwrap ( ) )
5756 } ) ;
5857 group. bench_function ( BenchmarkId :: new ( "cpython" , name) , |b| {
5958 let gil = cpython:: Python :: acquire_gil ( ) ;
60- let python = gil. python ( ) ;
59+ let py = gil. python ( ) ;
6160
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 ) ;
6463
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) )
7665 } ) ;
7766}
7867
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+
7996pub fn benchmark_pystone ( group : & mut BenchmarkGroup < WallTime > , contents : String ) {
8097 // Default is 50_000. This takes a while, so reduce it to 30k.
8198 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)
94111
95112pub fn criterion_benchmark ( c : & mut Criterion ) {
96113 let benchmark_dir = Path :: new ( "./benches/benchmarks/" ) ;
97- let dirs : Vec < fs :: DirEntry > = benchmark_dir
114+ let mut benches = benchmark_dir
98115 . read_dir ( )
99116 . 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+ )
110123 } )
111- . collect ( ) ;
124+ . collect :: < HashMap < _ , _ > > ( ) ;
112125
113126 // Benchmark parsing
114127 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 {
116129 benchmark_file_parsing ( & mut parse_group, name, contents) ;
117130 }
118131 parse_group. finish ( ) ;
119132
120133 // Benchmark PyStone
121- if let Some ( pystone_contents) = name_to_contents . remove ( "pystone.py" ) {
134+ if let Some ( pystone_contents) = benches . remove ( "pystone.py" ) {
122135 let mut pystone_group = c. benchmark_group ( "pystone" ) ;
123136 benchmark_pystone ( & mut pystone_group, pystone_contents) ;
124137 pystone_group. finish ( ) ;
125138 }
126139
127140 // Benchmark execution
128141 let mut execution_group = c. benchmark_group ( "execution" ) ;
129- for ( name, contents) in name_to_contents . iter ( ) {
142+ for ( name, contents) in & benches {
130143 benchmark_file_execution ( & mut execution_group, name, contents) ;
131144 }
132145 execution_group. finish ( ) ;
0 commit comments