This repository is currently being migrated. It's locked while the migration is in progress.

Repository files navigation

Build StatusCoverage StatusCode style: black

Apache Arrow Benchmarks

Language-independent Continuous Benchmarking (CB) for Apache Arrow

This package contains Python macro benchmarks for Apache Arrow, as well as external benchmark wrappers that execute and record the results for both the Arrow C++, Java, and JavaScript micro benchmarks (which are found in the arrow repository), and the Arrow R macro benchmarks (which are found in the arrowbench repository). These benchmarks use the Conbench legacy runner for benchmark execution, and the results are published to Arrow's public Conbench server.

On each commit to the main Arrow branch, the C++, Python, Java, JavaScript, and R benchmarks are run on a variety of physical benchmarking machines & EC2 instances of different sizes, and the results are published to Conbench. Additionally, benchmarks can also be run on an Arrow pull request by adding a GitHub comment with the text: @ursabot please benchmark. A baseline benchmarking run against the pull request's head with also be scheduled, and Conbench comparison links will be posted as a follow-up GitHub comment.

You can also filter the pull request benchmarks runs by filter name, language, or specific command. A GitHub comment with text @ursabot benchmark help will follow-up with a list of available ursabot benchmark commands.

@ursabot benchmark help
@ursabot please benchmark
@ursabot please benchmark lang=Python
@ursabot please benchmark lang=C++
@ursabot please benchmark lang=Java
@ursabot please benchmark lang=JavaScript
@ursabot please benchmark lang=R
@ursabot please benchmark name=file-write
@ursabot please benchmark name=file-write lang=Python
@ursabot please benchmark name=file-.*
@ursabot please benchmark command=cpp-micro --suite-filter=arrow-compute-vector-selection-benchmark --benchmark-filter=TakeStringRandomIndicesWithNulls/262144/2 --iterations=3

Benchmarks added to this repository and declared in benchmarks.json will automatically be picked up by by Arrow's Continuous Benchmarking pipeline. This file is regenerated each time the unit tests are run based on the various benchmark class attributes. See the BenchmarkList class for more information on how to override any of the benchmark defaults or to disable a particular benchmark.

Index

Contributing

Create workspace

$ cd
$ mkdir -p envs
$ mkdir -p workspace
$ mkdir -p data
$ export BENCHMARKS_DATA_DIR=$(pwd)/data
$ export ARROWBENCH_DATA_DIR=$(pwd)/data

Create virualenv

$ cd ~/envs
$ python3 -m venv qa
$ source qa/bin/activate

Clone repos

(qa) $ cd ~/workspace/
(qa) $ git clone https://github.com/voltrondata-labs/benchmarks.git
(qa) $ git clone https://github.com/apache/arrow.git
(qa) $ export ARROW_SRC=$(pwd)/arrow

Install voltrondata-labs/benchmarks

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pip install -e '.[dev]'

Install arrowbench (to run R benchmarks)

$ R
> install.packages('remotes')
> remotes::install_github("voltrondata-labs/arrowbench")

Install archery (to run C++ & Java micro benchmarks)

(qa) $ cd ~/workspace/
(qa) $ pip install -e arrow/dev/archery

Conbench credentials default to this following (edit .conbench to configure)

(This is only needed if you plan on publishing benchmark results to a Conbench server.)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cat .conbench
url: http://localhost:5000
email: conbench@example.com
password: conbench

Run tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv benchmarks/tests/

Format code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ git status
modified: foo.py
(qa) $ black foo.py
reformatted foo.py
(qa) $ git add foo.py

Sort imports (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ isort .
Fixing foo.py
(qa) $ git add foo.py

Lint code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ flake8
./foo/bar/__init__.py:1:1: F401 'FooBar' imported but unused

Generate coverage report

(qa) $ cd ~/workspace/benchmarks/
(qa) $ coverage run --source benchmarks -m pytest benchmarks/tests/
(qa) $ coverage report -m

Running benchmarks

Run benchmarks as tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv --capture=no benchmarks/tests/test_file_benchmark.py
test_file_benchmark.py::test_read[parquet, uncompressed, table] PASSED
test_file_benchmark.py::test_read[parquet, uncompressed, dataframe] PASSED
test_file_benchmark.py::test_read[parquet, snappy, table] PASSED
test_file_benchmark.py::test_read[parquet, snappy, dataframe] PASSED
...

Run benchmarks from command line

Conbench can be run from either of the following directories.

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cd ~/workspace/benchmarks/benchmarks/

Use the conbench --help command to see the available benchmarks.

(qa) $ conbench --help
Usage: conbench [OPTIONS] COMMAND [ARGS]...
Conbench: Language-independent Continuous Benchmarking (CB) Framework
Options:
--help Show this message and exit.
Commands:
cpp-micro Run the Arrow C++ micro benchmarks.
csv-read Run csv-read benchmark.
dataframe-to-table Run dataframe-to-table benchmark.
dataset-filter Run dataset-filter benchmark.
dataset-read Run dataset-read benchmark(s).
dataset-select Run dataset-select benchmark.
dataset-selectivity Run dataset-selectivity benchmark(s).
example-R-only Run example-R-only benchmark.
example-R-only-exception Run example-R-only-exception benchmark.
example-R-only-no-result Run example-R-only-no-result benchmark.
example-cases Run example-cases benchmark(s).
example-cases-exception Run example-cases-exception benchmark(s).
example-external Run example-external benchmark.
example-simple Run example-simple benchmark.
example-simple-exception Run example-simple-exception benchmark.
file-read Run file-read benchmark(s).
file-write Run file-write benchmark(s).
java-micro Run the Arrow Java micro benchmarks.
js-micro Run the Arrow JavaScript micro benchmarks.
list List of benchmarks (for orchestration).
partitioned-dataset-filter Run partitioned-dataset-filter benchmark(s).
wide-dataframe Run wide-dataframe benchmark(s).

Help is also available for individual benchmark commands.

(qa) $ conbench file-write --help
Usage: conbench file-write [OPTIONS] SOURCE
Run file-write benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--file-type=parquet --compression=uncompressed --input-type=table
--file-type=parquet --compression=uncompressed --input-type=dataframe
--file-type=parquet --compression=snappy --input-type=table
--file-type=parquet --compression=snappy --input-type=dataframe
--file-type=feather --compression=uncompressed --input-type=table
--file-type=feather --compression=uncompressed --input-type=dataframe
--file-type=feather --compression=lz4 --input-type=table
--file-type=feather --compression=lz4 --input-type=dataframe
To run all combinations:
$ conbench file-write --all=true
Options:
--file-type [feather|parquet]
--compression [lz4|snappy|uncompressed]
--input-type [dataframe|table]
--all BOOLEAN [default: false]
--language [Python|R]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

Example benchmark execution.

(qa) $ conbench file-read nyctaxi_sample --file-type=feather --compression=lz4 --output-type=dataframe --iterations=10 --gc-disable=false
Benchmark result:
{
"batch_id": "3d97e0185ef44d0d9d095f4b9fdd3fd2",
"run_id": "54c00bfd6b6147739bbf1224cfdf9b1d",
"timestamp": "2021-11-11T00:32:15.061174+00:00"
"context": {
"arrow_compiler_flags": " -Qunused-arguments -fcolor-diagnostics -O3 -DNDEBUG",
"benchmark_language": "Python"
},
"github": {
"commit": "4591d76fce2846a29dac33bf01e9ba0337b118e9",
"repository": "https://github.com/apache/arrow"
},
"info": {
"arrow_compiler_id": "AppleClang",
"arrow_compiler_version": "12.0.0.12000032",
"arrow_version": "5.0.0",
"benchmark_language_version": "Python 3.9.7"
},
"machine_info": {
"architecture_name": "arm64",
"cpu_core_count": "8",
"cpu_frequency_max_hz": "0",
"cpu_l1d_cache_bytes": "65536",
"cpu_l1i_cache_bytes": "131072",
"cpu_l2_cache_bytes": "4194304",
"cpu_l3_cache_bytes": "0",
"cpu_model_name": "Apple M1",
"cpu_thread_count": "8",
"gpu_count": "0",
"gpu_product_names": [],
"kernel_name": "20.6.0",
"memory_bytes": "17179869184",
"name": "diana",
"os_name": "macOS",
"os_version": "11.5.2"
},
"stats": {
"data": [
"0.004986",
"0.001076",
"0.001132",
"0.001086",
"0.001221",
"0.001143",
"0.001074",
"0.001057",
"0.000990",
"0.001032"
],
"iqr": "0.000079",
"iterations": 10,
"max": "0.004986",
"mean": "0.001480",
"median": "0.001081",
"min": "0.000990",
"q1": "0.001061",
"q3": "0.001140",
"stdev": "0.001234",
"time_unit": "s",
"times": [],
"unit": "s"
},
"tags": {
"compression": "lz4",
"cpu_count": null,
"dataset": "nyctaxi_sample",
"file_type": "feather",
"name": "file-read",
"output_type": "dataframe"
}
}

Authoring benchmarks

There are three main types of benchmarks: "simple benchmarks" that time the execution of a unit of work, "external benchmarks" that just record benchmark results that were obtained from some other benchmarking tool, and "case benchmarks" which benchmark a unit of work under different scenarios.

Included in this repository are contrived, minimal examples of these different kinds of benchmarks to be used as templates for benchmark authoring. These example benchmarks and their tests can be found here:

Example simple benchmarks

A "simple benchmark" runs and records the execution time of a unit of work.

Implementation details: Note that this benchmark extends benchmarks._benchmark.Benchmark, implements the minimum required run() method, and registers itself with the @conbenchlegacy.runner.register_benchmark decorator.

@conbenchlegacy.runner.register_benchmarkclassSimpleBenchmark(_benchmark.Benchmark):
"""Example benchmark without cases."""name="example-simple"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
f=self._get_benchmark_function()
yieldself.benchmark(f, tags, kwargs)
def_get_benchmark_function(self):
returnlambda: 1+1
(qa) $ conbench example-simple --help
Usage: conbench example-simple [OPTIONS]
Run example-simple benchmark.
Options:
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More simple benchmark examples that have minimal scaffolding:

Example external benchmarks

An "external benchmark" records results that were obtained from some other benchmarking tool (like executing the Arrow C++ micro benchmarks from command line, parsing the resulting JSON, and recording those results).

Implementation details: Note that the following benchmark sets external = True, and calls record() rather than benchmark() as the example above does.

@conbenchlegacy.runner.register_benchmarkclassExternalBenchmark(_benchmark.Benchmark):
"""Example benchmark that just records external results."""external=Truename="example-external"defrun(self, **kwargs):
# external results from somewhere# (an API call, command line execution, etc)result= {
"data": [100, 200, 300],
"unit": "i/s",
"times": [0.100, 0.200, 0.300],
"time_unit": "s",
}
tags=self.get_tags(kwargs)
info, context= {}, {"benchmark_language": "C++"}
yieldself.record(
result,
tags,
info,
context,
options=kwargs,
output=result["data"],
)
(qa) $ conbench example-external --help
Usage: conbench example-external [OPTIONS]
Run example-external benchmark.
Options:
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

And here's another external benchmark, one that runs an external R benchmark.

Implementation details: Note that the following benchmark extends BenchmarkR, sets both external and r_only to True, defines r_name, implements _get_r_command(), and calls r_benchmark() rather than benchmark() or record().

@conbenchlegacy.runner.register_benchmarkclassWithoutPythonBenchmark(_benchmark.BenchmarkR):
"""Example R benchmark that doesn't have a Python equivalent."""external, r_only=True, Truename, r_name="example-R-only", "placebo"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
command=self._get_r_command(kwargs)
yieldself.r_benchmark(command, tags, kwargs)
def_get_r_command(self, options):
return (
f"library(arrowbench); "f"run_one(arrowbench:::{self.r_name}, "f"cpu_count={self.r_cpu_count(options)})"
)
(qa) $ conbench example-R-only --help
Usage: conbench example-R-only [OPTIONS]
Run example-R-only benchmark.
Options:
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More external benchmark examples that record C++, Java, and R benchmark results:

Example case benchmarks

A "case benchmark" is a either a "simple benchmark" or an "external benchmark" executed under various predefined scenarios (cases).

Implementation details: Note that the following benchmark declares the valid combinations in valid_cases, which reads like a CSV (the first row contains the cases names).

@conbenchlegacy.runner.register_benchmarkclassCasesBenchmark(_benchmark.Benchmark):
"""Example benchmark with cases."""name="example-cases"valid_cases= (
("rows", "columns"),
("10", "10"),
("2", "10"),
("10", "2"),
)
defrun(self, case=None, **kwargs):
tags=self.get_tags(kwargs)
forcaseinself.get_cases(case, kwargs):
rows, columns=casef=self._get_benchmark_function(rows, columns)
yieldself.benchmark(f, tags, kwargs, case)
def_get_benchmark_function(self, rows, columns):
returnlambda: int(rows) * [int(columns) * [0]]
(qa) $ conbench example-cases --help
Usage: conbench example-cases [OPTIONS]
Run example-cases benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--rows=10 --columns=10
--rows=2 --columns=10
--rows=10 --columns=2
To run all combinations:
$ conbench example-cases --all=true
Options:
--rows [10|2]
--columns [10|2]
--all BOOLEAN [default: false]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More case benchmark examples:

About

Language-independent Continuous Benchmarking (CB) for Apache Arrow

Resources

Stars

10 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
This repository is currently being migrated. It's locked while the migration is in progress.

Repository files navigation

Build StatusCoverage StatusCode style: black

Apache Arrow Benchmarks

Language-independent Continuous Benchmarking (CB) for Apache Arrow

This package contains Python macro benchmarks for Apache Arrow, as well as external benchmark wrappers that execute and record the results for both the Arrow C++, Java, and JavaScript micro benchmarks (which are found in the arrow repository), and the Arrow R macro benchmarks (which are found in the arrowbench repository). These benchmarks use the Conbench legacy runner for benchmark execution, and the results are published to Arrow's public Conbench server.

On each commit to the main Arrow branch, the C++, Python, Java, JavaScript, and R benchmarks are run on a variety of physical benchmarking machines & EC2 instances of different sizes, and the results are published to Conbench. Additionally, benchmarks can also be run on an Arrow pull request by adding a GitHub comment with the text: @ursabot please benchmark. A baseline benchmarking run against the pull request's head with also be scheduled, and Conbench comparison links will be posted as a follow-up GitHub comment.

You can also filter the pull request benchmarks runs by filter name, language, or specific command. A GitHub comment with text @ursabot benchmark help will follow-up with a list of available ursabot benchmark commands.

@ursabot benchmark help
@ursabot please benchmark
@ursabot please benchmark lang=Python
@ursabot please benchmark lang=C++
@ursabot please benchmark lang=Java
@ursabot please benchmark lang=JavaScript
@ursabot please benchmark lang=R
@ursabot please benchmark name=file-write
@ursabot please benchmark name=file-write lang=Python
@ursabot please benchmark name=file-.*
@ursabot please benchmark command=cpp-micro --suite-filter=arrow-compute-vector-selection-benchmark --benchmark-filter=TakeStringRandomIndicesWithNulls/262144/2 --iterations=3

Benchmarks added to this repository and declared in benchmarks.json will automatically be picked up by by Arrow's Continuous Benchmarking pipeline. This file is regenerated each time the unit tests are run based on the various benchmark class attributes. See the BenchmarkList class for more information on how to override any of the benchmark defaults or to disable a particular benchmark.

Index

Contributing

Create workspace

$ cd
$ mkdir -p envs
$ mkdir -p workspace
$ mkdir -p data
$ export BENCHMARKS_DATA_DIR=$(pwd)/data
$ export ARROWBENCH_DATA_DIR=$(pwd)/data

Create virualenv

$ cd ~/envs
$ python3 -m venv qa
$ source qa/bin/activate

Clone repos

(qa) $ cd ~/workspace/
(qa) $ git clone https://github.com/voltrondata-labs/benchmarks.git
(qa) $ git clone https://github.com/apache/arrow.git
(qa) $ export ARROW_SRC=$(pwd)/arrow

Install voltrondata-labs/benchmarks

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pip install -e '.[dev]'

Install arrowbench (to run R benchmarks)

$ R
> install.packages('remotes')
> remotes::install_github("voltrondata-labs/arrowbench")

Install archery (to run C++ & Java micro benchmarks)

(qa) $ cd ~/workspace/
(qa) $ pip install -e arrow/dev/archery

Conbench credentials default to this following (edit .conbench to configure)

(This is only needed if you plan on publishing benchmark results to a Conbench server.)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cat .conbench
url: http://localhost:5000
email: conbench@example.com
password: conbench

Run tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv benchmarks/tests/

Format code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ git status
modified: foo.py
(qa) $ black foo.py
reformatted foo.py
(qa) $ git add foo.py

Sort imports (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ isort .
Fixing foo.py
(qa) $ git add foo.py

Lint code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ flake8
./foo/bar/__init__.py:1:1: F401 'FooBar' imported but unused

Generate coverage report

(qa) $ cd ~/workspace/benchmarks/
(qa) $ coverage run --source benchmarks -m pytest benchmarks/tests/
(qa) $ coverage report -m

Running benchmarks

Run benchmarks as tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv --capture=no benchmarks/tests/test_file_benchmark.py
test_file_benchmark.py::test_read[parquet, uncompressed, table] PASSED
test_file_benchmark.py::test_read[parquet, uncompressed, dataframe] PASSED
test_file_benchmark.py::test_read[parquet, snappy, table] PASSED
test_file_benchmark.py::test_read[parquet, snappy, dataframe] PASSED
...

Run benchmarks from command line

Conbench can be run from either of the following directories.

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cd ~/workspace/benchmarks/benchmarks/

Use the conbench --help command to see the available benchmarks.

(qa) $ conbench --help
Usage: conbench [OPTIONS] COMMAND [ARGS]...
Conbench: Language-independent Continuous Benchmarking (CB) Framework
Options:
--help Show this message and exit.
Commands:
cpp-micro Run the Arrow C++ micro benchmarks.
csv-read Run csv-read benchmark.
dataframe-to-table Run dataframe-to-table benchmark.
dataset-filter Run dataset-filter benchmark.
dataset-read Run dataset-read benchmark(s).
dataset-select Run dataset-select benchmark.
dataset-selectivity Run dataset-selectivity benchmark(s).
example-R-only Run example-R-only benchmark.
example-R-only-exception Run example-R-only-exception benchmark.
example-R-only-no-result Run example-R-only-no-result benchmark.
example-cases Run example-cases benchmark(s).
example-cases-exception Run example-cases-exception benchmark(s).
example-external Run example-external benchmark.
example-simple Run example-simple benchmark.
example-simple-exception Run example-simple-exception benchmark.
file-read Run file-read benchmark(s).
file-write Run file-write benchmark(s).
java-micro Run the Arrow Java micro benchmarks.
js-micro Run the Arrow JavaScript micro benchmarks.
list List of benchmarks (for orchestration).
partitioned-dataset-filter Run partitioned-dataset-filter benchmark(s).
wide-dataframe Run wide-dataframe benchmark(s).

Help is also available for individual benchmark commands.

(qa) $ conbench file-write --help
Usage: conbench file-write [OPTIONS] SOURCE
Run file-write benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--file-type=parquet --compression=uncompressed --input-type=table
--file-type=parquet --compression=uncompressed --input-type=dataframe
--file-type=parquet --compression=snappy --input-type=table
--file-type=parquet --compression=snappy --input-type=dataframe
--file-type=feather --compression=uncompressed --input-type=table
--file-type=feather --compression=uncompressed --input-type=dataframe
--file-type=feather --compression=lz4 --input-type=table
--file-type=feather --compression=lz4 --input-type=dataframe
To run all combinations:
$ conbench file-write --all=true
Options:
--file-type [feather|parquet]
--compression [lz4|snappy|uncompressed]
--input-type [dataframe|table]
--all BOOLEAN [default: false]
--language [Python|R]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

Example benchmark execution.

(qa) $ conbench file-read nyctaxi_sample --file-type=feather --compression=lz4 --output-type=dataframe --iterations=10 --gc-disable=false
Benchmark result:
{
"batch_id": "3d97e0185ef44d0d9d095f4b9fdd3fd2",
"run_id": "54c00bfd6b6147739bbf1224cfdf9b1d",
"timestamp": "2021-11-11T00:32:15.061174+00:00"
"context": {
"arrow_compiler_flags": " -Qunused-arguments -fcolor-diagnostics -O3 -DNDEBUG",
"benchmark_language": "Python"
},
"github": {
"commit": "4591d76fce2846a29dac33bf01e9ba0337b118e9",
"repository": "https://github.com/apache/arrow"
},
"info": {
"arrow_compiler_id": "AppleClang",
"arrow_compiler_version": "12.0.0.12000032",
"arrow_version": "5.0.0",
"benchmark_language_version": "Python 3.9.7"
},
"machine_info": {
"architecture_name": "arm64",
"cpu_core_count": "8",
"cpu_frequency_max_hz": "0",
"cpu_l1d_cache_bytes": "65536",
"cpu_l1i_cache_bytes": "131072",
"cpu_l2_cache_bytes": "4194304",
"cpu_l3_cache_bytes": "0",
"cpu_model_name": "Apple M1",
"cpu_thread_count": "8",
"gpu_count": "0",
"gpu_product_names": [],
"kernel_name": "20.6.0",
"memory_bytes": "17179869184",
"name": "diana",
"os_name": "macOS",
"os_version": "11.5.2"
},
"stats": {
"data": [
"0.004986",
"0.001076",
"0.001132",
"0.001086",
"0.001221",
"0.001143",
"0.001074",
"0.001057",
"0.000990",
"0.001032"
],
"iqr": "0.000079",
"iterations": 10,
"max": "0.004986",
"mean": "0.001480",
"median": "0.001081",
"min": "0.000990",
"q1": "0.001061",
"q3": "0.001140",
"stdev": "0.001234",
"time_unit": "s",
"times": [],
"unit": "s"
},
"tags": {
"compression": "lz4",
"cpu_count": null,
"dataset": "nyctaxi_sample",
"file_type": "feather",
"name": "file-read",
"output_type": "dataframe"
}
}

Authoring benchmarks

There are three main types of benchmarks: "simple benchmarks" that time the execution of a unit of work, "external benchmarks" that just record benchmark results that were obtained from some other benchmarking tool, and "case benchmarks" which benchmark a unit of work under different scenarios.

Included in this repository are contrived, minimal examples of these different kinds of benchmarks to be used as templates for benchmark authoring. These example benchmarks and their tests can be found here:

Example simple benchmarks

A "simple benchmark" runs and records the execution time of a unit of work.

Implementation details: Note that this benchmark extends benchmarks._benchmark.Benchmark, implements the minimum required run() method, and registers itself with the @conbenchlegacy.runner.register_benchmark decorator.

@conbenchlegacy.runner.register_benchmarkclassSimpleBenchmark(_benchmark.Benchmark):
"""Example benchmark without cases."""name="example-simple"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
f=self._get_benchmark_function()
yieldself.benchmark(f, tags, kwargs)
def_get_benchmark_function(self):
returnlambda: 1+1
(qa) $ conbench example-simple --help
Usage: conbench example-simple [OPTIONS]
Run example-simple benchmark.
Options:
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More simple benchmark examples that have minimal scaffolding:

Example external benchmarks

An "external benchmark" records results that were obtained from some other benchmarking tool (like executing the Arrow C++ micro benchmarks from command line, parsing the resulting JSON, and recording those results).

Implementation details: Note that the following benchmark sets external = True, and calls record() rather than benchmark() as the example above does.

@conbenchlegacy.runner.register_benchmarkclassExternalBenchmark(_benchmark.Benchmark):
"""Example benchmark that just records external results."""external=Truename="example-external"defrun(self, **kwargs):
# external results from somewhere# (an API call, command line execution, etc)result= {
"data": [100, 200, 300],
"unit": "i/s",
"times": [0.100, 0.200, 0.300],
"time_unit": "s",
}
tags=self.get_tags(kwargs)
info, context= {}, {"benchmark_language": "C++"}
yieldself.record(
result,
tags,
info,
context,
options=kwargs,
output=result["data"],
)
(qa) $ conbench example-external --help
Usage: conbench example-external [OPTIONS]
Run example-external benchmark.
Options:
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

And here's another external benchmark, one that runs an external R benchmark.

Implementation details: Note that the following benchmark extends BenchmarkR, sets both external and r_only to True, defines r_name, implements _get_r_command(), and calls r_benchmark() rather than benchmark() or record().

@conbenchlegacy.runner.register_benchmarkclassWithoutPythonBenchmark(_benchmark.BenchmarkR):
"""Example R benchmark that doesn't have a Python equivalent."""external, r_only=True, Truename, r_name="example-R-only", "placebo"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
command=self._get_r_command(kwargs)
yieldself.r_benchmark(command, tags, kwargs)
def_get_r_command(self, options):
return (
f"library(arrowbench); "f"run_one(arrowbench:::{self.r_name}, "f"cpu_count={self.r_cpu_count(options)})"
)
(qa) $ conbench example-R-only --help
Usage: conbench example-R-only [OPTIONS]
Run example-R-only benchmark.
Options:
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More external benchmark examples that record C++, Java, and R benchmark results:

Example case benchmarks

A "case benchmark" is a either a "simple benchmark" or an "external benchmark" executed under various predefined scenarios (cases).

Implementation details: Note that the following benchmark declares the valid combinations in valid_cases, which reads like a CSV (the first row contains the cases names).

@conbenchlegacy.runner.register_benchmarkclassCasesBenchmark(_benchmark.Benchmark):
"""Example benchmark with cases."""name="example-cases"valid_cases= (
("rows", "columns"),
("10", "10"),
("2", "10"),
("10", "2"),
)
defrun(self, case=None, **kwargs):
tags=self.get_tags(kwargs)
forcaseinself.get_cases(case, kwargs):
rows, columns=casef=self._get_benchmark_function(rows, columns)
yieldself.benchmark(f, tags, kwargs, case)
def_get_benchmark_function(self, rows, columns):
returnlambda: int(rows) * [int(columns) * [0]]
(qa) $ conbench example-cases --help
Usage: conbench example-cases [OPTIONS]
Run example-cases benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--rows=10 --columns=10
--rows=2 --columns=10
--rows=10 --columns=2
To run all combinations:
$ conbench example-cases --all=true
Options:
--rows [10|2]
--columns [10|2]
--all BOOLEAN [default: false]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More case benchmark examples:

About

Language-independent Continuous Benchmarking (CB) for Apache Arrow

Resources

Stars

10 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository is currently being migrated. It's locked while the migration is in progress.

Repository files navigation

Build StatusCoverage StatusCode style: black

Apache Arrow Benchmarks

Language-independent Continuous Benchmarking (CB) for Apache Arrow

This package contains Python macro benchmarks for Apache Arrow, as well as external benchmark wrappers that execute and record the results for both the Arrow C++, Java, and JavaScript micro benchmarks (which are found in the arrow repository), and the Arrow R macro benchmarks (which are found in the arrowbench repository). These benchmarks use the Conbench legacy runner for benchmark execution, and the results are published to Arrow's public Conbench server.

On each commit to the main Arrow branch, the C++, Python, Java, JavaScript, and R benchmarks are run on a variety of physical benchmarking machines & EC2 instances of different sizes, and the results are published to Conbench. Additionally, benchmarks can also be run on an Arrow pull request by adding a GitHub comment with the text: @ursabot please benchmark. A baseline benchmarking run against the pull request's head with also be scheduled, and Conbench comparison links will be posted as a follow-up GitHub comment.

You can also filter the pull request benchmarks runs by filter name, language, or specific command. A GitHub comment with text @ursabot benchmark help will follow-up with a list of available ursabot benchmark commands.

@ursabot benchmark help
@ursabot please benchmark
@ursabot please benchmark lang=Python
@ursabot please benchmark lang=C++
@ursabot please benchmark lang=Java
@ursabot please benchmark lang=JavaScript
@ursabot please benchmark lang=R
@ursabot please benchmark name=file-write
@ursabot please benchmark name=file-write lang=Python
@ursabot please benchmark name=file-.*
@ursabot please benchmark command=cpp-micro --suite-filter=arrow-compute-vector-selection-benchmark --benchmark-filter=TakeStringRandomIndicesWithNulls/262144/2 --iterations=3

Benchmarks added to this repository and declared in benchmarks.json will automatically be picked up by by Arrow's Continuous Benchmarking pipeline. This file is regenerated each time the unit tests are run based on the various benchmark class attributes. See the BenchmarkList class for more information on how to override any of the benchmark defaults or to disable a particular benchmark.

Index

Contributing

Create workspace

$ cd
$ mkdir -p envs
$ mkdir -p workspace
$ mkdir -p data
$ export BENCHMARKS_DATA_DIR=$(pwd)/data
$ export ARROWBENCH_DATA_DIR=$(pwd)/data

Create virualenv

$ cd ~/envs
$ python3 -m venv qa
$ source qa/bin/activate

Clone repos

(qa) $ cd ~/workspace/
(qa) $ git clone https://github.com/voltrondata-labs/benchmarks.git
(qa) $ git clone https://github.com/apache/arrow.git
(qa) $ export ARROW_SRC=$(pwd)/arrow

Install voltrondata-labs/benchmarks

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pip install -e '.[dev]'

Install arrowbench (to run R benchmarks)

$ R
> install.packages('remotes')
> remotes::install_github("voltrondata-labs/arrowbench")

Install archery (to run C++ & Java micro benchmarks)

(qa) $ cd ~/workspace/
(qa) $ pip install -e arrow/dev/archery

Conbench credentials default to this following (edit .conbench to configure)

(This is only needed if you plan on publishing benchmark results to a Conbench server.)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cat .conbench
url: http://localhost:5000
email: conbench@example.com
password: conbench

Run tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv benchmarks/tests/

Format code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ git status
modified: foo.py
(qa) $ black foo.py
reformatted foo.py
(qa) $ git add foo.py

Sort imports (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ isort .
Fixing foo.py
(qa) $ git add foo.py

Lint code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ flake8
./foo/bar/__init__.py:1:1: F401 'FooBar' imported but unused

Generate coverage report

(qa) $ cd ~/workspace/benchmarks/
(qa) $ coverage run --source benchmarks -m pytest benchmarks/tests/
(qa) $ coverage report -m

Running benchmarks

Run benchmarks as tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv --capture=no benchmarks/tests/test_file_benchmark.py
test_file_benchmark.py::test_read[parquet, uncompressed, table] PASSED
test_file_benchmark.py::test_read[parquet, uncompressed, dataframe] PASSED
test_file_benchmark.py::test_read[parquet, snappy, table] PASSED
test_file_benchmark.py::test_read[parquet, snappy, dataframe] PASSED
...

Run benchmarks from command line

Conbench can be run from either of the following directories.

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cd ~/workspace/benchmarks/benchmarks/

Use the conbench --help command to see the available benchmarks.

(qa) $ conbench --help
Usage: conbench [OPTIONS] COMMAND [ARGS]...
Conbench: Language-independent Continuous Benchmarking (CB) Framework
Options:
--help Show this message and exit.
Commands:
cpp-micro Run the Arrow C++ micro benchmarks.
csv-read Run csv-read benchmark.
dataframe-to-table Run dataframe-to-table benchmark.
dataset-filter Run dataset-filter benchmark.
dataset-read Run dataset-read benchmark(s).
dataset-select Run dataset-select benchmark.
dataset-selectivity Run dataset-selectivity benchmark(s).
example-R-only Run example-R-only benchmark.
example-R-only-exception Run example-R-only-exception benchmark.
example-R-only-no-result Run example-R-only-no-result benchmark.
example-cases Run example-cases benchmark(s).
example-cases-exception Run example-cases-exception benchmark(s).
example-external Run example-external benchmark.
example-simple Run example-simple benchmark.
example-simple-exception Run example-simple-exception benchmark.
file-read Run file-read benchmark(s).
file-write Run file-write benchmark(s).
java-micro Run the Arrow Java micro benchmarks.
js-micro Run the Arrow JavaScript micro benchmarks.
list List of benchmarks (for orchestration).
partitioned-dataset-filter Run partitioned-dataset-filter benchmark(s).
wide-dataframe Run wide-dataframe benchmark(s).

Help is also available for individual benchmark commands.

(qa) $ conbench file-write --help
Usage: conbench file-write [OPTIONS] SOURCE
Run file-write benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--file-type=parquet --compression=uncompressed --input-type=table
--file-type=parquet --compression=uncompressed --input-type=dataframe
--file-type=parquet --compression=snappy --input-type=table
--file-type=parquet --compression=snappy --input-type=dataframe
--file-type=feather --compression=uncompressed --input-type=table
--file-type=feather --compression=uncompressed --input-type=dataframe
--file-type=feather --compression=lz4 --input-type=table
--file-type=feather --compression=lz4 --input-type=dataframe
To run all combinations:
$ conbench file-write --all=true
Options:
--file-type [feather|parquet]
--compression [lz4|snappy|uncompressed]
--input-type [dataframe|table]
--all BOOLEAN [default: false]
--language [Python|R]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

Example benchmark execution.

(qa) $ conbench file-read nyctaxi_sample --file-type=feather --compression=lz4 --output-type=dataframe --iterations=10 --gc-disable=false
Benchmark result:
{
"batch_id": "3d97e0185ef44d0d9d095f4b9fdd3fd2",
"run_id": "54c00bfd6b6147739bbf1224cfdf9b1d",
"timestamp": "2021-11-11T00:32:15.061174+00:00"
"context": {
"arrow_compiler_flags": " -Qunused-arguments -fcolor-diagnostics -O3 -DNDEBUG",
"benchmark_language": "Python"
},
"github": {
"commit": "4591d76fce2846a29dac33bf01e9ba0337b118e9",
"repository": "https://github.com/apache/arrow"
},
"info": {
"arrow_compiler_id": "AppleClang",
"arrow_compiler_version": "12.0.0.12000032",
"arrow_version": "5.0.0",
"benchmark_language_version": "Python 3.9.7"
},
"machine_info": {
"architecture_name": "arm64",
"cpu_core_count": "8",
"cpu_frequency_max_hz": "0",
"cpu_l1d_cache_bytes": "65536",
"cpu_l1i_cache_bytes": "131072",
"cpu_l2_cache_bytes": "4194304",
"cpu_l3_cache_bytes": "0",
"cpu_model_name": "Apple M1",
"cpu_thread_count": "8",
"gpu_count": "0",
"gpu_product_names": [],
"kernel_name": "20.6.0",
"memory_bytes": "17179869184",
"name": "diana",
"os_name": "macOS",
"os_version": "11.5.2"
},
"stats": {
"data": [
"0.004986",
"0.001076",
"0.001132",
"0.001086",
"0.001221",
"0.001143",
"0.001074",
"0.001057",
"0.000990",
"0.001032"
],
"iqr": "0.000079",
"iterations": 10,
"max": "0.004986",
"mean": "0.001480",
"median": "0.001081",
"min": "0.000990",
"q1": "0.001061",
"q3": "0.001140",
"stdev": "0.001234",
"time_unit": "s",
"times": [],
"unit": "s"
},
"tags": {
"compression": "lz4",
"cpu_count": null,
"dataset": "nyctaxi_sample",
"file_type": "feather",
"name": "file-read",
"output_type": "dataframe"
}
}

Authoring benchmarks

There are three main types of benchmarks: "simple benchmarks" that time the execution of a unit of work, "external benchmarks" that just record benchmark results that were obtained from some other benchmarking tool, and "case benchmarks" which benchmark a unit of work under different scenarios.

Included in this repository are contrived, minimal examples of these different kinds of benchmarks to be used as templates for benchmark authoring. These example benchmarks and their tests can be found here:

Example simple benchmarks

A "simple benchmark" runs and records the execution time of a unit of work.

Implementation details: Note that this benchmark extends benchmarks._benchmark.Benchmark, implements the minimum required run() method, and registers itself with the @conbenchlegacy.runner.register_benchmark decorator.

@conbenchlegacy.runner.register_benchmarkclassSimpleBenchmark(_benchmark.Benchmark):
"""Example benchmark without cases."""name="example-simple"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
f=self._get_benchmark_function()
yieldself.benchmark(f, tags, kwargs)
def_get_benchmark_function(self):
returnlambda: 1+1
(qa) $ conbench example-simple --help
Usage: conbench example-simple [OPTIONS]
Run example-simple benchmark.
Options:
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More simple benchmark examples that have minimal scaffolding:

Example external benchmarks

An "external benchmark" records results that were obtained from some other benchmarking tool (like executing the Arrow C++ micro benchmarks from command line, parsing the resulting JSON, and recording those results).

Implementation details: Note that the following benchmark sets external = True, and calls record() rather than benchmark() as the example above does.

@conbenchlegacy.runner.register_benchmarkclassExternalBenchmark(_benchmark.Benchmark):
"""Example benchmark that just records external results."""external=Truename="example-external"defrun(self, **kwargs):
# external results from somewhere# (an API call, command line execution, etc)result= {
"data": [100, 200, 300],
"unit": "i/s",
"times": [0.100, 0.200, 0.300],
"time_unit": "s",
}
tags=self.get_tags(kwargs)
info, context= {}, {"benchmark_language": "C++"}
yieldself.record(
result,
tags,
info,
context,
options=kwargs,
output=result["data"],
)
(qa) $ conbench example-external --help
Usage: conbench example-external [OPTIONS]
Run example-external benchmark.
Options:
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

And here's another external benchmark, one that runs an external R benchmark.

Implementation details: Note that the following benchmark extends BenchmarkR, sets both external and r_only to True, defines r_name, implements _get_r_command(), and calls r_benchmark() rather than benchmark() or record().

@conbenchlegacy.runner.register_benchmarkclassWithoutPythonBenchmark(_benchmark.BenchmarkR):
"""Example R benchmark that doesn't have a Python equivalent."""external, r_only=True, Truename, r_name="example-R-only", "placebo"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
command=self._get_r_command(kwargs)
yieldself.r_benchmark(command, tags, kwargs)
def_get_r_command(self, options):
return (
f"library(arrowbench); "f"run_one(arrowbench:::{self.r_name}, "f"cpu_count={self.r_cpu_count(options)})"
)
(qa) $ conbench example-R-only --help
Usage: conbench example-R-only [OPTIONS]
Run example-R-only benchmark.
Options:
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More external benchmark examples that record C++, Java, and R benchmark results:

Example case benchmarks

A "case benchmark" is a either a "simple benchmark" or an "external benchmark" executed under various predefined scenarios (cases).

Implementation details: Note that the following benchmark declares the valid combinations in valid_cases, which reads like a CSV (the first row contains the cases names).

@conbenchlegacy.runner.register_benchmarkclassCasesBenchmark(_benchmark.Benchmark):
"""Example benchmark with cases."""name="example-cases"valid_cases= (
("rows", "columns"),
("10", "10"),
("2", "10"),
("10", "2"),
)
defrun(self, case=None, **kwargs):
tags=self.get_tags(kwargs)
forcaseinself.get_cases(case, kwargs):
rows, columns=casef=self._get_benchmark_function(rows, columns)
yieldself.benchmark(f, tags, kwargs, case)
def_get_benchmark_function(self, rows, columns):
returnlambda: int(rows) * [int(columns) * [0]]
(qa) $ conbench example-cases --help
Usage: conbench example-cases [OPTIONS]
Run example-cases benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--rows=10 --columns=10
--rows=2 --columns=10
--rows=10 --columns=2
To run all combinations:
$ conbench example-cases --all=true
Options:
--rows [10|2]
--columns [10|2]
--all BOOLEAN [default: false]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More case benchmark examples:

About

Language-independent Continuous Benchmarking (CB) for Apache Arrow

Resources

Stars

10 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository is currently being migrated. It's locked while the migration is in progress.

Repository files navigation

Build StatusCoverage StatusCode style: black

Apache Arrow Benchmarks

Language-independent Continuous Benchmarking (CB) for Apache Arrow

This package contains Python macro benchmarks for Apache Arrow, as well as external benchmark wrappers that execute and record the results for both the Arrow C++, Java, and JavaScript micro benchmarks (which are found in the arrow repository), and the Arrow R macro benchmarks (which are found in the arrowbench repository). These benchmarks use the Conbench legacy runner for benchmark execution, and the results are published to Arrow's public Conbench server.

On each commit to the main Arrow branch, the C++, Python, Java, JavaScript, and R benchmarks are run on a variety of physical benchmarking machines & EC2 instances of different sizes, and the results are published to Conbench. Additionally, benchmarks can also be run on an Arrow pull request by adding a GitHub comment with the text: @ursabot please benchmark. A baseline benchmarking run against the pull request's head with also be scheduled, and Conbench comparison links will be posted as a follow-up GitHub comment.

You can also filter the pull request benchmarks runs by filter name, language, or specific command. A GitHub comment with text @ursabot benchmark help will follow-up with a list of available ursabot benchmark commands.

@ursabot benchmark help
@ursabot please benchmark
@ursabot please benchmark lang=Python
@ursabot please benchmark lang=C++
@ursabot please benchmark lang=Java
@ursabot please benchmark lang=JavaScript
@ursabot please benchmark lang=R
@ursabot please benchmark name=file-write
@ursabot please benchmark name=file-write lang=Python
@ursabot please benchmark name=file-.*
@ursabot please benchmark command=cpp-micro --suite-filter=arrow-compute-vector-selection-benchmark --benchmark-filter=TakeStringRandomIndicesWithNulls/262144/2 --iterations=3

Benchmarks added to this repository and declared in benchmarks.json will automatically be picked up by by Arrow's Continuous Benchmarking pipeline. This file is regenerated each time the unit tests are run based on the various benchmark class attributes. See the BenchmarkList class for more information on how to override any of the benchmark defaults or to disable a particular benchmark.

Index

Contributing

Create workspace

$ cd
$ mkdir -p envs
$ mkdir -p workspace
$ mkdir -p data
$ export BENCHMARKS_DATA_DIR=$(pwd)/data
$ export ARROWBENCH_DATA_DIR=$(pwd)/data

Create virualenv

$ cd ~/envs
$ python3 -m venv qa
$ source qa/bin/activate

Clone repos

(qa) $ cd ~/workspace/
(qa) $ git clone https://github.com/voltrondata-labs/benchmarks.git
(qa) $ git clone https://github.com/apache/arrow.git
(qa) $ export ARROW_SRC=$(pwd)/arrow

Install voltrondata-labs/benchmarks

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pip install -e '.[dev]'

Install arrowbench (to run R benchmarks)

$ R
> install.packages('remotes')
> remotes::install_github("voltrondata-labs/arrowbench")

Install archery (to run C++ & Java micro benchmarks)

(qa) $ cd ~/workspace/
(qa) $ pip install -e arrow/dev/archery

Conbench credentials default to this following (edit .conbench to configure)

(This is only needed if you plan on publishing benchmark results to a Conbench server.)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cat .conbench
url: http://localhost:5000
email: conbench@example.com
password: conbench

Run tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv benchmarks/tests/

Format code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ git status
modified: foo.py
(qa) $ black foo.py
reformatted foo.py
(qa) $ git add foo.py

Sort imports (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ isort .
Fixing foo.py
(qa) $ git add foo.py

Lint code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ flake8
./foo/bar/__init__.py:1:1: F401 'FooBar' imported but unused

Generate coverage report

(qa) $ cd ~/workspace/benchmarks/
(qa) $ coverage run --source benchmarks -m pytest benchmarks/tests/
(qa) $ coverage report -m

Running benchmarks

Run benchmarks as tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv --capture=no benchmarks/tests/test_file_benchmark.py
test_file_benchmark.py::test_read[parquet, uncompressed, table] PASSED
test_file_benchmark.py::test_read[parquet, uncompressed, dataframe] PASSED
test_file_benchmark.py::test_read[parquet, snappy, table] PASSED
test_file_benchmark.py::test_read[parquet, snappy, dataframe] PASSED
...

Run benchmarks from command line

Conbench can be run from either of the following directories.

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cd ~/workspace/benchmarks/benchmarks/

Use the conbench --help command to see the available benchmarks.

(qa) $ conbench --help
Usage: conbench [OPTIONS] COMMAND [ARGS]...
Conbench: Language-independent Continuous Benchmarking (CB) Framework
Options:
--help Show this message and exit.
Commands:
cpp-micro Run the Arrow C++ micro benchmarks.
csv-read Run csv-read benchmark.
dataframe-to-table Run dataframe-to-table benchmark.
dataset-filter Run dataset-filter benchmark.
dataset-read Run dataset-read benchmark(s).
dataset-select Run dataset-select benchmark.
dataset-selectivity Run dataset-selectivity benchmark(s).
example-R-only Run example-R-only benchmark.
example-R-only-exception Run example-R-only-exception benchmark.
example-R-only-no-result Run example-R-only-no-result benchmark.
example-cases Run example-cases benchmark(s).
example-cases-exception Run example-cases-exception benchmark(s).
example-external Run example-external benchmark.
example-simple Run example-simple benchmark.
example-simple-exception Run example-simple-exception benchmark.
file-read Run file-read benchmark(s).
file-write Run file-write benchmark(s).
java-micro Run the Arrow Java micro benchmarks.
js-micro Run the Arrow JavaScript micro benchmarks.
list List of benchmarks (for orchestration).
partitioned-dataset-filter Run partitioned-dataset-filter benchmark(s).
wide-dataframe Run wide-dataframe benchmark(s).

Help is also available for individual benchmark commands.

(qa) $ conbench file-write --help
Usage: conbench file-write [OPTIONS] SOURCE
Run file-write benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--file-type=parquet --compression=uncompressed --input-type=table
--file-type=parquet --compression=uncompressed --input-type=dataframe
--file-type=parquet --compression=snappy --input-type=table
--file-type=parquet --compression=snappy --input-type=dataframe
--file-type=feather --compression=uncompressed --input-type=table
--file-type=feather --compression=uncompressed --input-type=dataframe
--file-type=feather --compression=lz4 --input-type=table
--file-type=feather --compression=lz4 --input-type=dataframe
To run all combinations:
$ conbench file-write --all=true
Options:
--file-type [feather|parquet]
--compression [lz4|snappy|uncompressed]
--input-type [dataframe|table]
--all BOOLEAN [default: false]
--language [Python|R]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

Example benchmark execution.

(qa) $ conbench file-read nyctaxi_sample --file-type=feather --compression=lz4 --output-type=dataframe --iterations=10 --gc-disable=false
Benchmark result:
{
"batch_id": "3d97e0185ef44d0d9d095f4b9fdd3fd2",
"run_id": "54c00bfd6b6147739bbf1224cfdf9b1d",
"timestamp": "2021-11-11T00:32:15.061174+00:00"
"context": {
"arrow_compiler_flags": " -Qunused-arguments -fcolor-diagnostics -O3 -DNDEBUG",
"benchmark_language": "Python"
},
"github": {
"commit": "4591d76fce2846a29dac33bf01e9ba0337b118e9",
"repository": "https://github.com/apache/arrow"
},
"info": {
"arrow_compiler_id": "AppleClang",
"arrow_compiler_version": "12.0.0.12000032",
"arrow_version": "5.0.0",
"benchmark_language_version": "Python 3.9.7"
},
"machine_info": {
"architecture_name": "arm64",
"cpu_core_count": "8",
"cpu_frequency_max_hz": "0",
"cpu_l1d_cache_bytes": "65536",
"cpu_l1i_cache_bytes": "131072",
"cpu_l2_cache_bytes": "4194304",
"cpu_l3_cache_bytes": "0",
"cpu_model_name": "Apple M1",
"cpu_thread_count": "8",
"gpu_count": "0",
"gpu_product_names": [],
"kernel_name": "20.6.0",
"memory_bytes": "17179869184",
"name": "diana",
"os_name": "macOS",
"os_version": "11.5.2"
},
"stats": {
"data": [
"0.004986",
"0.001076",
"0.001132",
"0.001086",
"0.001221",
"0.001143",
"0.001074",
"0.001057",
"0.000990",
"0.001032"
],
"iqr": "0.000079",
"iterations": 10,
"max": "0.004986",
"mean": "0.001480",
"median": "0.001081",
"min": "0.000990",
"q1": "0.001061",
"q3": "0.001140",
"stdev": "0.001234",
"time_unit": "s",
"times": [],
"unit": "s"
},
"tags": {
"compression": "lz4",
"cpu_count": null,
"dataset": "nyctaxi_sample",
"file_type": "feather",
"name": "file-read",
"output_type": "dataframe"
}
}

Authoring benchmarks

There are three main types of benchmarks: "simple benchmarks" that time the execution of a unit of work, "external benchmarks" that just record benchmark results that were obtained from some other benchmarking tool, and "case benchmarks" which benchmark a unit of work under different scenarios.

Included in this repository are contrived, minimal examples of these different kinds of benchmarks to be used as templates for benchmark authoring. These example benchmarks and their tests can be found here:

Example simple benchmarks

A "simple benchmark" runs and records the execution time of a unit of work.

Implementation details: Note that this benchmark extends benchmarks._benchmark.Benchmark, implements the minimum required run() method, and registers itself with the @conbenchlegacy.runner.register_benchmark decorator.

@conbenchlegacy.runner.register_benchmarkclassSimpleBenchmark(_benchmark.Benchmark):
"""Example benchmark without cases."""name="example-simple"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
f=self._get_benchmark_function()
yieldself.benchmark(f, tags, kwargs)
def_get_benchmark_function(self):
returnlambda: 1+1
(qa) $ conbench example-simple --help
Usage: conbench example-simple [OPTIONS]
Run example-simple benchmark.
Options:
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More simple benchmark examples that have minimal scaffolding:

Example external benchmarks

An "external benchmark" records results that were obtained from some other benchmarking tool (like executing the Arrow C++ micro benchmarks from command line, parsing the resulting JSON, and recording those results).

Implementation details: Note that the following benchmark sets external = True, and calls record() rather than benchmark() as the example above does.

@conbenchlegacy.runner.register_benchmarkclassExternalBenchmark(_benchmark.Benchmark):
"""Example benchmark that just records external results."""external=Truename="example-external"defrun(self, **kwargs):
# external results from somewhere# (an API call, command line execution, etc)result= {
"data": [100, 200, 300],
"unit": "i/s",
"times": [0.100, 0.200, 0.300],
"time_unit": "s",
}
tags=self.get_tags(kwargs)
info, context= {}, {"benchmark_language": "C++"}
yieldself.record(
result,
tags,
info,
context,
options=kwargs,
output=result["data"],
)
(qa) $ conbench example-external --help
Usage: conbench example-external [OPTIONS]
Run example-external benchmark.
Options:
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

And here's another external benchmark, one that runs an external R benchmark.

Implementation details: Note that the following benchmark extends BenchmarkR, sets both external and r_only to True, defines r_name, implements _get_r_command(), and calls r_benchmark() rather than benchmark() or record().

@conbenchlegacy.runner.register_benchmarkclassWithoutPythonBenchmark(_benchmark.BenchmarkR):
"""Example R benchmark that doesn't have a Python equivalent."""external, r_only=True, Truename, r_name="example-R-only", "placebo"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
command=self._get_r_command(kwargs)
yieldself.r_benchmark(command, tags, kwargs)
def_get_r_command(self, options):
return (
f"library(arrowbench); "f"run_one(arrowbench:::{self.r_name}, "f"cpu_count={self.r_cpu_count(options)})"
)
(qa) $ conbench example-R-only --help
Usage: conbench example-R-only [OPTIONS]
Run example-R-only benchmark.
Options:
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More external benchmark examples that record C++, Java, and R benchmark results:

Example case benchmarks

A "case benchmark" is a either a "simple benchmark" or an "external benchmark" executed under various predefined scenarios (cases).

Implementation details: Note that the following benchmark declares the valid combinations in valid_cases, which reads like a CSV (the first row contains the cases names).

@conbenchlegacy.runner.register_benchmarkclassCasesBenchmark(_benchmark.Benchmark):
"""Example benchmark with cases."""name="example-cases"valid_cases= (
("rows", "columns"),
("10", "10"),
("2", "10"),
("10", "2"),
)
defrun(self, case=None, **kwargs):
tags=self.get_tags(kwargs)
forcaseinself.get_cases(case, kwargs):
rows, columns=casef=self._get_benchmark_function(rows, columns)
yieldself.benchmark(f, tags, kwargs, case)
def_get_benchmark_function(self, rows, columns):
returnlambda: int(rows) * [int(columns) * [0]]
(qa) $ conbench example-cases --help
Usage: conbench example-cases [OPTIONS]
Run example-cases benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--rows=10 --columns=10
--rows=2 --columns=10
--rows=10 --columns=2
To run all combinations:
$ conbench example-cases --all=true
Options:
--rows [10|2]
--columns [10|2]
--all BOOLEAN [default: false]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More case benchmark examples:

About

Language-independent Continuous Benchmarking (CB) for Apache Arrow

Resources

Stars

10 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
This repository is currently being migrated. It's locked while the migration is in progress.

Repository files navigation

Build StatusCoverage StatusCode style: black

Apache Arrow Benchmarks

Language-independent Continuous Benchmarking (CB) for Apache Arrow

This package contains Python macro benchmarks for Apache Arrow, as well as external benchmark wrappers that execute and record the results for both the Arrow C++, Java, and JavaScript micro benchmarks (which are found in the arrow repository), and the Arrow R macro benchmarks (which are found in the arrowbench repository). These benchmarks use the Conbench legacy runner for benchmark execution, and the results are published to Arrow's public Conbench server.

On each commit to the main Arrow branch, the C++, Python, Java, JavaScript, and R benchmarks are run on a variety of physical benchmarking machines & EC2 instances of different sizes, and the results are published to Conbench. Additionally, benchmarks can also be run on an Arrow pull request by adding a GitHub comment with the text: @ursabot please benchmark. A baseline benchmarking run against the pull request's head with also be scheduled, and Conbench comparison links will be posted as a follow-up GitHub comment.

You can also filter the pull request benchmarks runs by filter name, language, or specific command. A GitHub comment with text @ursabot benchmark help will follow-up with a list of available ursabot benchmark commands.

@ursabot benchmark help
@ursabot please benchmark
@ursabot please benchmark lang=Python
@ursabot please benchmark lang=C++
@ursabot please benchmark lang=Java
@ursabot please benchmark lang=JavaScript
@ursabot please benchmark lang=R
@ursabot please benchmark name=file-write
@ursabot please benchmark name=file-write lang=Python
@ursabot please benchmark name=file-.*
@ursabot please benchmark command=cpp-micro --suite-filter=arrow-compute-vector-selection-benchmark --benchmark-filter=TakeStringRandomIndicesWithNulls/262144/2 --iterations=3

Benchmarks added to this repository and declared in benchmarks.json will automatically be picked up by by Arrow's Continuous Benchmarking pipeline. This file is regenerated each time the unit tests are run based on the various benchmark class attributes. See the BenchmarkList class for more information on how to override any of the benchmark defaults or to disable a particular benchmark.

Index

Contributing

Create workspace

$ cd
$ mkdir -p envs
$ mkdir -p workspace
$ mkdir -p data
$ export BENCHMARKS_DATA_DIR=$(pwd)/data
$ export ARROWBENCH_DATA_DIR=$(pwd)/data

Create virualenv

$ cd ~/envs
$ python3 -m venv qa
$ source qa/bin/activate

Clone repos

(qa) $ cd ~/workspace/
(qa) $ git clone https://github.com/voltrondata-labs/benchmarks.git
(qa) $ git clone https://github.com/apache/arrow.git
(qa) $ export ARROW_SRC=$(pwd)/arrow

Install voltrondata-labs/benchmarks

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pip install -e '.[dev]'

Install arrowbench (to run R benchmarks)

$ R
> install.packages('remotes')
> remotes::install_github("voltrondata-labs/arrowbench")

Install archery (to run C++ & Java micro benchmarks)

(qa) $ cd ~/workspace/
(qa) $ pip install -e arrow/dev/archery

Conbench credentials default to this following (edit .conbench to configure)

(This is only needed if you plan on publishing benchmark results to a Conbench server.)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cat .conbench
url: http://localhost:5000
email: conbench@example.com
password: conbench

Run tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv benchmarks/tests/

Format code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ git status
modified: foo.py
(qa) $ black foo.py
reformatted foo.py
(qa) $ git add foo.py

Sort imports (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ isort .
Fixing foo.py
(qa) $ git add foo.py

Lint code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ flake8
./foo/bar/__init__.py:1:1: F401 'FooBar' imported but unused

Generate coverage report

(qa) $ cd ~/workspace/benchmarks/
(qa) $ coverage run --source benchmarks -m pytest benchmarks/tests/
(qa) $ coverage report -m

Running benchmarks

Run benchmarks as tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv --capture=no benchmarks/tests/test_file_benchmark.py
test_file_benchmark.py::test_read[parquet, uncompressed, table] PASSED
test_file_benchmark.py::test_read[parquet, uncompressed, dataframe] PASSED
test_file_benchmark.py::test_read[parquet, snappy, table] PASSED
test_file_benchmark.py::test_read[parquet, snappy, dataframe] PASSED
...

Run benchmarks from command line

Conbench can be run from either of the following directories.

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cd ~/workspace/benchmarks/benchmarks/

Use the conbench --help command to see the available benchmarks.

(qa) $ conbench --help
Usage: conbench [OPTIONS] COMMAND [ARGS]...
Conbench: Language-independent Continuous Benchmarking (CB) Framework
Options:
--help Show this message and exit.
Commands:
cpp-micro Run the Arrow C++ micro benchmarks.
csv-read Run csv-read benchmark.
dataframe-to-table Run dataframe-to-table benchmark.
dataset-filter Run dataset-filter benchmark.
dataset-read Run dataset-read benchmark(s).
dataset-select Run dataset-select benchmark.
dataset-selectivity Run dataset-selectivity benchmark(s).
example-R-only Run example-R-only benchmark.
example-R-only-exception Run example-R-only-exception benchmark.
example-R-only-no-result Run example-R-only-no-result benchmark.
example-cases Run example-cases benchmark(s).
example-cases-exception Run example-cases-exception benchmark(s).
example-external Run example-external benchmark.
example-simple Run example-simple benchmark.
example-simple-exception Run example-simple-exception benchmark.
file-read Run file-read benchmark(s).
file-write Run file-write benchmark(s).
java-micro Run the Arrow Java micro benchmarks.
js-micro Run the Arrow JavaScript micro benchmarks.
list List of benchmarks (for orchestration).
partitioned-dataset-filter Run partitioned-dataset-filter benchmark(s).
wide-dataframe Run wide-dataframe benchmark(s).

Help is also available for individual benchmark commands.

(qa) $ conbench file-write --help
Usage: conbench file-write [OPTIONS] SOURCE
Run file-write benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--file-type=parquet --compression=uncompressed --input-type=table
--file-type=parquet --compression=uncompressed --input-type=dataframe
--file-type=parquet --compression=snappy --input-type=table
--file-type=parquet --compression=snappy --input-type=dataframe
--file-type=feather --compression=uncompressed --input-type=table
--file-type=feather --compression=uncompressed --input-type=dataframe
--file-type=feather --compression=lz4 --input-type=table
--file-type=feather --compression=lz4 --input-type=dataframe
To run all combinations:
$ conbench file-write --all=true
Options:
--file-type [feather|parquet]
--compression [lz4|snappy|uncompressed]
--input-type [dataframe|table]
--all BOOLEAN [default: false]
--language [Python|R]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

Example benchmark execution.

(qa) $ conbench file-read nyctaxi_sample --file-type=feather --compression=lz4 --output-type=dataframe --iterations=10 --gc-disable=false
Benchmark result:
{
"batch_id": "3d97e0185ef44d0d9d095f4b9fdd3fd2",
"run_id": "54c00bfd6b6147739bbf1224cfdf9b1d",
"timestamp": "2021-11-11T00:32:15.061174+00:00"
"context": {
"arrow_compiler_flags": " -Qunused-arguments -fcolor-diagnostics -O3 -DNDEBUG",
"benchmark_language": "Python"
},
"github": {
"commit": "4591d76fce2846a29dac33bf01e9ba0337b118e9",
"repository": "https://github.com/apache/arrow"
},
"info": {
"arrow_compiler_id": "AppleClang",
"arrow_compiler_version": "12.0.0.12000032",
"arrow_version": "5.0.0",
"benchmark_language_version": "Python 3.9.7"
},
"machine_info": {
"architecture_name": "arm64",
"cpu_core_count": "8",
"cpu_frequency_max_hz": "0",
"cpu_l1d_cache_bytes": "65536",
"cpu_l1i_cache_bytes": "131072",
"cpu_l2_cache_bytes": "4194304",
"cpu_l3_cache_bytes": "0",
"cpu_model_name": "Apple M1",
"cpu_thread_count": "8",
"gpu_count": "0",
"gpu_product_names": [],
"kernel_name": "20.6.0",
"memory_bytes": "17179869184",
"name": "diana",
"os_name": "macOS",
"os_version": "11.5.2"
},
"stats": {
"data": [
"0.004986",
"0.001076",
"0.001132",
"0.001086",
"0.001221",
"0.001143",
"0.001074",
"0.001057",
"0.000990",
"0.001032"
],
"iqr": "0.000079",
"iterations": 10,
"max": "0.004986",
"mean": "0.001480",
"median": "0.001081",
"min": "0.000990",
"q1": "0.001061",
"q3": "0.001140",
"stdev": "0.001234",
"time_unit": "s",
"times": [],
"unit": "s"
},
"tags": {
"compression": "lz4",
"cpu_count": null,
"dataset": "nyctaxi_sample",
"file_type": "feather",
"name": "file-read",
"output_type": "dataframe"
}
}

Authoring benchmarks

There are three main types of benchmarks: "simple benchmarks" that time the execution of a unit of work, "external benchmarks" that just record benchmark results that were obtained from some other benchmarking tool, and "case benchmarks" which benchmark a unit of work under different scenarios.

Included in this repository are contrived, minimal examples of these different kinds of benchmarks to be used as templates for benchmark authoring. These example benchmarks and their tests can be found here:

Example simple benchmarks

A "simple benchmark" runs and records the execution time of a unit of work.

Implementation details: Note that this benchmark extends benchmarks._benchmark.Benchmark, implements the minimum required run() method, and registers itself with the @conbenchlegacy.runner.register_benchmark decorator.

@conbenchlegacy.runner.register_benchmarkclassSimpleBenchmark(_benchmark.Benchmark):
"""Example benchmark without cases."""name="example-simple"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
f=self._get_benchmark_function()
yieldself.benchmark(f, tags, kwargs)
def_get_benchmark_function(self):
returnlambda: 1+1
(qa) $ conbench example-simple --help
Usage: conbench example-simple [OPTIONS]
Run example-simple benchmark.
Options:
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More simple benchmark examples that have minimal scaffolding:

Example external benchmarks

An "external benchmark" records results that were obtained from some other benchmarking tool (like executing the Arrow C++ micro benchmarks from command line, parsing the resulting JSON, and recording those results).

Implementation details: Note that the following benchmark sets external = True, and calls record() rather than benchmark() as the example above does.

@conbenchlegacy.runner.register_benchmarkclassExternalBenchmark(_benchmark.Benchmark):
"""Example benchmark that just records external results."""external=Truename="example-external"defrun(self, **kwargs):
# external results from somewhere# (an API call, command line execution, etc)result= {
"data": [100, 200, 300],
"unit": "i/s",
"times": [0.100, 0.200, 0.300],
"time_unit": "s",
}
tags=self.get_tags(kwargs)
info, context= {}, {"benchmark_language": "C++"}
yieldself.record(
result,
tags,
info,
context,
options=kwargs,
output=result["data"],
)
(qa) $ conbench example-external --help
Usage: conbench example-external [OPTIONS]
Run example-external benchmark.
Options:
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

And here's another external benchmark, one that runs an external R benchmark.

Implementation details: Note that the following benchmark extends BenchmarkR, sets both external and r_only to True, defines r_name, implements _get_r_command(), and calls r_benchmark() rather than benchmark() or record().

@conbenchlegacy.runner.register_benchmarkclassWithoutPythonBenchmark(_benchmark.BenchmarkR):
"""Example R benchmark that doesn't have a Python equivalent."""external, r_only=True, Truename, r_name="example-R-only", "placebo"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
command=self._get_r_command(kwargs)
yieldself.r_benchmark(command, tags, kwargs)
def_get_r_command(self, options):
return (
f"library(arrowbench); "f"run_one(arrowbench:::{self.r_name}, "f"cpu_count={self.r_cpu_count(options)})"
)
(qa) $ conbench example-R-only --help
Usage: conbench example-R-only [OPTIONS]
Run example-R-only benchmark.
Options:
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More external benchmark examples that record C++, Java, and R benchmark results:

Example case benchmarks

A "case benchmark" is a either a "simple benchmark" or an "external benchmark" executed under various predefined scenarios (cases).

Implementation details: Note that the following benchmark declares the valid combinations in valid_cases, which reads like a CSV (the first row contains the cases names).

@conbenchlegacy.runner.register_benchmarkclassCasesBenchmark(_benchmark.Benchmark):
"""Example benchmark with cases."""name="example-cases"valid_cases= (
("rows", "columns"),
("10", "10"),
("2", "10"),
("10", "2"),
)
defrun(self, case=None, **kwargs):
tags=self.get_tags(kwargs)
forcaseinself.get_cases(case, kwargs):
rows, columns=casef=self._get_benchmark_function(rows, columns)
yieldself.benchmark(f, tags, kwargs, case)
def_get_benchmark_function(self, rows, columns):
returnlambda: int(rows) * [int(columns) * [0]]
(qa) $ conbench example-cases --help
Usage: conbench example-cases [OPTIONS]
Run example-cases benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--rows=10 --columns=10
--rows=2 --columns=10
--rows=10 --columns=2
To run all combinations:
$ conbench example-cases --all=true
Options:
--rows [10|2]
--columns [10|2]
--all BOOLEAN [default: false]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More case benchmark examples:

About

Language-independent Continuous Benchmarking (CB) for Apache Arrow

Resources

Stars

10 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository is currently being migrated. It's locked while the migration is in progress.

Repository files navigation

Build StatusCoverage StatusCode style: black

Apache Arrow Benchmarks

Language-independent Continuous Benchmarking (CB) for Apache Arrow

This package contains Python macro benchmarks for Apache Arrow, as well as external benchmark wrappers that execute and record the results for both the Arrow C++, Java, and JavaScript micro benchmarks (which are found in the arrow repository), and the Arrow R macro benchmarks (which are found in the arrowbench repository). These benchmarks use the Conbench legacy runner for benchmark execution, and the results are published to Arrow's public Conbench server.

On each commit to the main Arrow branch, the C++, Python, Java, JavaScript, and R benchmarks are run on a variety of physical benchmarking machines & EC2 instances of different sizes, and the results are published to Conbench. Additionally, benchmarks can also be run on an Arrow pull request by adding a GitHub comment with the text: @ursabot please benchmark. A baseline benchmarking run against the pull request's head with also be scheduled, and Conbench comparison links will be posted as a follow-up GitHub comment.

You can also filter the pull request benchmarks runs by filter name, language, or specific command. A GitHub comment with text @ursabot benchmark help will follow-up with a list of available ursabot benchmark commands.

@ursabot benchmark help
@ursabot please benchmark
@ursabot please benchmark lang=Python
@ursabot please benchmark lang=C++
@ursabot please benchmark lang=Java
@ursabot please benchmark lang=JavaScript
@ursabot please benchmark lang=R
@ursabot please benchmark name=file-write
@ursabot please benchmark name=file-write lang=Python
@ursabot please benchmark name=file-.*
@ursabot please benchmark command=cpp-micro --suite-filter=arrow-compute-vector-selection-benchmark --benchmark-filter=TakeStringRandomIndicesWithNulls/262144/2 --iterations=3

Benchmarks added to this repository and declared in benchmarks.json will automatically be picked up by by Arrow's Continuous Benchmarking pipeline. This file is regenerated each time the unit tests are run based on the various benchmark class attributes. See the BenchmarkList class for more information on how to override any of the benchmark defaults or to disable a particular benchmark.

Index

Contributing

Create workspace

$ cd
$ mkdir -p envs
$ mkdir -p workspace
$ mkdir -p data
$ export BENCHMARKS_DATA_DIR=$(pwd)/data
$ export ARROWBENCH_DATA_DIR=$(pwd)/data

Create virualenv

$ cd ~/envs
$ python3 -m venv qa
$ source qa/bin/activate

Clone repos

(qa) $ cd ~/workspace/
(qa) $ git clone https://github.com/voltrondata-labs/benchmarks.git
(qa) $ git clone https://github.com/apache/arrow.git
(qa) $ export ARROW_SRC=$(pwd)/arrow

Install voltrondata-labs/benchmarks

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pip install -e '.[dev]'

Install arrowbench (to run R benchmarks)

$ R
> install.packages('remotes')
> remotes::install_github("voltrondata-labs/arrowbench")

Install archery (to run C++ & Java micro benchmarks)

(qa) $ cd ~/workspace/
(qa) $ pip install -e arrow/dev/archery

Conbench credentials default to this following (edit .conbench to configure)

(This is only needed if you plan on publishing benchmark results to a Conbench server.)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cat .conbench
url: http://localhost:5000
email: conbench@example.com
password: conbench

Run tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv benchmarks/tests/

Format code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ git status
modified: foo.py
(qa) $ black foo.py
reformatted foo.py
(qa) $ git add foo.py

Sort imports (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ isort .
Fixing foo.py
(qa) $ git add foo.py

Lint code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ flake8
./foo/bar/__init__.py:1:1: F401 'FooBar' imported but unused

Generate coverage report

(qa) $ cd ~/workspace/benchmarks/
(qa) $ coverage run --source benchmarks -m pytest benchmarks/tests/
(qa) $ coverage report -m

Running benchmarks

Run benchmarks as tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv --capture=no benchmarks/tests/test_file_benchmark.py
test_file_benchmark.py::test_read[parquet, uncompressed, table] PASSED
test_file_benchmark.py::test_read[parquet, uncompressed, dataframe] PASSED
test_file_benchmark.py::test_read[parquet, snappy, table] PASSED
test_file_benchmark.py::test_read[parquet, snappy, dataframe] PASSED
...

Run benchmarks from command line

Conbench can be run from either of the following directories.

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cd ~/workspace/benchmarks/benchmarks/

Use the conbench --help command to see the available benchmarks.

(qa) $ conbench --help
Usage: conbench [OPTIONS] COMMAND [ARGS]...
Conbench: Language-independent Continuous Benchmarking (CB) Framework
Options:
--help Show this message and exit.
Commands:
cpp-micro Run the Arrow C++ micro benchmarks.
csv-read Run csv-read benchmark.
dataframe-to-table Run dataframe-to-table benchmark.
dataset-filter Run dataset-filter benchmark.
dataset-read Run dataset-read benchmark(s).
dataset-select Run dataset-select benchmark.
dataset-selectivity Run dataset-selectivity benchmark(s).
example-R-only Run example-R-only benchmark.
example-R-only-exception Run example-R-only-exception benchmark.
example-R-only-no-result Run example-R-only-no-result benchmark.
example-cases Run example-cases benchmark(s).
example-cases-exception Run example-cases-exception benchmark(s).
example-external Run example-external benchmark.
example-simple Run example-simple benchmark.
example-simple-exception Run example-simple-exception benchmark.
file-read Run file-read benchmark(s).
file-write Run file-write benchmark(s).
java-micro Run the Arrow Java micro benchmarks.
js-micro Run the Arrow JavaScript micro benchmarks.
list List of benchmarks (for orchestration).
partitioned-dataset-filter Run partitioned-dataset-filter benchmark(s).
wide-dataframe Run wide-dataframe benchmark(s).

Help is also available for individual benchmark commands.

(qa) $ conbench file-write --help
Usage: conbench file-write [OPTIONS] SOURCE
Run file-write benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--file-type=parquet --compression=uncompressed --input-type=table
--file-type=parquet --compression=uncompressed --input-type=dataframe
--file-type=parquet --compression=snappy --input-type=table
--file-type=parquet --compression=snappy --input-type=dataframe
--file-type=feather --compression=uncompressed --input-type=table
--file-type=feather --compression=uncompressed --input-type=dataframe
--file-type=feather --compression=lz4 --input-type=table
--file-type=feather --compression=lz4 --input-type=dataframe
To run all combinations:
$ conbench file-write --all=true
Options:
--file-type [feather|parquet]
--compression [lz4|snappy|uncompressed]
--input-type [dataframe|table]
--all BOOLEAN [default: false]
--language [Python|R]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

Example benchmark execution.

(qa) $ conbench file-read nyctaxi_sample --file-type=feather --compression=lz4 --output-type=dataframe --iterations=10 --gc-disable=false
Benchmark result:
{
"batch_id": "3d97e0185ef44d0d9d095f4b9fdd3fd2",
"run_id": "54c00bfd6b6147739bbf1224cfdf9b1d",
"timestamp": "2021-11-11T00:32:15.061174+00:00"
"context": {
"arrow_compiler_flags": " -Qunused-arguments -fcolor-diagnostics -O3 -DNDEBUG",
"benchmark_language": "Python"
},
"github": {
"commit": "4591d76fce2846a29dac33bf01e9ba0337b118e9",
"repository": "https://github.com/apache/arrow"
},
"info": {
"arrow_compiler_id": "AppleClang",
"arrow_compiler_version": "12.0.0.12000032",
"arrow_version": "5.0.0",
"benchmark_language_version": "Python 3.9.7"
},
"machine_info": {
"architecture_name": "arm64",
"cpu_core_count": "8",
"cpu_frequency_max_hz": "0",
"cpu_l1d_cache_bytes": "65536",
"cpu_l1i_cache_bytes": "131072",
"cpu_l2_cache_bytes": "4194304",
"cpu_l3_cache_bytes": "0",
"cpu_model_name": "Apple M1",
"cpu_thread_count": "8",
"gpu_count": "0",
"gpu_product_names": [],
"kernel_name": "20.6.0",
"memory_bytes": "17179869184",
"name": "diana",
"os_name": "macOS",
"os_version": "11.5.2"
},
"stats": {
"data": [
"0.004986",
"0.001076",
"0.001132",
"0.001086",
"0.001221",
"0.001143",
"0.001074",
"0.001057",
"0.000990",
"0.001032"
],
"iqr": "0.000079",
"iterations": 10,
"max": "0.004986",
"mean": "0.001480",
"median": "0.001081",
"min": "0.000990",
"q1": "0.001061",
"q3": "0.001140",
"stdev": "0.001234",
"time_unit": "s",
"times": [],
"unit": "s"
},
"tags": {
"compression": "lz4",
"cpu_count": null,
"dataset": "nyctaxi_sample",
"file_type": "feather",
"name": "file-read",
"output_type": "dataframe"
}
}

Authoring benchmarks

There are three main types of benchmarks: "simple benchmarks" that time the execution of a unit of work, "external benchmarks" that just record benchmark results that were obtained from some other benchmarking tool, and "case benchmarks" which benchmark a unit of work under different scenarios.

Included in this repository are contrived, minimal examples of these different kinds of benchmarks to be used as templates for benchmark authoring. These example benchmarks and their tests can be found here:

Example simple benchmarks

A "simple benchmark" runs and records the execution time of a unit of work.

Implementation details: Note that this benchmark extends benchmarks._benchmark.Benchmark, implements the minimum required run() method, and registers itself with the @conbenchlegacy.runner.register_benchmark decorator.

@conbenchlegacy.runner.register_benchmarkclassSimpleBenchmark(_benchmark.Benchmark):
"""Example benchmark without cases."""name="example-simple"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
f=self._get_benchmark_function()
yieldself.benchmark(f, tags, kwargs)
def_get_benchmark_function(self):
returnlambda: 1+1
(qa) $ conbench example-simple --help
Usage: conbench example-simple [OPTIONS]
Run example-simple benchmark.
Options:
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More simple benchmark examples that have minimal scaffolding:

Example external benchmarks

An "external benchmark" records results that were obtained from some other benchmarking tool (like executing the Arrow C++ micro benchmarks from command line, parsing the resulting JSON, and recording those results).

Implementation details: Note that the following benchmark sets external = True, and calls record() rather than benchmark() as the example above does.

@conbenchlegacy.runner.register_benchmarkclassExternalBenchmark(_benchmark.Benchmark):
"""Example benchmark that just records external results."""external=Truename="example-external"defrun(self, **kwargs):
# external results from somewhere# (an API call, command line execution, etc)result= {
"data": [100, 200, 300],
"unit": "i/s",
"times": [0.100, 0.200, 0.300],
"time_unit": "s",
}
tags=self.get_tags(kwargs)
info, context= {}, {"benchmark_language": "C++"}
yieldself.record(
result,
tags,
info,
context,
options=kwargs,
output=result["data"],
)
(qa) $ conbench example-external --help
Usage: conbench example-external [OPTIONS]
Run example-external benchmark.
Options:
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

And here's another external benchmark, one that runs an external R benchmark.

Implementation details: Note that the following benchmark extends BenchmarkR, sets both external and r_only to True, defines r_name, implements _get_r_command(), and calls r_benchmark() rather than benchmark() or record().

@conbenchlegacy.runner.register_benchmarkclassWithoutPythonBenchmark(_benchmark.BenchmarkR):
"""Example R benchmark that doesn't have a Python equivalent."""external, r_only=True, Truename, r_name="example-R-only", "placebo"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
command=self._get_r_command(kwargs)
yieldself.r_benchmark(command, tags, kwargs)
def_get_r_command(self, options):
return (
f"library(arrowbench); "f"run_one(arrowbench:::{self.r_name}, "f"cpu_count={self.r_cpu_count(options)})"
)
(qa) $ conbench example-R-only --help
Usage: conbench example-R-only [OPTIONS]
Run example-R-only benchmark.
Options:
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More external benchmark examples that record C++, Java, and R benchmark results:

Example case benchmarks

A "case benchmark" is a either a "simple benchmark" or an "external benchmark" executed under various predefined scenarios (cases).

Implementation details: Note that the following benchmark declares the valid combinations in valid_cases, which reads like a CSV (the first row contains the cases names).

@conbenchlegacy.runner.register_benchmarkclassCasesBenchmark(_benchmark.Benchmark):
"""Example benchmark with cases."""name="example-cases"valid_cases= (
("rows", "columns"),
("10", "10"),
("2", "10"),
("10", "2"),
)
defrun(self, case=None, **kwargs):
tags=self.get_tags(kwargs)
forcaseinself.get_cases(case, kwargs):
rows, columns=casef=self._get_benchmark_function(rows, columns)
yieldself.benchmark(f, tags, kwargs, case)
def_get_benchmark_function(self, rows, columns):
returnlambda: int(rows) * [int(columns) * [0]]
(qa) $ conbench example-cases --help
Usage: conbench example-cases [OPTIONS]
Run example-cases benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--rows=10 --columns=10
--rows=2 --columns=10
--rows=10 --columns=2
To run all combinations:
$ conbench example-cases --all=true
Options:
--rows [10|2]
--columns [10|2]
--all BOOLEAN [default: false]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More case benchmark examples:

About

Language-independent Continuous Benchmarking (CB) for Apache Arrow

Resources

Stars

10 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository is currently being migrated. It's locked while the migration is in progress.

Repository files navigation

Build StatusCoverage StatusCode style: black

Apache Arrow Benchmarks

Language-independent Continuous Benchmarking (CB) for Apache Arrow

This package contains Python macro benchmarks for Apache Arrow, as well as external benchmark wrappers that execute and record the results for both the Arrow C++, Java, and JavaScript micro benchmarks (which are found in the arrow repository), and the Arrow R macro benchmarks (which are found in the arrowbench repository). These benchmarks use the Conbench legacy runner for benchmark execution, and the results are published to Arrow's public Conbench server.

On each commit to the main Arrow branch, the C++, Python, Java, JavaScript, and R benchmarks are run on a variety of physical benchmarking machines & EC2 instances of different sizes, and the results are published to Conbench. Additionally, benchmarks can also be run on an Arrow pull request by adding a GitHub comment with the text: @ursabot please benchmark. A baseline benchmarking run against the pull request's head with also be scheduled, and Conbench comparison links will be posted as a follow-up GitHub comment.

You can also filter the pull request benchmarks runs by filter name, language, or specific command. A GitHub comment with text @ursabot benchmark help will follow-up with a list of available ursabot benchmark commands.

@ursabot benchmark help
@ursabot please benchmark
@ursabot please benchmark lang=Python
@ursabot please benchmark lang=C++
@ursabot please benchmark lang=Java
@ursabot please benchmark lang=JavaScript
@ursabot please benchmark lang=R
@ursabot please benchmark name=file-write
@ursabot please benchmark name=file-write lang=Python
@ursabot please benchmark name=file-.*
@ursabot please benchmark command=cpp-micro --suite-filter=arrow-compute-vector-selection-benchmark --benchmark-filter=TakeStringRandomIndicesWithNulls/262144/2 --iterations=3

Benchmarks added to this repository and declared in benchmarks.json will automatically be picked up by by Arrow's Continuous Benchmarking pipeline. This file is regenerated each time the unit tests are run based on the various benchmark class attributes. See the BenchmarkList class for more information on how to override any of the benchmark defaults or to disable a particular benchmark.

Index

Contributing

Create workspace

$ cd
$ mkdir -p envs
$ mkdir -p workspace
$ mkdir -p data
$ export BENCHMARKS_DATA_DIR=$(pwd)/data
$ export ARROWBENCH_DATA_DIR=$(pwd)/data

Create virualenv

$ cd ~/envs
$ python3 -m venv qa
$ source qa/bin/activate

Clone repos

(qa) $ cd ~/workspace/
(qa) $ git clone https://github.com/voltrondata-labs/benchmarks.git
(qa) $ git clone https://github.com/apache/arrow.git
(qa) $ export ARROW_SRC=$(pwd)/arrow

Install voltrondata-labs/benchmarks

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pip install -e '.[dev]'

Install arrowbench (to run R benchmarks)

$ R
> install.packages('remotes')
> remotes::install_github("voltrondata-labs/arrowbench")

Install archery (to run C++ & Java micro benchmarks)

(qa) $ cd ~/workspace/
(qa) $ pip install -e arrow/dev/archery

Conbench credentials default to this following (edit .conbench to configure)

(This is only needed if you plan on publishing benchmark results to a Conbench server.)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cat .conbench
url: http://localhost:5000
email: conbench@example.com
password: conbench

Run tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv benchmarks/tests/

Format code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ git status
modified: foo.py
(qa) $ black foo.py
reformatted foo.py
(qa) $ git add foo.py

Sort imports (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ isort .
Fixing foo.py
(qa) $ git add foo.py

Lint code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ flake8
./foo/bar/__init__.py:1:1: F401 'FooBar' imported but unused

Generate coverage report

(qa) $ cd ~/workspace/benchmarks/
(qa) $ coverage run --source benchmarks -m pytest benchmarks/tests/
(qa) $ coverage report -m

Running benchmarks

Run benchmarks as tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv --capture=no benchmarks/tests/test_file_benchmark.py
test_file_benchmark.py::test_read[parquet, uncompressed, table] PASSED
test_file_benchmark.py::test_read[parquet, uncompressed, dataframe] PASSED
test_file_benchmark.py::test_read[parquet, snappy, table] PASSED
test_file_benchmark.py::test_read[parquet, snappy, dataframe] PASSED
...

Run benchmarks from command line

Conbench can be run from either of the following directories.

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cd ~/workspace/benchmarks/benchmarks/

Use the conbench --help command to see the available benchmarks.

(qa) $ conbench --help
Usage: conbench [OPTIONS] COMMAND [ARGS]...
Conbench: Language-independent Continuous Benchmarking (CB) Framework
Options:
--help Show this message and exit.
Commands:
cpp-micro Run the Arrow C++ micro benchmarks.
csv-read Run csv-read benchmark.
dataframe-to-table Run dataframe-to-table benchmark.
dataset-filter Run dataset-filter benchmark.
dataset-read Run dataset-read benchmark(s).
dataset-select Run dataset-select benchmark.
dataset-selectivity Run dataset-selectivity benchmark(s).
example-R-only Run example-R-only benchmark.
example-R-only-exception Run example-R-only-exception benchmark.
example-R-only-no-result Run example-R-only-no-result benchmark.
example-cases Run example-cases benchmark(s).
example-cases-exception Run example-cases-exception benchmark(s).
example-external Run example-external benchmark.
example-simple Run example-simple benchmark.
example-simple-exception Run example-simple-exception benchmark.
file-read Run file-read benchmark(s).
file-write Run file-write benchmark(s).
java-micro Run the Arrow Java micro benchmarks.
js-micro Run the Arrow JavaScript micro benchmarks.
list List of benchmarks (for orchestration).
partitioned-dataset-filter Run partitioned-dataset-filter benchmark(s).
wide-dataframe Run wide-dataframe benchmark(s).

Help is also available for individual benchmark commands.

(qa) $ conbench file-write --help
Usage: conbench file-write [OPTIONS] SOURCE
Run file-write benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--file-type=parquet --compression=uncompressed --input-type=table
--file-type=parquet --compression=uncompressed --input-type=dataframe
--file-type=parquet --compression=snappy --input-type=table
--file-type=parquet --compression=snappy --input-type=dataframe
--file-type=feather --compression=uncompressed --input-type=table
--file-type=feather --compression=uncompressed --input-type=dataframe
--file-type=feather --compression=lz4 --input-type=table
--file-type=feather --compression=lz4 --input-type=dataframe
To run all combinations:
$ conbench file-write --all=true
Options:
--file-type [feather|parquet]
--compression [lz4|snappy|uncompressed]
--input-type [dataframe|table]
--all BOOLEAN [default: false]
--language [Python|R]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

Example benchmark execution.

(qa) $ conbench file-read nyctaxi_sample --file-type=feather --compression=lz4 --output-type=dataframe --iterations=10 --gc-disable=false
Benchmark result:
{
"batch_id": "3d97e0185ef44d0d9d095f4b9fdd3fd2",
"run_id": "54c00bfd6b6147739bbf1224cfdf9b1d",
"timestamp": "2021-11-11T00:32:15.061174+00:00"
"context": {
"arrow_compiler_flags": " -Qunused-arguments -fcolor-diagnostics -O3 -DNDEBUG",
"benchmark_language": "Python"
},
"github": {
"commit": "4591d76fce2846a29dac33bf01e9ba0337b118e9",
"repository": "https://github.com/apache/arrow"
},
"info": {
"arrow_compiler_id": "AppleClang",
"arrow_compiler_version": "12.0.0.12000032",
"arrow_version": "5.0.0",
"benchmark_language_version": "Python 3.9.7"
},
"machine_info": {
"architecture_name": "arm64",
"cpu_core_count": "8",
"cpu_frequency_max_hz": "0",
"cpu_l1d_cache_bytes": "65536",
"cpu_l1i_cache_bytes": "131072",
"cpu_l2_cache_bytes": "4194304",
"cpu_l3_cache_bytes": "0",
"cpu_model_name": "Apple M1",
"cpu_thread_count": "8",
"gpu_count": "0",
"gpu_product_names": [],
"kernel_name": "20.6.0",
"memory_bytes": "17179869184",
"name": "diana",
"os_name": "macOS",
"os_version": "11.5.2"
},
"stats": {
"data": [
"0.004986",
"0.001076",
"0.001132",
"0.001086",
"0.001221",
"0.001143",
"0.001074",
"0.001057",
"0.000990",
"0.001032"
],
"iqr": "0.000079",
"iterations": 10,
"max": "0.004986",
"mean": "0.001480",
"median": "0.001081",
"min": "0.000990",
"q1": "0.001061",
"q3": "0.001140",
"stdev": "0.001234",
"time_unit": "s",
"times": [],
"unit": "s"
},
"tags": {
"compression": "lz4",
"cpu_count": null,
"dataset": "nyctaxi_sample",
"file_type": "feather",
"name": "file-read",
"output_type": "dataframe"
}
}

Authoring benchmarks

There are three main types of benchmarks: "simple benchmarks" that time the execution of a unit of work, "external benchmarks" that just record benchmark results that were obtained from some other benchmarking tool, and "case benchmarks" which benchmark a unit of work under different scenarios.

Included in this repository are contrived, minimal examples of these different kinds of benchmarks to be used as templates for benchmark authoring. These example benchmarks and their tests can be found here:

Example simple benchmarks

A "simple benchmark" runs and records the execution time of a unit of work.

Implementation details: Note that this benchmark extends benchmarks._benchmark.Benchmark, implements the minimum required run() method, and registers itself with the @conbenchlegacy.runner.register_benchmark decorator.

@conbenchlegacy.runner.register_benchmarkclassSimpleBenchmark(_benchmark.Benchmark):
"""Example benchmark without cases."""name="example-simple"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
f=self._get_benchmark_function()
yieldself.benchmark(f, tags, kwargs)
def_get_benchmark_function(self):
returnlambda: 1+1
(qa) $ conbench example-simple --help
Usage: conbench example-simple [OPTIONS]
Run example-simple benchmark.
Options:
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More simple benchmark examples that have minimal scaffolding:

Example external benchmarks

An "external benchmark" records results that were obtained from some other benchmarking tool (like executing the Arrow C++ micro benchmarks from command line, parsing the resulting JSON, and recording those results).

Implementation details: Note that the following benchmark sets external = True, and calls record() rather than benchmark() as the example above does.

@conbenchlegacy.runner.register_benchmarkclassExternalBenchmark(_benchmark.Benchmark):
"""Example benchmark that just records external results."""external=Truename="example-external"defrun(self, **kwargs):
# external results from somewhere# (an API call, command line execution, etc)result= {
"data": [100, 200, 300],
"unit": "i/s",
"times": [0.100, 0.200, 0.300],
"time_unit": "s",
}
tags=self.get_tags(kwargs)
info, context= {}, {"benchmark_language": "C++"}
yieldself.record(
result,
tags,
info,
context,
options=kwargs,
output=result["data"],
)
(qa) $ conbench example-external --help
Usage: conbench example-external [OPTIONS]
Run example-external benchmark.
Options:
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

And here's another external benchmark, one that runs an external R benchmark.

Implementation details: Note that the following benchmark extends BenchmarkR, sets both external and r_only to True, defines r_name, implements _get_r_command(), and calls r_benchmark() rather than benchmark() or record().

@conbenchlegacy.runner.register_benchmarkclassWithoutPythonBenchmark(_benchmark.BenchmarkR):
"""Example R benchmark that doesn't have a Python equivalent."""external, r_only=True, Truename, r_name="example-R-only", "placebo"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
command=self._get_r_command(kwargs)
yieldself.r_benchmark(command, tags, kwargs)
def_get_r_command(self, options):
return (
f"library(arrowbench); "f"run_one(arrowbench:::{self.r_name}, "f"cpu_count={self.r_cpu_count(options)})"
)
(qa) $ conbench example-R-only --help
Usage: conbench example-R-only [OPTIONS]
Run example-R-only benchmark.
Options:
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More external benchmark examples that record C++, Java, and R benchmark results:

Example case benchmarks

A "case benchmark" is a either a "simple benchmark" or an "external benchmark" executed under various predefined scenarios (cases).

Implementation details: Note that the following benchmark declares the valid combinations in valid_cases, which reads like a CSV (the first row contains the cases names).

@conbenchlegacy.runner.register_benchmarkclassCasesBenchmark(_benchmark.Benchmark):
"""Example benchmark with cases."""name="example-cases"valid_cases= (
("rows", "columns"),
("10", "10"),
("2", "10"),
("10", "2"),
)
defrun(self, case=None, **kwargs):
tags=self.get_tags(kwargs)
forcaseinself.get_cases(case, kwargs):
rows, columns=casef=self._get_benchmark_function(rows, columns)
yieldself.benchmark(f, tags, kwargs, case)
def_get_benchmark_function(self, rows, columns):
returnlambda: int(rows) * [int(columns) * [0]]
(qa) $ conbench example-cases --help
Usage: conbench example-cases [OPTIONS]
Run example-cases benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--rows=10 --columns=10
--rows=2 --columns=10
--rows=10 --columns=2
To run all combinations:
$ conbench example-cases --all=true
Options:
--rows [10|2]
--columns [10|2]
--all BOOLEAN [default: false]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More case benchmark examples:

About

Language-independent Continuous Benchmarking (CB) for Apache Arrow

Resources

Stars

10 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
This repository is currently being migrated. It's locked while the migration is in progress.

Repository files navigation

Build StatusCoverage StatusCode style: black

Apache Arrow Benchmarks

Language-independent Continuous Benchmarking (CB) for Apache Arrow

This package contains Python macro benchmarks for Apache Arrow, as well as external benchmark wrappers that execute and record the results for both the Arrow C++, Java, and JavaScript micro benchmarks (which are found in the arrow repository), and the Arrow R macro benchmarks (which are found in the arrowbench repository). These benchmarks use the Conbench legacy runner for benchmark execution, and the results are published to Arrow's public Conbench server.

On each commit to the main Arrow branch, the C++, Python, Java, JavaScript, and R benchmarks are run on a variety of physical benchmarking machines & EC2 instances of different sizes, and the results are published to Conbench. Additionally, benchmarks can also be run on an Arrow pull request by adding a GitHub comment with the text: @ursabot please benchmark. A baseline benchmarking run against the pull request's head with also be scheduled, and Conbench comparison links will be posted as a follow-up GitHub comment.

You can also filter the pull request benchmarks runs by filter name, language, or specific command. A GitHub comment with text @ursabot benchmark help will follow-up with a list of available ursabot benchmark commands.

@ursabot benchmark help
@ursabot please benchmark
@ursabot please benchmark lang=Python
@ursabot please benchmark lang=C++
@ursabot please benchmark lang=Java
@ursabot please benchmark lang=JavaScript
@ursabot please benchmark lang=R
@ursabot please benchmark name=file-write
@ursabot please benchmark name=file-write lang=Python
@ursabot please benchmark name=file-.*
@ursabot please benchmark command=cpp-micro --suite-filter=arrow-compute-vector-selection-benchmark --benchmark-filter=TakeStringRandomIndicesWithNulls/262144/2 --iterations=3

Benchmarks added to this repository and declared in benchmarks.json will automatically be picked up by by Arrow's Continuous Benchmarking pipeline. This file is regenerated each time the unit tests are run based on the various benchmark class attributes. See the BenchmarkList class for more information on how to override any of the benchmark defaults or to disable a particular benchmark.

Index

Contributing

Create workspace

$ cd
$ mkdir -p envs
$ mkdir -p workspace
$ mkdir -p data
$ export BENCHMARKS_DATA_DIR=$(pwd)/data
$ export ARROWBENCH_DATA_DIR=$(pwd)/data

Create virualenv

$ cd ~/envs
$ python3 -m venv qa
$ source qa/bin/activate

Clone repos

(qa) $ cd ~/workspace/
(qa) $ git clone https://github.com/voltrondata-labs/benchmarks.git
(qa) $ git clone https://github.com/apache/arrow.git
(qa) $ export ARROW_SRC=$(pwd)/arrow

Install voltrondata-labs/benchmarks

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pip install -e '.[dev]'

Install arrowbench (to run R benchmarks)

$ R
> install.packages('remotes')
> remotes::install_github("voltrondata-labs/arrowbench")

Install archery (to run C++ & Java micro benchmarks)

(qa) $ cd ~/workspace/
(qa) $ pip install -e arrow/dev/archery

Conbench credentials default to this following (edit .conbench to configure)

(This is only needed if you plan on publishing benchmark results to a Conbench server.)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cat .conbench
url: http://localhost:5000
email: conbench@example.com
password: conbench

Run tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv benchmarks/tests/

Format code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ git status
modified: foo.py
(qa) $ black foo.py
reformatted foo.py
(qa) $ git add foo.py

Sort imports (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ isort .
Fixing foo.py
(qa) $ git add foo.py

Lint code (before committing)

(qa) $ cd ~/workspace/benchmarks/
(qa) $ flake8
./foo/bar/__init__.py:1:1: F401 'FooBar' imported but unused

Generate coverage report

(qa) $ cd ~/workspace/benchmarks/
(qa) $ coverage run --source benchmarks -m pytest benchmarks/tests/
(qa) $ coverage report -m

Running benchmarks

Run benchmarks as tests

(qa) $ cd ~/workspace/benchmarks/
(qa) $ pytest -vv --capture=no benchmarks/tests/test_file_benchmark.py
test_file_benchmark.py::test_read[parquet, uncompressed, table] PASSED
test_file_benchmark.py::test_read[parquet, uncompressed, dataframe] PASSED
test_file_benchmark.py::test_read[parquet, snappy, table] PASSED
test_file_benchmark.py::test_read[parquet, snappy, dataframe] PASSED
...

Run benchmarks from command line

Conbench can be run from either of the following directories.

(qa) $ cd ~/workspace/benchmarks/
(qa) $ cd ~/workspace/benchmarks/benchmarks/

Use the conbench --help command to see the available benchmarks.

(qa) $ conbench --help
Usage: conbench [OPTIONS] COMMAND [ARGS]...
Conbench: Language-independent Continuous Benchmarking (CB) Framework
Options:
--help Show this message and exit.
Commands:
cpp-micro Run the Arrow C++ micro benchmarks.
csv-read Run csv-read benchmark.
dataframe-to-table Run dataframe-to-table benchmark.
dataset-filter Run dataset-filter benchmark.
dataset-read Run dataset-read benchmark(s).
dataset-select Run dataset-select benchmark.
dataset-selectivity Run dataset-selectivity benchmark(s).
example-R-only Run example-R-only benchmark.
example-R-only-exception Run example-R-only-exception benchmark.
example-R-only-no-result Run example-R-only-no-result benchmark.
example-cases Run example-cases benchmark(s).
example-cases-exception Run example-cases-exception benchmark(s).
example-external Run example-external benchmark.
example-simple Run example-simple benchmark.
example-simple-exception Run example-simple-exception benchmark.
file-read Run file-read benchmark(s).
file-write Run file-write benchmark(s).
java-micro Run the Arrow Java micro benchmarks.
js-micro Run the Arrow JavaScript micro benchmarks.
list List of benchmarks (for orchestration).
partitioned-dataset-filter Run partitioned-dataset-filter benchmark(s).
wide-dataframe Run wide-dataframe benchmark(s).

Help is also available for individual benchmark commands.

(qa) $ conbench file-write --help
Usage: conbench file-write [OPTIONS] SOURCE
Run file-write benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--file-type=parquet --compression=uncompressed --input-type=table
--file-type=parquet --compression=uncompressed --input-type=dataframe
--file-type=parquet --compression=snappy --input-type=table
--file-type=parquet --compression=snappy --input-type=dataframe
--file-type=feather --compression=uncompressed --input-type=table
--file-type=feather --compression=uncompressed --input-type=dataframe
--file-type=feather --compression=lz4 --input-type=table
--file-type=feather --compression=lz4 --input-type=dataframe
To run all combinations:
$ conbench file-write --all=true
Options:
--file-type [feather|parquet]
--compression [lz4|snappy|uncompressed]
--input-type [dataframe|table]
--all BOOLEAN [default: false]
--language [Python|R]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

Example benchmark execution.

(qa) $ conbench file-read nyctaxi_sample --file-type=feather --compression=lz4 --output-type=dataframe --iterations=10 --gc-disable=false
Benchmark result:
{
"batch_id": "3d97e0185ef44d0d9d095f4b9fdd3fd2",
"run_id": "54c00bfd6b6147739bbf1224cfdf9b1d",
"timestamp": "2021-11-11T00:32:15.061174+00:00"
"context": {
"arrow_compiler_flags": " -Qunused-arguments -fcolor-diagnostics -O3 -DNDEBUG",
"benchmark_language": "Python"
},
"github": {
"commit": "4591d76fce2846a29dac33bf01e9ba0337b118e9",
"repository": "https://github.com/apache/arrow"
},
"info": {
"arrow_compiler_id": "AppleClang",
"arrow_compiler_version": "12.0.0.12000032",
"arrow_version": "5.0.0",
"benchmark_language_version": "Python 3.9.7"
},
"machine_info": {
"architecture_name": "arm64",
"cpu_core_count": "8",
"cpu_frequency_max_hz": "0",
"cpu_l1d_cache_bytes": "65536",
"cpu_l1i_cache_bytes": "131072",
"cpu_l2_cache_bytes": "4194304",
"cpu_l3_cache_bytes": "0",
"cpu_model_name": "Apple M1",
"cpu_thread_count": "8",
"gpu_count": "0",
"gpu_product_names": [],
"kernel_name": "20.6.0",
"memory_bytes": "17179869184",
"name": "diana",
"os_name": "macOS",
"os_version": "11.5.2"
},
"stats": {
"data": [
"0.004986",
"0.001076",
"0.001132",
"0.001086",
"0.001221",
"0.001143",
"0.001074",
"0.001057",
"0.000990",
"0.001032"
],
"iqr": "0.000079",
"iterations": 10,
"max": "0.004986",
"mean": "0.001480",
"median": "0.001081",
"min": "0.000990",
"q1": "0.001061",
"q3": "0.001140",
"stdev": "0.001234",
"time_unit": "s",
"times": [],
"unit": "s"
},
"tags": {
"compression": "lz4",
"cpu_count": null,
"dataset": "nyctaxi_sample",
"file_type": "feather",
"name": "file-read",
"output_type": "dataframe"
}
}

Authoring benchmarks

There are three main types of benchmarks: "simple benchmarks" that time the execution of a unit of work, "external benchmarks" that just record benchmark results that were obtained from some other benchmarking tool, and "case benchmarks" which benchmark a unit of work under different scenarios.

Included in this repository are contrived, minimal examples of these different kinds of benchmarks to be used as templates for benchmark authoring. These example benchmarks and their tests can be found here:

Example simple benchmarks

A "simple benchmark" runs and records the execution time of a unit of work.

Implementation details: Note that this benchmark extends benchmarks._benchmark.Benchmark, implements the minimum required run() method, and registers itself with the @conbenchlegacy.runner.register_benchmark decorator.

@conbenchlegacy.runner.register_benchmarkclassSimpleBenchmark(_benchmark.Benchmark):
"""Example benchmark without cases."""name="example-simple"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
f=self._get_benchmark_function()
yieldself.benchmark(f, tags, kwargs)
def_get_benchmark_function(self):
returnlambda: 1+1
(qa) $ conbench example-simple --help
Usage: conbench example-simple [OPTIONS]
Run example-simple benchmark.
Options:
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More simple benchmark examples that have minimal scaffolding:

Example external benchmarks

An "external benchmark" records results that were obtained from some other benchmarking tool (like executing the Arrow C++ micro benchmarks from command line, parsing the resulting JSON, and recording those results).

Implementation details: Note that the following benchmark sets external = True, and calls record() rather than benchmark() as the example above does.

@conbenchlegacy.runner.register_benchmarkclassExternalBenchmark(_benchmark.Benchmark):
"""Example benchmark that just records external results."""external=Truename="example-external"defrun(self, **kwargs):
# external results from somewhere# (an API call, command line execution, etc)result= {
"data": [100, 200, 300],
"unit": "i/s",
"times": [0.100, 0.200, 0.300],
"time_unit": "s",
}
tags=self.get_tags(kwargs)
info, context= {}, {"benchmark_language": "C++"}
yieldself.record(
result,
tags,
info,
context,
options=kwargs,
output=result["data"],
)
(qa) $ conbench example-external --help
Usage: conbench example-external [OPTIONS]
Run example-external benchmark.
Options:
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

And here's another external benchmark, one that runs an external R benchmark.

Implementation details: Note that the following benchmark extends BenchmarkR, sets both external and r_only to True, defines r_name, implements _get_r_command(), and calls r_benchmark() rather than benchmark() or record().

@conbenchlegacy.runner.register_benchmarkclassWithoutPythonBenchmark(_benchmark.BenchmarkR):
"""Example R benchmark that doesn't have a Python equivalent."""external, r_only=True, Truename, r_name="example-R-only", "placebo"defrun(self, **kwargs):
tags=self.get_tags(kwargs)
command=self._get_r_command(kwargs)
yieldself.r_benchmark(command, tags, kwargs)
def_get_r_command(self, options):
return (
f"library(arrowbench); "f"run_one(arrowbench:::{self.r_name}, "f"cpu_count={self.r_cpu_count(options)})"
)
(qa) $ conbench example-R-only --help
Usage: conbench example-R-only [OPTIONS]
Run example-R-only benchmark.
Options:
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--cpu-count INTEGER
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More external benchmark examples that record C++, Java, and R benchmark results:

Example case benchmarks

A "case benchmark" is a either a "simple benchmark" or an "external benchmark" executed under various predefined scenarios (cases).

Implementation details: Note that the following benchmark declares the valid combinations in valid_cases, which reads like a CSV (the first row contains the cases names).

@conbenchlegacy.runner.register_benchmarkclassCasesBenchmark(_benchmark.Benchmark):
"""Example benchmark with cases."""name="example-cases"valid_cases= (
("rows", "columns"),
("10", "10"),
("2", "10"),
("10", "2"),
)
defrun(self, case=None, **kwargs):
tags=self.get_tags(kwargs)
forcaseinself.get_cases(case, kwargs):
rows, columns=casef=self._get_benchmark_function(rows, columns)
yieldself.benchmark(f, tags, kwargs, case)
def_get_benchmark_function(self, rows, columns):
returnlambda: int(rows) * [int(columns) * [0]]
(qa) $ conbench example-cases --help
Usage: conbench example-cases [OPTIONS]
Run example-cases benchmark(s).
For each benchmark option, the first option value is the default.
Valid benchmark combinations:
--rows=10 --columns=10
--rows=2 --columns=10
--rows=10 --columns=2
To run all combinations:
$ conbench example-cases --all=true
Options:
--rows [10|2]
--columns [10|2]
--all BOOLEAN [default: false]
--cpu-count INTEGER
--iterations INTEGER [default: 1]
--drop-caches BOOLEAN [default: false]
--gc-collect BOOLEAN [default: true]
--gc-disable BOOLEAN [default: true]
--show-result BOOLEAN [default: true]
--show-output BOOLEAN [default: false]
--run-id TEXT Group executions together with a run id.
--run-name TEXT Name of run (commit, pull request, etc).
--help Show this message and exit.

More case benchmark examples:

About

Language-independent Continuous Benchmarking (CB) for Apache Arrow

Resources

Stars

10 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages