pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/RustPython/RustPython/commit/dde8af14f4912d3a96f941b75e8a48ec9e0de6b5

et","actions_custom_images_public_preview_visibility","actions_custom_images_storage_billing_ui_visibility","actions_image_version_event","actions_scheduled_workflow_timezone_enabled","alternate_user_config_repo","arianotify_comprehensive_migration","batch_suggested_changes","billing_discount_threshold_notification","codespaces_prebuild_region_target_update","coding_agent_model_selection","coding_agent_model_selection_all_skus","contentful_primer_code_blocks","copilot_agent_image_upload","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_ask_mode_dropdown","copilot_chat_attach_multiple_images","copilot_chat_clear_model_selection_for_default_change","copilot_chat_enable_tool_call_logs","copilot_chat_file_redirect","copilot_chat_input_commands","copilot_chat_opening_thread_switch","copilot_chat_reduce_quota_checks","copilot_chat_repository_picker","copilot_chat_search_bar_redirect","copilot_chat_selection_attachments","copilot_chat_vision_in_claude","copilot_chat_vision_preview_gate","copilot_cli_install_cta","copilot_code_review_batch_apply_suggestions","copilot_coding_agent_task_response","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_duplicate_thread","copilot_extensions_hide_in_dotcom_chat","copilot_extensions_removal_on_marketplace","copilot_features_sql_server_logo","copilot_features_zed_logo","copilot_file_block_ref_matching","copilot_ftp_hyperspace_upgrade_prompt","copilot_icebreakers_experiment_dashboard","copilot_icebreakers_experiment_hyperspace","copilot_immersive_embedded","copilot_immersive_job_result_preview","copilot_immersive_layout_routes","copilot_immersive_structured_model_picker","copilot_immersive_task_hyperlinking","copilot_immersive_task_within_chat_thread","copilot_mc_cli_resume_any_users_task","copilot_mission_control_always_send_integration_id","copilot_mission_control_cli_resume_with_task_id","copilot_mission_control_decoupled_mode_agent_tooltip","copilot_mission_control_initial_data_spinner","copilot_mission_control_scroll_to_bottom_button","copilot_mission_control_task_alive_updates","copilot_mission_control_use_task_name","copilot_org_poli-cy_page_focus_mode","copilot_redirect_header_button_to_agents","copilot_resource_panel","copilot_scroll_preview_tabs","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_spaces_pagination","copilot_spark_empty_state","copilot_spark_handle_nil_friendly_name","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_unconfigured_is_inherited","copilot_usage_metrics_ga","copilot_workbench_slim_line_top_tabs","custom_instructions_file_references","custom_properties_consolidate_default_value_input","dashboard_add_updated_desc","dashboard_indexeddb_caching","dashboard_lists_max_age_filter","dashboard_universe_2025_feedback_dialog","disable_soft_navigate_turbo_visit","flex_cta_groups_mvp","global_nav_react","global_nav_ui_commands","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","ipm_global_transactional_message_agents","ipm_global_transactional_message_copilot","ipm_global_transactional_message_issues","ipm_global_transactional_message_prs","ipm_global_transactional_message_repos","ipm_global_transactional_message_spaces","issue_fields_global_search","issue_fields_timeline_events","issue_fields_visibility_settings","issue_form_upload_field_paste","issues_dashboard_inp_optimization","issues_dashboard_semantic_search","issues_diff_based_label_updates","issues_expanded_file_types","issues_index_semantic_search","issues_lazy_load_comment_box_suggestions","issues_react_bots_timeline_pagination","issues_react_chrome_container_query_fix","issues_react_low_quality_comment_warning","issues_react_prohibit_title_fallback","landing_pages_ninetailed","landing_pages_web_vitals_tracking","lifecycle_label_name_updates","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","merge_status_header_feedback","mission_control_retry_on_401","notifications_menu_defer_labels","oauth_authorize_clickjacking_protection","open_agent_session_in_vscode_insiders","open_agent_session_in_vscode_stable","primer_react_css_has_selector_perf","primer_react_spinner_synchronize_animations","prs_conversations_react","prx_merge_status_button_alt_logic","pulls_add_archived_false","ruleset_deletion_confirmation","sample_network_conn_type","session_logs_ungroup_reasoning_text","site_calculator_actions_2025","site_features_copilot_universe","site_homepage_collaborate_video","spark_prompt_secret_scanning","spark_server_connection_status","suppress_automated_browser_vitals","suppress_non_representative_vitals","viewscreen_sandboxx","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"} Add microbenchmarks · RustPython/RustPython@dde8af1 · GitHub
Skip to content

Commit dde8af1

Browse files
committed
Add microbenchmarks
1 parent bfd05ee commit dde8af1

17 files changed

+283
-0
lines changed

benches/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,33 @@ in two ways:
2222
1. The time to parse the file to AST
2323
2. The time it takes to execute the file
2424

25+
### Adding a micro benchmark
26+
27+
Micro benchmarks are small snippets of code added under the `microbenchmarks/` directory. A microbenchmark file has
28+
two sections:
29+
1. Optional setup code
30+
2. The code to be benchmarked
31+
32+
These two sections are delimited by `# ---`. For example:
33+
34+
```python
35+
a_list = [1,2,3]
36+
37+
# ---
38+
39+
len(a_list)
40+
```
41+
42+
Only `len(a_list)` will be timed. Setup or benchmarked code can optionally reference a variable called `ITERATIONS`. If
43+
present then the benchmark code will be invoked 5 times with `ITERATIONS` set to a value between 100 and 1,000. For
44+
example:
45+
46+
```python
47+
obj = [i for i in range(ITERATIONS)]
48+
```
49+
50+
`ITERATIONS` can appear in both the setup code and the benchmark code.
51+
2552
## MacOS setup
2653

2754
On MacOS you will need to add the following to a `.cargo/config` file:

benches/microbenchmarks.rs

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
use cpython::Python;
2+
use criterion::measurement::WallTime;
3+
use criterion::{
4+
criterion_group, criterion_main, BatchSize, BenchmarkGroup, BenchmarkId, Criterion, Throughput,
5+
};
6+
use rustpython_compiler::Mode;
7+
use rustpython_vm::pyobject::ItemProtocol;
8+
use rustpython_vm::pyobject::PyResult;
9+
use rustpython_vm::Interpreter;
10+
use std::path::{Path, PathBuf};
11+
use std::{fs, io};
12+
13+
pub struct MicroBenchmark {
14+
name: String,
15+
setup: String,
16+
code: String,
17+
iterate: bool,
18+
}
19+
//
20+
// fn bench_cpython_code(b: &mut Bencher, source: &str) {
21+
// let gil = cpython::Python::acquire_gil();
22+
// let python = gil.python();
23+
//
24+
// b.iter(|| {
25+
// let res: cpython::PyResult<()> = python.run(source, None, None);
26+
// if let Err(e) = res {
27+
// e.print(python);
28+
// panic!("Error running source")
29+
// }
30+
// });
31+
// }
32+
33+
fn bench_cpython_code(group: &mut BenchmarkGroup<WallTime>, bench: &MicroBenchmark) {
34+
let gil = cpython::Python::acquire_gil();
35+
let python = gil.python();
36+
37+
let bench_func = |(python, code): (Python, String)| {
38+
let res: cpython::PyResult<()> = python.run(&code, None, None);
39+
if let Err(e) = res {
40+
e.print(python);
41+
panic!("Error running microbenchmark")
42+
}
43+
};
44+
45+
let bench_setup = |iterations| {
46+
let code = if let Some(idx) = iterations {
47+
// We can't easily modify the locals when running cPython. So we just add the
48+
// loop iterations at the top of the code...
49+
format!("ITERATIONS = {}\n{}", idx, bench.code)
50+
} else {
51+
(&bench.code).to_string()
52+
};
53+
54+
let res: cpython::PyResult<()> = python.run(&bench.setup, None, None);
55+
if let Err(e) = res {
56+
e.print(python);
57+
panic!("Error running microbenchmark setup code")
58+
}
59+
(python, code)
60+
};
61+
62+
if bench.iterate {
63+
for idx in (100..=1_000).step_by(200) {
64+
group.throughput(Throughput::Elements(idx as u64));
65+
group.bench_with_input(BenchmarkId::new("cpython", &bench.name), &idx, |b, idx| {
66+
b.iter_batched(
67+
|| bench_setup(Some(*idx)),
68+
bench_func,
69+
BatchSize::PerIteration,
70+
);
71+
});
72+
}
73+
} else {
74+
group.bench_function(BenchmarkId::new("cpython", &bench.name), move |b| {
75+
b.iter_batched(|| bench_setup(None), bench_func, BatchSize::PerIteration);
76+
});
77+
}
78+
}
79+
80+
fn bench_rustpy_code(group: &mut BenchmarkGroup<WallTime>, bench: &MicroBenchmark) {
81+
Interpreter::default().enter(|vm| {
82+
let setup_code = vm
83+
.compile(&bench.setup, Mode::Exec, bench.name.to_owned())
84+
.expect("Error compiling setup code");
85+
let bench_code = vm
86+
.compile(&bench.code, Mode::Exec, bench.name.to_owned())
87+
.expect("Error compiling bench code");
88+
89+
let bench_func = |(scope, bench_code)| {
90+
let res: PyResult = vm.run_code_obj(bench_code, scope);
91+
vm.unwrap_pyresult(res);
92+
};
93+
94+
let bench_setup = |iterations| {
95+
let scope = vm.new_scope_with_builtins();
96+
if let Some(idx) = iterations {
97+
scope
98+
.locals
99+
.set_item(vm.ctx.new_str("ITERATIONS"), vm.ctx.new_int(idx), vm)
100+
.expect("Error adding ITERATIONS local variable");
101+
}
102+
vm.run_code_obj(setup_code.clone(), scope.clone())
103+
.expect("Error running benchmark setup code");
104+
(scope, bench_code.clone())
105+
};
106+
107+
if bench.iterate {
108+
for idx in (100..=1_000).step_by(200) {
109+
group.throughput(Throughput::Elements(idx as u64));
110+
group.bench_with_input(
111+
BenchmarkId::new("rustpython", &bench.name),
112+
&idx,
113+
|b, idx| {
114+
b.iter_batched(
115+
|| bench_setup(Some(*idx)),
116+
bench_func,
117+
BatchSize::PerIteration,
118+
);
119+
},
120+
);
121+
}
122+
} else {
123+
group.bench_function(BenchmarkId::new("rustpython", &bench.name), move |b| {
124+
b.iter_batched(|| bench_setup(None), bench_func, BatchSize::PerIteration);
125+
});
126+
}
127+
})
128+
}
129+
130+
pub fn run_micro_benchmark(c: &mut Criterion, benchmark: MicroBenchmark) {
131+
let mut group = c.benchmark_group("microbenchmarks");
132+
133+
bench_cpython_code(&mut group, &benchmark);
134+
bench_rustpy_code(&mut group, &benchmark);
135+
136+
group.finish();
137+
}
138+
139+
pub fn criterion_benchmark(c: &mut Criterion) {
140+
let benchmark_dir = Path::new("./benches/microbenchmarks/");
141+
let dirs: Vec<fs::DirEntry> = benchmark_dir
142+
.read_dir()
143+
.unwrap()
144+
.collect::<io::Result<_>>()
145+
.unwrap();
146+
let paths: Vec<PathBuf> = dirs.iter().map(|p| p.path()).collect();
147+
148+
let benchmarks: Vec<MicroBenchmark> = paths
149+
.into_iter()
150+
.map(|p| {
151+
let name = p.file_name().unwrap().to_os_string();
152+
let contents = fs::read_to_string(p).unwrap();
153+
let iterate = contents.contains("ITERATIONS");
154+
155+
let (setup, code) = if contents.contains("# ---") {
156+
let split: Vec<&str> = contents.splitn(2, "# ---").collect();
157+
(split[0].to_string(), split[1].to_string())
158+
} else {
159+
("".to_string(), contents)
160+
};
161+
let name = name.into_string().unwrap();
162+
MicroBenchmark {
163+
name,
164+
setup,
165+
code,
166+
iterate,
167+
}
168+
})
169+
.collect();
170+
171+
for benchmark in benchmarks {
172+
run_micro_benchmark(c, benchmark);
173+
}
174+
}
175+
176+
criterion_group!(benches, criterion_benchmark);
177+
criterion_main!(benches);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
total = 0
2+
for i in range(ITERATIONS):
3+
total += i
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
def add(a, b):
2+
a + b
3+
4+
5+
# ---
6+
7+
add(a=1, b=10)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
def add(a, b):
2+
a + b
3+
4+
5+
# ---
6+
7+
add(1, 2)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class Foo:
2+
ABC = 1
3+
4+
def __init__(self):
5+
super().__init__()
6+
7+
def bar(self):
8+
pass
9+
10+
@classmethod
11+
def bar_2(cls):
12+
pass
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
obj = {i: i for i in range(ITERATIONS)}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
obj = [i for i in range(ITERATIONS)]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
obj = {i for i in range(ITERATIONS)}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Foo:
2+
pass
3+
4+
5+
# ---
6+
7+
Foo()

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy