You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add more short-circuit optimization scenarios for OR and AND #15636
changed the title [-]Add some scenarios for `OR` and `AND` short-circuit optimization[/-][+]Add more short-circuit optimization scenarios for `OR` and `AND`[/+]on Apr 8, 2025
@kosiew Thank you very much for your hard work and contribution. However, there might still be a point regarding a short-circuit optimization worth discussing: #15631 (comment)
If this optimization is confirmed, I think it could be achieved by returning an enum structure similar to the one below:
on main branch
cargo bench --bench binary_op --profile=profiling -- --save-baseline main
on feature branch
cargo bench --bench binary_op --profile=profiling -- --baseline main
compare
python ...python-scripts/critcmp.py
#!/usr/bin/env python3importosimportjsonimporttyperfromtypingimportOptional, ListfrompathlibimportPathfromrich.consoleimportConsolefromrich.tableimportTablefromrichimportprintasrprintapp=typer.Typer()
console=Console()
# ConstantsDEFAULT_CRITERION_DIR=Path.home() /".cargo"/"target"/"criterion"deffind_criterion_dir() ->Path:
"""Locate the criterion directory in the user's cargo target directory."""ifDEFAULT_CRITERION_DIR.exists():
returnDEFAULT_CRITERION_DIRraiseFileNotFoundError(
"Could not find criterion directory. Please specify path explicitly."
)
defparse_estimates_json(benchmark_dir: Path) ->dict:
"""Parse the estimates.json file for a benchmark to extract performance data."""change_file=benchmark_dir/"change"/"estimates.json"ifnotchange_file.exists():
returnNonewithopen(change_file, "r") asf:
data=json.load(f)
returndatadefget_benchmark_change(data: dict) ->dict:
"""Extract the relevant change metrics from the estimates data."""ifnotdataor"mean"notindata:
returnNoneresult= {
"mean_change": data["mean"]["point_estimate"],
"mean_pct": data["mean"]["point_estimate"] *100,
"median_change": data["median"]["point_estimate"],
"median_pct": data["median"]["point_estimate"] *100,
}
returnresultdefget_default_criterion_dir() ->Path:
"""Return the default Criterion directory path."""returnDEFAULT_CRITERION_DIRdefget_default_output_file(criterion_dir: Path=None) ->str:
"""Return the default output file path in the report folder."""ifcriterion_dirisNone:
criterion_dir=get_default_criterion_dir()
report_dir=criterion_dir/"report"ifnotreport_dir.exists():
report_dir.mkdir(exist_ok=True)
returnstr(report_dir/"summary_critcmp.txt")
defformat_percentage(value: float) ->str:
"""Format a number as a percentage string with +/- sign."""ifvalue<0:
returnf"[green]-{abs(value):.2f}%[/green]"# Improvement (negative is good)else:
returnf"[red]+{value:.2f}%[/red]"# Regression@app.command()defanalyze(
criterion_dir: Path=typer.Option(
get_default_criterion_dir(),
"--dir",
"-d",
help="Path to the criterion directory",
exists=True,
dir_okay=True,
file_okay=False,
),
threshold: float=typer.Option(
1.0, "--threshold", "-t", help="Threshold percentage for significant changes"
),
output_file: str=typer.Option(
None, # None here to allow dynamic default based on criterion_dir"--output",
"-o",
help="Output file for the summary (defaults to <criterion_dir>/report/summary_critcmp.txt)",
),
detailed: bool=typer.Option(False, "--detailed", help="Show detailed metrics"),
):
"""Analyze Criterion benchmark results and summarize improvements and regressions. This script should be run after executing 'cargo bench' twice: 1. First run 'cargo bench' for your baseline/current code 2. Then make your changes and run 'cargo bench' again The script will then analyze and summarize the performance differences between the baseline and your changes, highlighting improvements and regressions. """# Set default output file if not specifiedifoutput_fileisNone:
output_file=get_default_output_file(criterion_dir)
# Create table for resultstable=Table(title="Criterion Benchmark Summary")
table.add_column("Benchmark", style="cyan")
table.add_column("Mean Change", justify="right")
ifdetailed:
table.add_column("Median Change", justify="right")
# Find all benchmark directoriesbenchmark_dirs= [
dfordincriterion_dir.iterdir() ifd.is_dir() andd.name!="report"
]
results= []
forbenchmark_dirinbenchmark_dirs:
data=parse_estimates_json(benchmark_dir)
ifdata:
change_data=get_benchmark_change(data)
ifchange_data:
# Only include changes above the thresholdifabs(change_data["mean_pct"]) >=threshold:
benchmark_name=benchmark_dir.namemean_formatted=format_percentage(change_data["mean_pct"])
ifdetailed:
median_formatted=format_percentage(change_data["median_pct"])
table.add_row(benchmark_name, mean_formatted, median_formatted)
results.append(
(
benchmark_name,
change_data["mean_pct"],
change_data["median_pct"],
)
)
else:
table.add_row(benchmark_name, mean_formatted)
results.append((benchmark_name, change_data["mean_pct"]))
# Display resultsconsole.print(table)
# Summary statisticsimprovements=sum(1forrinresultsifr[1] <0)
regressions=sum(1forrinresultsifr[1] >0)
console.print(f"\nSummary: {improvements} improvements, {regressions} regressions")
# Save to file if requestedifoutput_file:
withopen(output_file, "w") asf:
f.write(f"Criterion Benchmark Summary\n\n")
forresultinresults:
benchmark_name=result[0]
mean_pct=result[1]
sign="-"ifmean_pct<0else"+"f.write(f"{benchmark_name}: {sign}{abs(mean_pct):.2f}%\n")
f.write(
f"\nSummary: {improvements} improvements, {regressions} regressions\n"
)
console.print(f"Results saved to {output_file}")
if__name__=="__main__":
app()
amended the script to filter for p < 0.05 results only
#!/usr/bin/env python3importosimportjsonfrombs4importBeautifulSoupimportreimporttyperfromtypingimportOptional, ListfrompathlibimportPathfromrich.consoleimportConsolefromrich.tableimportTablefromrichimportprintasrprintapp=typer.Typer()
console=Console()
# ConstantsDEFAULT_CRITERION_DIR=Path.home() /".cargo"/"target"/"criterion"deffind_criterion_dir() ->Path:
"""Locate the criterion directory in the user's cargo target directory."""ifDEFAULT_CRITERION_DIR.exists():
returnDEFAULT_CRITERION_DIRraiseFileNotFoundError(
"Could not find criterion directory. Please specify path explicitly."
)
defparse_benchmark_report(benchmark_dir: Path) ->dict:
"""Parse the index.html report file for a benchmark to extract performance data."""report_file=benchmark_dir/"report"/"index.html"print(f"==> Checking for file: {report_file}")
ifnotreport_file.exists():
print(f"==> File does not exist: {report_file}")
returnNonetry:
withopen(report_file, "r") asf:
html_content=f.read()
soup=BeautifulSoup(html_content, "html.parser")
print(f"==> Successfully parsed HTML for {benchmark_dir.name}")
# Extract performance data from the HTMLdata= {}
# Find tables that contain performance datatables=soup.find_all("table")
print(f"==> Found {len(tables)} tables in the report")
fortableintables:
# Find rows that contain "Change in time"change_rows=table.find_all(
"tr",
string=lambdatext: (
textand"Change in time"intextiftextelseFalse
),
)
ifnotchange_rows:
# Try another approach - find td with "Change in time" textforrowintable.find_all("tr"):
cells=row.find_all("td")
ifcellsandlen(cells) >0and"Change in time"incells[0].text:
print(f"==> Found 'Change in time' row")
# The percentage change is in the middle column (index 2)iflen(cells) >2:
change_text=cells[2].text.strip()
change_match=re.search(r"([+-]?\d+\.\d+)%", change_text)
ifchange_match:
percentage=float(change_match.group(1))
print(f"==> Found percentage change: {percentage}%")
if"mean"notindata:
data["mean"] = {}
data["mean"]["point_estimate"] =percentage/100# The p-value is in the last columniflen(cells) >4:
p_value_text=cells[4].text.strip()
p_value_match=re.search(
r"p\s*=\s*(\d+\.\d+)", p_value_text
)
if (
notp_value_match
): # Try another format for p = 0.00 < 0.05p_value_match=re.search(
r"p\s*=\s*(\d+\.\d+)\s*[<>=]", p_value_text
)
ifp_value_match:
p_value=float(p_value_match.group(1))
print(f"==> Found p-value: {p_value}")
if"mean"notindata:
data["mean"] = {}
data["mean"]["p_value"] =p_value# If we found mean data, add a placeholder for median with the same values# This is a simplification since your HTML example only showed one rowif"mean"indata:
data["median"] =data["mean"].copy()
print(f"==> Extracted data: {data}")
returndataexceptExceptionase:
print(f"==> Error parsing report: {e}")
importtracebackprint(traceback.format_exc())
returnNonedefget_benchmark_change(data: dict) ->dict:
"""Extract the relevant change metrics from the estimates data."""ifnotdataor"mean"notindata:
print(f"==> Invalid data format in get_benchmark_change")
returnNoneresult= {
"mean_change": data["mean"]["point_estimate"],
"mean_pct": data["mean"]["point_estimate"] *100,
"mean_p_value": data["mean"].get(
"p_value", 1.0
), # Default to 1.0 if not present"median_change": data["median"]["point_estimate"],
"median_pct": data["median"]["point_estimate"] *100,
"median_p_value": data["median"].get(
"p_value", 1.0
), # Default to 1.0 if not present
}
print(
f"==> Extracted change data: mean_pct={result['mean_pct']:.2f}%, p_value={result['mean_p_value']}"
)
returnresultdefget_default_criterion_dir() ->Path:
"""Return the default Criterion directory path."""returnDEFAULT_CRITERION_DIRdefget_default_output_file(criterion_dir: Path=None) ->str:
"""Return the default output file path in the report folder."""ifcriterion_dirisNone:
criterion_dir=get_default_criterion_dir()
report_dir=criterion_dir/"report"ifnotreport_dir.exists():
report_dir.mkdir(exist_ok=True)
returnstr(report_dir/"summary_critcmp.txt")
defformat_percentage(value: float) ->str:
"""Format a number as a percentage string with +/- sign."""ifvalue<0:
returnf"[green]-{abs(value):.2f}%[/green]"# Improvement (negative is good)else:
returnf"[red]+{value:.2f}%[/red]"# Regression@app.command()defanalyze(
criterion_dir: Path=typer.Option(
get_default_criterion_dir(),
"--dir",
"-d",
help="Path to the criterion directory",
exists=True,
dir_okay=True,
file_okay=False,
),
threshold: float=typer.Option(
1.0, "--threshold", "-t", help="Threshold percentage for significant changes"
),
output_file: str=typer.Option(
None, # None here to allow dynamic default based on criterion_dir"--output",
"-o",
help="Output file for the summary (defaults to <criterion_dir>/report/summary_critcmp.txt)",
),
detailed: bool=typer.Option(False, "--detailed", help="Show detailed metrics"),
p_value_threshold: float=typer.Option(
0.05,
"--p-value",
"-p",
help="P-value threshold for statistical significance (default: 0.05)",
),
):
"""Analyze Criterion benchmark results and summarize improvements and regressions. This script should be run after executing 'cargo bench' twice: 1. First run 'cargo bench' for your baseline/current code 2. Then make your changes and run 'cargo bench' again The script will then analyze and summarize the performance differences between the baseline and your changes, highlighting improvements and regressions. Only statistically significant changes (p < 0.05) are included by default. """# Set default output file if not specifiedifoutput_fileisNone:
output_file=get_default_output_file(criterion_dir)
# Create table for resultstable=Table(
title="Criterion Benchmark Summary (Statistically Significant Changes)"
)
table.add_column("Benchmark", style="cyan")
table.add_column("Mean Change", justify="right")
table.add_column("P-value", justify="right")
ifdetailed:
table.add_column("Median Change", justify="right")
# Find all benchmark directoriesbenchmark_dirs= [
dfordincriterion_dir.iterdir() ifd.is_dir() andd.name!="report"
]
results= []
forbenchmark_dirinbenchmark_dirs:
print(f"\n==> Processing benchmark: {benchmark_dir.name}")
data=parse_benchmark_report(benchmark_dir)
ifdata:
change_data=get_benchmark_change(data)
ifchange_data:
print(
f"==> Checking threshold: abs({change_data['mean_pct']:.2f}) >= {threshold} = {abs(change_data['mean_pct']) >=threshold}"
)
print(
f"==> Checking p-value: {change_data['mean_p_value']} < {p_value_threshold} = {change_data['mean_p_value'] <p_value_threshold}"
)
# Only include changes above threshold AND statistically significantif (
abs(change_data["mean_pct"]) >=thresholdandchange_data["mean_p_value"] <p_value_threshold
):
print(
f"==> INCLUDED: Benchmark '{benchmark_dir.name}' meets criteria"
)
benchmark_name=benchmark_dir.namemean_formatted=format_percentage(change_data["mean_pct"])
p_value=f"{change_data['mean_p_value']:.6f}"ifdetailed:
median_formatted=format_percentage(change_data["median_pct"])
table.add_row(
benchmark_name, mean_formatted, p_value, median_formatted
)
results.append(
(
benchmark_name,
change_data["mean_pct"],
change_data["mean_p_value"],
change_data["median_pct"],
)
)
else:
table.add_row(benchmark_name, mean_formatted, p_value)
results.append(
(
benchmark_name,
change_data["mean_pct"],
change_data["mean_p_value"],
)
)
else:
print(
f"==> EXCLUDED: Benchmark '{benchmark_dir.name}' doesn't meet criteria"
)
else:
print(f"==> No valid change data for {benchmark_dir.name}")
else:
print(f"==> No data found for {benchmark_dir.name}")
# Sort results by benchmark nameresults.sort(key=lambdax: x[0])
# Rebuild the table with sorted resultstable=Table(
title="Criterion Benchmark Summary (Statistically Significant Changes)"
)
table.add_column("Benchmark", style="cyan")
table.add_column("Mean Change", justify="right")
table.add_column("P-value", justify="right")
ifdetailed:
table.add_column("Median Change", justify="right")
forresultinresults:
benchmark_name=result[0]
mean_pct=result[1]
p_value=f"{result[2]:.6f}"mean_formatted=format_percentage(mean_pct)
ifdetailedandlen(result) >3:
median_formatted=format_percentage(result[3])
table.add_row(benchmark_name, mean_formatted, p_value, median_formatted)
else:
table.add_row(benchmark_name, mean_formatted, p_value)
# Display resultsconsole.print(table)
# Summary statisticsimprovements=sum(1forrinresultsifr[1] <0)
regressions=sum(1forrinresultsifr[1] >0)
console.print(
f"\nSummary: {improvements} improvements, {regressions} regressions (p < {p_value_threshold})"
)
# Save to file if requestedifoutput_file:
withopen(output_file, "w") asf:
f.write(
f"Criterion Benchmark Summary (Statistically Significant Changes p < {p_value_threshold})\n\n"
)
forresultinresults:
benchmark_name=result[0]
mean_pct=result[1]
p_value=result[2]
sign="-"ifmean_pct<0else"+"f.write(
f"{benchmark_name}: {sign}{abs(mean_pct):.2f}% (p={p_value:.6f})\n"
)
f.write(
f"\nSummary: {improvements} improvements, {regressions} regressions\n"
)
console.print(f"Results saved to {output_file}")
if__name__=="__main__":
app()
Activity
acking-you commentedon Apr 8, 2025
It might be better to do this after it's completed at #15631.
[-]Add some scenarios for `OR` and `AND` short-circuit optimization[/-][+]Add more short-circuit optimization scenarios for `OR` and `AND`[/+]kosiew commentedon Apr 9, 2025
take
kosiew commentedon Apr 9, 2025
@acking-you
I made an attempt at this anyway as it was a quick job.
We could revisit this after #15631
acking-you commentedon Apr 9, 2025
@kosiew Thank you very much for your hard work and contribution. However, there might still be a point regarding a short-circuit optimization worth discussing: #15631 (comment)
If this optimization is confirmed, I think it could be achieved by returning an
enumstructure similar to the one below:kosiew commentedon Apr 11, 2025
Notes on generating the benchmark comparison results
mainbranchcargo bench --bench binary_op --profile=profiling -- --save-baseline main
featurebranchcargo bench --bench binary_op --profile=profiling -- --baseline main
python ...python-scripts/critcmp.py
kosiew commentedon Apr 11, 2025
amended the script to filter for p < 0.05 results only