Skip to content

Commit 7dbda84

Browse files
authored
chore: update local benchmark, 10t config and kokoro project. (#995)
* chore: update local benchmark, 10t config and kokoro project. * update details * fixes * update config * update config reading * update config * remove notebook for now.
1 parent ad8263d commit 7dbda84

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+301
-199
lines changed

.kokoro/load/benchmark.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ env_vars: {
1313

1414
env_vars: {
1515
key: "GOOGLE_CLOUD_PROJECT"
16-
value: "bigframes-load-testing"
16+
value: "bigframes-benchmarking"
1717
}
1818

1919
env_vars: {

noxfile.py

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from __future__ import absolute_import
1818

19+
import argparse
1920
import multiprocessing
2021
import os
2122
import pathlib
@@ -804,7 +805,7 @@ def notebook(session: nox.Session):
804805
processes = []
805806
for notebook, regions in notebooks_reg.items():
806807
for region in regions:
807-
args = (
808+
region_args = (
808809
"python",
809810
"scripts/run_and_publish_benchmark.py",
810811
"--notebook",
@@ -814,15 +815,15 @@ def notebook(session: nox.Session):
814815
if multi_process_mode:
815816
process = multiprocessing.Process(
816817
target=_run_process,
817-
args=(session, args, error_flag),
818+
args=(session, region_args, error_flag),
818819
)
819820
process.start()
820821
processes.append(process)
821822
# Adding a small delay between starting each
822823
# process to avoid potential race conditions。
823824
time.sleep(1)
824825
else:
825-
session.run(*args)
826+
session.run(*region_args)
826827

827828
for process in processes:
828829
process.join()
@@ -861,7 +862,51 @@ def benchmark(session: nox.Session):
861862
session.install("-e", ".[all]")
862863
base_path = os.path.join("tests", "benchmark")
863864

864-
benchmark_script_list = list(pathlib.Path(base_path).rglob("*.py"))
865+
parser = argparse.ArgumentParser()
866+
parser.add_argument(
867+
"-i",
868+
"--iterations",
869+
type=int,
870+
default=1,
871+
help="Number of iterations to run each benchmark.",
872+
)
873+
parser.add_argument(
874+
"-o",
875+
"--output-csv",
876+
nargs="?",
877+
const=True,
878+
default=False,
879+
help=(
880+
"Determines whether to output results to a CSV file. If no location is provided, "
881+
"a temporary location is automatically generated."
882+
),
883+
)
884+
parser.add_argument(
885+
"-b",
886+
"--benchmark-filter",
887+
nargs="+",
888+
help=(
889+
"List of file or directory names to include in the benchmarks. If not provided, "
890+
"all benchmarks are run."
891+
),
892+
)
893+
894+
args = parser.parse_args(session.posargs)
895+
896+
benchmark_script_list: List[pathlib.Path] = []
897+
if args.benchmark_filter:
898+
for filter_item in args.benchmark_filter:
899+
full_path = os.path.join(base_path, filter_item)
900+
if os.path.isdir(full_path):
901+
benchmark_script_list.extend(pathlib.Path(full_path).rglob("*.py"))
902+
elif os.path.isfile(full_path) and full_path.endswith(".py"):
903+
benchmark_script_list.append(pathlib.Path(full_path))
904+
else:
905+
raise ValueError(
906+
f"Item {filter_item} does not match any valid file or directory"
907+
)
908+
else:
909+
benchmark_script_list = list(pathlib.Path(base_path).rglob("*.py"))
865910

866911
try:
867912
for benchmark in benchmark_script_list:
@@ -871,12 +916,15 @@ def benchmark(session: nox.Session):
871916
"python",
872917
"scripts/run_and_publish_benchmark.py",
873918
f"--benchmark-path={benchmark}",
919+
f"--iterations={args.iterations}",
874920
)
875921
finally:
876922
session.run(
877923
"python",
878924
"scripts/run_and_publish_benchmark.py",
879925
f"--publish-benchmarks={base_path}",
926+
f"--iterations={args.iterations}",
927+
f"--output-csv={args.output_csv}",
880928
)
881929

882930

scripts/run_and_publish_benchmark.py

Lines changed: 92 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import pathlib
2020
import subprocess
2121
import sys
22+
import tempfile
2223
from typing import Dict, List, Union
2324

2425
import numpy as np
@@ -50,7 +51,7 @@ def run_benchmark_subprocess(args, log_env_name_var, filename=None, region=None)
5051
subprocess.run(args, env=env, check=True)
5152

5253

53-
def collect_benchmark_result(benchmark_path: str) -> pd.DataFrame:
54+
def collect_benchmark_result(benchmark_path: str, iterations: int) -> pd.DataFrame:
5455
"""Generate a DataFrame report on HTTP queries, bytes processed, slot time and execution time from log files."""
5556
path = pathlib.Path(benchmark_path)
5657
try:
@@ -100,28 +101,23 @@ def collect_benchmark_result(benchmark_path: str) -> pd.DataFrame:
100101

101102
with open(bytes_file, "r") as file:
102103
lines = file.read().splitlines()
103-
query_count = len(lines)
104-
total_bytes = sum(int(line) for line in lines)
104+
query_count = len(lines) / iterations
105+
total_bytes = sum(int(line) for line in lines) / iterations
105106

106107
with open(millis_file, "r") as file:
107108
lines = file.read().splitlines()
108-
total_slot_millis = sum(int(line) for line in lines)
109+
total_slot_millis = sum(int(line) for line in lines) / iterations
109110

110111
if has_local_seconds:
111-
# 'local_seconds' captures the total execution time for a benchmark as it
112-
# starts timing immediately before the benchmark code begins and stops
113-
# immediately after it ends. Unlike other metrics that might accumulate
114-
# values proportional to the number of queries executed, 'local_seconds' is
115-
# a singular measure of the time taken for the complete execution of the
116-
# benchmark, from start to finish.
117112
with open(local_seconds_file, "r") as file:
118-
local_seconds = float(file.readline().strip())
113+
lines = file.read().splitlines()
114+
local_seconds = sum(float(line) for line in lines) / iterations
119115
else:
120116
local_seconds = None
121117

122118
with open(bq_seconds_file, "r") as file:
123119
lines = file.read().splitlines()
124-
bq_seconds = sum(float(line) for line in lines)
120+
bq_seconds = sum(float(line) for line in lines) / iterations
125121

126122
results_dict[str(filename)] = [
127123
query_count,
@@ -154,7 +150,12 @@ def collect_benchmark_result(benchmark_path: str) -> pd.DataFrame:
154150
columns=columns,
155151
)
156152

157-
print("---BIGQUERY USAGE REPORT---")
153+
report_title = (
154+
"---BIGQUERY USAGE REPORT---"
155+
if iterations == 1
156+
else f"---BIGQUERY USAGE REPORT (Averages over {iterations} Iterations)---"
157+
)
158+
print(report_title)
158159
for index, row in benchmark_metrics.iterrows():
159160
formatted_local_exec_time = (
160161
f"{round(row['Local_Execution_Time_Sec'], 1)} seconds"
@@ -259,32 +260,53 @@ def find_config(start_path):
259260
return None
260261

261262

262-
def run_benchmark_from_config(benchmark: str):
263+
def publish_to_bigquery(dataframe, notebook, project_name="bigframes-metrics"):
264+
bigquery_table = (
265+
f"{project_name}.benchmark_report.notebook_benchmark"
266+
if notebook
267+
else f"{project_name}.benchmark_report.benchmark"
268+
)
269+
270+
repo_status = get_repository_status()
271+
for idx, col in enumerate(repo_status.keys()):
272+
dataframe.insert(idx, col, repo_status[col])
273+
274+
pandas_gbq.to_gbq(
275+
dataframe=dataframe,
276+
destination_table=bigquery_table,
277+
if_exists="append",
278+
)
279+
print(f"Results have been successfully uploaded to {bigquery_table}.")
280+
281+
282+
def run_benchmark_from_config(benchmark: str, iterations: int):
263283
print(benchmark)
264284
config_path = find_config(benchmark)
265285

266286
if config_path:
267287
benchmark_configs = []
268288
with open(config_path, "r") as f:
269289
for line in f:
270-
config = json.loads(line)
271-
python_args = [f"--{key}={value}" for key, value in config.items()]
272-
suffix = (
273-
config["benchmark_suffix"]
274-
if "benchmark_suffix" in config
275-
else "_".join(f"{key}_{value}" for key, value in config.items())
276-
)
277-
benchmark_configs.append((suffix, python_args))
290+
if line.strip():
291+
config = json.loads(line)
292+
python_args = [f"--{key}={value}" for key, value in config.items()]
293+
suffix = (
294+
config["benchmark_suffix"]
295+
if "benchmark_suffix" in config
296+
else "_".join(f"{key}_{value}" for key, value in config.items())
297+
)
298+
benchmark_configs.append((suffix, python_args))
278299
else:
279300
benchmark_configs = [(None, [])]
280301

281-
for benchmark_config in benchmark_configs:
282-
args = ["python", str(benchmark)]
283-
args.extend(benchmark_config[1])
284-
log_env_name_var = str(benchmark)
285-
if benchmark_config[0] is not None:
286-
log_env_name_var += f"_{benchmark_config[0]}"
287-
run_benchmark_subprocess(args=args, log_env_name_var=log_env_name_var)
302+
for _ in range(iterations):
303+
for benchmark_config in benchmark_configs:
304+
args = ["python", str(benchmark)]
305+
args.extend(benchmark_config[1])
306+
log_env_name_var = str(benchmark)
307+
if benchmark_config[0] is not None:
308+
log_env_name_var += f"_{benchmark_config[0]}"
309+
run_benchmark_subprocess(args=args, log_env_name_var=log_env_name_var)
288310

289311

290312
def run_notebook_benchmark(benchmark_file: str, region: str):
@@ -341,35 +363,59 @@ def parse_arguments():
341363
help="Set the benchmarks to be published to BigQuery.",
342364
)
343365

366+
parser.add_argument(
367+
"--iterations",
368+
type=int,
369+
default=1,
370+
help="Number of iterations to run each benchmark.",
371+
)
372+
parser.add_argument(
373+
"--output-csv",
374+
type=str,
375+
default=None,
376+
help="Determines whether to output results to a CSV file. If no location is provided, a temporary location is automatically generated.",
377+
)
378+
344379
return parser.parse_args()
345380

346381

347382
def main():
348383
args = parse_arguments()
349384

350385
if args.publish_benchmarks:
351-
bigquery_table = (
352-
"bigframes-metrics.benchmark_report.notebook_benchmark"
353-
if args.notebook
354-
else "bigframes-metrics.benchmark_report.benchmark"
386+
benchmark_metrics = collect_benchmark_result(
387+
args.publish_benchmarks, args.iterations
355388
)
356-
benchmark_metrics = collect_benchmark_result(args.publish_benchmarks)
357-
358-
if os.getenv("BENCHMARK_AND_PUBLISH", "false") == "true":
359-
repo_status = get_repository_status()
360-
for idx, col in enumerate(repo_status.keys()):
361-
benchmark_metrics.insert(idx, col, repo_status[col])
362-
363-
pandas_gbq.to_gbq(
364-
dataframe=benchmark_metrics,
365-
destination_table=bigquery_table,
366-
if_exists="append",
389+
# Output results to CSV without specifying a location
390+
if args.output_csv == "True":
391+
current_time = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
392+
temp_file = tempfile.NamedTemporaryFile(
393+
prefix=f"benchmark_{current_time}_", delete=False, suffix=".csv"
367394
)
368-
print("Results have been successfully uploaded to BigQuery.")
395+
benchmark_metrics.to_csv(temp_file.name, index=False)
396+
print(
397+
f"Benchmark result is saved to a temporary location: {temp_file.name}"
398+
)
399+
temp_file.close()
400+
# Output results to CSV with specified a custom location
401+
elif args.output_csv != "False":
402+
benchmark_metrics.to_csv(args.output_csv, index=False)
403+
print(f"Benchmark result is saved to: {args.output_csv}")
404+
405+
# Publish the benchmark metrics to BigQuery under the 'bigframes-metrics' project.
406+
# The 'BENCHMARK_AND_PUBLISH' environment variable should be set to 'true' only
407+
# in specific Kokoro sessions.
408+
if os.getenv("BENCHMARK_AND_PUBLISH", "false") == "true":
409+
publish_to_bigquery(benchmark_metrics, args.notebook)
410+
# If the 'GCLOUD_BENCH_PUBLISH_PROJECT' environment variable is set, publish the
411+
# benchmark metrics to a specified BigQuery table in the provided project. This is
412+
# intended for local testing where the default behavior is not to publish results.
413+
elif project := os.getenv("GCLOUD_BENCH_PUBLISH_PROJECT", ""):
414+
publish_to_bigquery(benchmark_metrics, args.notebook, project)
369415
elif args.notebook:
370416
run_notebook_benchmark(args.benchmark_path, args.region)
371417
else:
372-
run_benchmark_from_config(args.benchmark_path)
418+
run_benchmark_from_config(args.benchmark_path, args.iterations)
373419

374420

375421
if __name__ == "__main__":

tests/benchmark/tpch/config.jsonl

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
{"benchmark_suffix": "1g_ordered", "dataset_id": "tpch_0001g", "ordered": true}
2-
{"benchmark_suffix": "1g_unordered", "dataset_id": "tpch_0001g", "ordered": false}
3-
{"benchmark_suffix": "10g_ordered", "dataset_id": "tpch_0010g", "ordered": true}
4-
{"benchmark_suffix": "10g_unordered", "dataset_id": "tpch_0010g", "ordered": false}
5-
{"benchmark_suffix": "100g_ordered", "dataset_id": "tpch_0100g", "ordered": true}
6-
{"benchmark_suffix": "100g_unordered", "dataset_id": "tpch_0100g", "ordered": false}
7-
{"benchmark_suffix": "1t_ordered", "dataset_id": "tpch_0001t", "ordered": true}
8-
{"benchmark_suffix": "1t_unordered", "dataset_id": "tpch_0001t", "ordered": false}
1+
{"benchmark_suffix": "1g_ordered", "project_id": "bigframes-dev-perf", "dataset_id": "tpch_0001g", "ordered": true}
2+
{"benchmark_suffix": "1g_unordered", "project_id": "bigframes-dev-perf", "dataset_id": "tpch_0001g", "ordered": false}
3+
{"benchmark_suffix": "10g_ordered", "project_id": "bigframes-dev-perf", "dataset_id": "tpch_0010g", "ordered": true}
4+
{"benchmark_suffix": "10g_unordered", "project_id": "bigframes-dev-perf", "dataset_id": "tpch_0010g", "ordered": false}
5+
{"benchmark_suffix": "100g_ordered", "project_id": "bigframes-dev-perf", "dataset_id": "tpch_0100g", "ordered": true}
6+
{"benchmark_suffix": "100g_unordered", "project_id": "bigframes-dev-perf", "dataset_id": "tpch_0100g", "ordered": false}
7+
{"benchmark_suffix": "1t_ordered", "project_id": "bigframes-dev-perf", "dataset_id": "tpch_0001t", "ordered": true}
8+
{"benchmark_suffix": "1t_unordered", "project_id": "bigframes-dev-perf", "dataset_id": "tpch_0001t", "ordered": false}
9+
{"benchmark_suffix": "10t_ordered", "project_id": "bigframes-dev-perf", "dataset_id": "tpch_0010t", "ordered": true}
10+
{"benchmark_suffix": "10t_unordered", "project_id": "bigframes-dev-perf", "dataset_id": "tpch_0010t", "ordered": false}

tests/benchmark/tpch/q1.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
import bigframes_vendored.tpch.queries.q1 as vendored_tpch_q1
1818

1919
if __name__ == "__main__":
20-
dataset_id, session, suffix = utils.get_tpch_configuration()
20+
project_id, dataset_id, session, suffix = utils.get_tpch_configuration()
2121
current_path = pathlib.Path(__file__).absolute()
2222

2323
utils.get_execution_time(
24-
vendored_tpch_q1.q, current_path, suffix, dataset_id, session
24+
vendored_tpch_q1.q, current_path, suffix, project_id, dataset_id, session
2525
)

tests/benchmark/tpch/q10.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
import bigframes_vendored.tpch.queries.q10 as vendored_tpch_q10
1818

1919
if __name__ == "__main__":
20-
dataset_id, session, suffix = utils.get_tpch_configuration()
20+
project_id, dataset_id, session, suffix = utils.get_tpch_configuration()
2121
current_path = pathlib.Path(__file__).absolute()
2222

2323
utils.get_execution_time(
24-
vendored_tpch_q10.q, current_path, suffix, dataset_id, session
24+
vendored_tpch_q10.q, current_path, suffix, project_id, dataset_id, session
2525
)

tests/benchmark/tpch/q11.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
import bigframes_vendored.tpch.queries.q11 as vendored_tpch_q11
1818

1919
if __name__ == "__main__":
20-
dataset_id, session, suffix = utils.get_tpch_configuration()
20+
project_id, dataset_id, session, suffix = utils.get_tpch_configuration()
2121
current_path = pathlib.Path(__file__).absolute()
2222

2323
utils.get_execution_time(
24-
vendored_tpch_q11.q, current_path, suffix, dataset_id, session
24+
vendored_tpch_q11.q, current_path, suffix, project_id, dataset_id, session
2525
)

tests/benchmark/tpch/q12.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
import bigframes_vendored.tpch.queries.q12 as vendored_tpch_q12
1818

1919
if __name__ == "__main__":
20-
dataset_id, session, suffix = utils.get_tpch_configuration()
20+
project_id, dataset_id, session, suffix = utils.get_tpch_configuration()
2121
current_path = pathlib.Path(__file__).absolute()
2222

2323
utils.get_execution_time(
24-
vendored_tpch_q12.q, current_path, suffix, dataset_id, session
24+
vendored_tpch_q12.q, current_path, suffix, project_id, dataset_id, session
2525
)

0 commit comments

Comments
 (0)