chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:25:07 +08:00
commit a26e856398
1681 changed files with 296950 additions and 0 deletions
@@ -0,0 +1,15 @@
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
# ┃ This file is part of the Perspective library, distributed under the terms ┃
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
from bench import Benchmark, Suite, Runner
__all__ = ["Benchmark", "Suite", "Runner"]
@@ -0,0 +1,349 @@
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
# ┃ This file is part of the Perspective library, distributed under the terms ┃
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
import logging
import os
import sys
import signal
import subprocess
import venv
import tornado
from timeit import timeit
from perspective import (
Table,
PerspectiveManager,
PerspectiveTornadoHandler,
)
logging.basicConfig(level=logging.INFO)
ARROW_PATH = os.path.join(
os.path.dirname(__file__),
"..",
"..",
"..",
"..",
"tools",
"perspective-bench",
"dist",
"benchmark-python.arrow",
)
BASELINE = {
"name": [
"arrow",
"csv",
"one",
"one_1_pivot",
"one_2_pivot",
"to_arrow",
"to_arrow_r1",
"to_arrow_r1_c1",
"to_arrow_r2",
"to_arrow_r2_c2",
"to_columns",
"to_columns_r1",
"to_columns_r1_c1",
"to_columns_r2",
"to_columns_r2_c2",
"to_csv",
"to_csv_r1",
"to_csv_r1_c1",
"to_csv_r2",
"to_csv_r2_c2",
"to_records",
"to_records_r1",
"to_records_r1_c1",
"to_records_r2",
"to_records_r2_c2",
"two",
"two_1x1_pivot",
"two_2x2_pivot",
"zero",
],
"time": [
0.007100801400002865,
0.2905632236999963,
0.31363245369999504,
0.5827624402000027,
0.5723526209999988,
0.3929776023999921,
0.00021701669998037688,
0.005837792799991348,
0.0012358780999875308,
0.06712399980000328,
1.5685727534000022,
0.00040022939999744266,
0.007451989500009404,
0.0027319223000063174,
0.08117095989999826,
0.5763108057000068,
0.0003611342000112927,
0.008143171199992593,
0.0019054690000075425,
0.07623720379999668,
2.040859387900002,
0.00047493509999867455,
0.008475803500004986,
0.0036788466000075458,
0.09640174390000311,
1.1455542396000056,
1.9211396786000023,
1.9244194315999947,
0.10238117819999956,
],
}
class VirtualEnvHandler(object):
"""Creates and manages a virtualenv for benchmarking, which allows for
clean dependency management and benchmarking of multiple versions without
contaminating the system's `site-packages` folder."""
def __init__(self, virtualenv_path):
self._virtualenv_path = virtualenv_path
self._is_activated = False
def virtualenv_exists(self):
"""Returns whether the directory specified by `VIRTUALENV_PATH`
exists."""
return os.path.exists(self._virtualenv_path)
def activate_virtualenv(self):
"""Activates the virtualenv at `VIRTUALENV_PATH`."""
logging.info("Activating virtualenv at: `{}`".format(self._virtualenv_path))
self._is_activated = True
return ". {}/bin/activate".format(self._virtualenv_path)
def create_virtualenv(self):
"""Clears the folder and creates a new virtualenv at
`self._virtualenv_path`."""
if self.virtualenv_exists():
logging.ERROR("Virtualenv already exists at: `{0}`".format(self._virtualenv_path))
return
logging.info("Creating virtualenv at: `{}`".format(self._virtualenv_path))
venv.create(self._virtualenv_path, clear=True, with_pip=True)
def deactivate_virtualenv(self):
if self.virtualenv_exists() and self._is_activated:
subprocess.check_output("deactivate", shell=True)
logging.info("Virtualenv deactivated!")
self._is_activated = False
class BenchmarkTornadoHandler(tornado.web.RequestHandler):
"""Host the results of the benchmark suite over a websocket."""
def set_default_headers(self):
self.set_header("Access-Control-Allow-Origin", "*")
self.set_header("Access-Control-Allow-Headers", "x-requested-with")
self.set_header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
def get(self):
self.render("benchmark_hosted.html")
class Benchmark(object):
"""A single Benchmark function. Use as a wrapper for stateless lambdas
with no parameters.
Example:
>>> func = Benchmark(lambda: self._view.to_records(), meta={
"name": "to_records",
"group": "view"
})
"""
def __init__(self, func, meta={}):
"""A decorator for a benchmark function, which will attach each attribute
of the `meta` dictionary to the decorated function as well as provide
it with the `benchmark` attribute.
Args:
meta (dict) : a metadata dictionary, whose keys and values will
become attributes on the benchmark function. The metadata dictionary
should be consistent within each suite, i.e. there should be no
additional values in between different methods decorated with
`@benchmark`.
"""
self._func = func
self._meta = meta
self.benchmark = True
for k, v in self._meta.items():
marked_key = "__BENCH__{0}".format(k)
setattr(self, marked_key, v)
def __call__(self):
"""Call the lambda bound to the decorator. This call asserts that the
lambda has no parameters and no reference to a `self` object.
"""
self._func()
class Suite(object):
"""A benchmark suite stub that contains `register_benchmarks` and generic
before/after methods.
Inherit from this class and implement `register_benchmarks`, which should
set all benchmark methods as attributes on the class.
"""
def register_benchmarks(self):
"""Registers all callbacks with `Runner`.
This function must be implemented in all child classes of `Suite.`
"""
raise NotImplementedError("Must implement `register_benchmarks` to run benchmark suite.")
def before_all(self):
pass
def after_all(self):
pass
def before_each(self):
pass
def after_each(self):
pass
class Runner(object):
ITERATIONS = 10
def __init__(self, suite):
"""Initializes a benchmark runner for the `Suite`.
Args:
suite (Suite) : A class that inherits from `Suite`, with any number
of instance methods decorated with `@benchmark`.
"""
self._suite = suite
self._benchmarks = []
self._table = None
self._WROTE_RESULTS = False
self._HOSTING = False
self._suite.register_benchmarks()
class_attrs = self._suite.__class__.__dict__.items()
instance_attrs = self._suite.__dict__.items()
for k, v in class_attrs:
if hasattr(v, "benchmark") and getattr(v, "benchmark") is True:
logging.debug("Registering {0}".format(k))
self._benchmarks.append(v)
for k, v in instance_attrs:
if hasattr(v, "benchmark") and getattr(v, "benchmark") is True:
logging.debug("Registering {0}".format(k))
self._benchmarks.append(v)
# Write results on SIGINT
signal.signal(signal.SIGINT, self.sigint_handler)
def sigint_handler(self, signum, frame):
"""On SIGINT, host the results over a websocket."""
if not self._WROTE_RESULTS:
self.write_results()
if not self._HOSTING:
self.host_results()
else:
sys.exit(0)
def host_results(self):
"""Create a tornado application that hosts the results table over a
websocket."""
if self._table is None:
return
MANAGER = PerspectiveManager()
MANAGER.host_table("benchmark_results", self._table)
application = tornado.web.Application(
[
(r"/", BenchmarkTornadoHandler),
# create a websocket endpoint that the client Javascript can access
(
r"/websocket",
PerspectiveTornadoHandler,
{"manager": MANAGER, "check_origin": True},
),
]
)
self._HOSTING = True
application.listen(8888)
logging.warn("Displaying results at http://localhost:8888")
loop = tornado.ioloop.IOLoop.current()
loop.start()
def write_results(self):
if self._table is None:
return
logging.debug("Writing results to `benchmark-python.arrow`")
if not os.path.exists(os.path.dirname(ARROW_PATH)):
os.makedirs(os.path.dirname(ARROW_PATH))
with open(ARROW_PATH, "wb") as file:
arrow = self._table.view().to_arrow(compression=None)
file.write(arrow)
html_path = os.path.join(os.path.dirname(__file__), "benchmark-python.html")
out_path = os.path.join(os.path.dirname(ARROW_PATH), "benchmark-python.html")
with open(html_path, "r") as input:
with open(out_path, "w") as output:
output.write(input.read())
self._WROTE_RESULTS = True
def run_method(self, func, *args, **kwargs):
"""Wrap the benchmark `func` with timing code and run for n
`ITERATIONS`, returning a result row that can be fed into Perspective.
"""
overall_result = {k.replace("__BENCH__", ""): v for (k, v) in func.__dict__.items() if "__BENCH__" in k}
result = timeit(func, number=Runner.ITERATIONS) / Runner.ITERATIONS
overall_result["__TIME__"] = result
overall_result["baseline"] = BASELINE["time"][BASELINE["name"].index(overall_result["name"])]
return overall_result
def print_result(self, result):
logging.info(
"{:<9} {:<14} {:<7} {:>2.4f}s".format(
result["group"],
result["name"],
result["version"],
result["__TIME__"],
)
)
def run(self, version):
"""Runs each benchmark function from the suite for n `ITERATIONS`,
timing each function and writing the results to a `perspective.Table`.
"""
logging.info("Running benchmark suite...")
for benchmark in self._benchmarks:
result = self.run_method(benchmark)
result["version"] = version
self.print_result(result)
if self._table is None:
if os.path.exists(ARROW_PATH):
# if arrow exists, append to it
with open(ARROW_PATH, "rb") as arr:
print("Reading table from pre-existing benchmark-python.arrow")
self._table = Table(arr.read())
self._table.update([result])
else:
print("Creating new table")
self._table = Table([result])
else:
self._table.update([result])
@@ -0,0 +1,39 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<script type="module" src="node_modules/@perspective-dev/viewer/dist/cdn/perspective-viewer.js"></script>
<script type="module" src="node_modules/@perspective-dev/viewer-datagrid/dist/cdn/perspective-viewer-datagrid.js"></script>
<script type="module" src="node_modules/@perspective-dev/viewer-charts/dist/cdn/perspective-viewer-charts.js"></script>
<link rel="stylesheet" crossorigin="anonymous" href="/node_modules/@perspective-dev/viewer/dist/css/themes.css" />
<style>
perspective-viewer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
</style>
</head>
<body>
<perspective-viewer></perspective-viewer>
<script type="module">
import perspective from "/node_modules/@perspective-dev/client/dist/cdn/perspective.js";
const el = document.getElementsByTagName("perspective-viewer")[0];
el.addEventListener("perspective-config-update", async () => localStorage.setItem("layout", JSON.stringify(await el.save())));
const req = await fetch("benchmark-python.arrow");
const arrow = await req.arrayBuffer();
const worker = perspective.worker();
const table = await worker.table(arrow);
el.load(table);
el.restore(JSON.parse(localStorage.getItem("layout")));
el.toggleConfig();
</script>
</body>
</html>
@@ -0,0 +1,43 @@
<!--
Copyright (c) 2019, the Perspective Authors.
This file is part of the Perspective library, distributed under the terms of
the Apache License 2.0. The full license can be found in the LICENSE file.
-->
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<script src="http://localhost:8080/perspective-viewer"></script>
<script src="http://localhost:8080/perspective-viewer-datagrid"></script>
<script src="http://localhost:8080/perspective-viewer-charts"></script>
<script src="http://localhost:8080/perspective"></script>
<link rel="stylesheet" href="http://localhost:8080/pro.dark.css" />
<style>
perspective-viewer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
</style>
</head>
<body>
<perspective-viewer id="viewer" editable plugin="Y Bar" columns='["__TIME__"]' row-pivots='["group", "name"]' column-pivots='["group", "name"]' aggregates="{'__TIME__':'avg'}">
</perspective-viewer>
<script>
const websocket = perspective.websocket("ws://localhost:8888/websocket");
const table = websocket.open_table("benchmark_results");
document.getElementById("viewer").load(table);
</script>
</body>
</html>
@@ -0,0 +1,242 @@
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
# ┃ This file is part of the Perspective library, distributed under the terms ┃
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
import os
from functools import partial
from bench import Benchmark, Suite, Runner
from perspective import Table
import perspective
import logging
SUPERSTORE_ARROW = os.path.join(
os.path.dirname(__file__),
"..",
"..",
"..",
"..",
"node_modules",
"superstore-arrow",
"superstore.arrow",
)
with open(SUPERSTORE_ARROW, "rb") as f:
SUPERSTORE_ARROW_DATA = f.read()
VERSIONS = ["master", "0.4.1", "0.4.0rc6"]
def make_meta(group, name):
return {"group": group, "name": name}
def empty_callback(port_id):
pass
class PerspectiveBenchmark(Suite):
AGG_OPTIONS = [
[{"column": "Sales", "op": "sum"}],
[{"column": "State", "op": "dominant"}],
[{"column": "Order Date", "op": "dominant"}],
]
split_by_OPTIONS = [[], ["Sub-Category"], ["Category", "Sub-Category"]]
group_by_OPTIONS = [[], ["State"], ["State", "City"]]
def __init__(self):
"""Create a benchmark suite for the `perspective-python` runtime."""
tbl = Table(SUPERSTORE_ARROW_DATA)
for x in range(19):
tbl.update(SUPERSTORE_ARROW_DATA)
self._schema = tbl.schema()
self._df_schema = tbl.schema()
# mutate schema to have some integer columns, so as to force numpy
# float-to-int demotion
self._df_schema["Sales"] = int
self._df_schema["Profit"] = int
self._df_schema["Quantity"] = int
self._view = tbl.view()
self._table = tbl
def _get_update_data(self, n=30):
"""Retrieve n rows from self.records to be used as update data."""
return SUPERSTORE_ARROW_DATA
def register_benchmarks(self):
"""Register all the benchmark methods - each method creates a number of
lambdas, and then calls `setattr` on the Suite itself so that the
`Runner` can find the tests at runtime."""
self.benchmark_table_arrow()
self.benchmark_table_csv()
self.benchmark_view_zero()
self.benchmark_view_one()
self.benchmark_view_two()
self.benchmark_view_zero_updates()
self.benchmark_view_one_updates()
self.benchmark_view_two_updates()
self.benchmark_to_format_zero()
self.benchmark_to_format_one()
self.benchmark_to_format_two()
def benchmark_table_arrow(self):
"""Benchmark table from arrow separately as it requires opening the
Arrow file from the filesystem."""
test_meta = make_meta("table", "arrow")
func = Benchmark(lambda: Table(SUPERSTORE_ARROW_DATA), meta=test_meta)
setattr(self, "table_arrow", func)
def benchmark_table_csv(self):
"""Benchmark table from csv separately as it requires opening the
Arrow file from the filesystem."""
csv = self._view.to_csv()
test_meta = make_meta("table", "csv")
func = Benchmark(lambda: Table(csv), meta=test_meta)
setattr(self, "table_csv", func)
def benchmark_view_zero(self):
"""Benchmark view creation with zero pivots."""
func = Benchmark(lambda: self._table.view(), meta=make_meta("view", "zero"))
setattr(self, "view_zero", func)
def benchmark_view_zero_updates(self):
"""Benchmark how long it takes for each update to resolve fully, using
the on update callback that forces resolution of updates across
10 views."""
table = Table(self._schema)
views = [table.view() for i in range(25)]
for v in views:
v.on_update(empty_callback)
update_data = self._get_update_data(1000)
def resolve_update():
table.update(update_data)
table.size()
func = Benchmark(resolve_update, meta=make_meta("update", "zero"))
setattr(self, "update_zero", func)
def benchmark_view_one(self):
"""Benchmark view creation with different pivots."""
for pivot in PerspectiveBenchmark.group_by_OPTIONS:
if len(pivot) == 0:
continue
test_meta = make_meta("view", "one_{0}_pivot".format(len(pivot)))
view_constructor = partial(self._table.view, group_by=pivot)
func = Benchmark(lambda: view_constructor(), meta=test_meta)
setattr(self, "view_{0}".format(test_meta["name"]), func)
def benchmark_view_one_updates(self):
"""Benchmark how long it takes for each update to resolve fully, using
the on update callback that forces resolution of updates across
25 views."""
table = Table(self._schema)
views = [table.view(group_by=["State", "City"]) for i in range(25)]
for v in views:
v.on_update(empty_callback)
update_data = self._get_update_data(1000)
def resolve_update():
table.update(update_data)
table.size()
func = Benchmark(resolve_update, meta=make_meta("update", "one"))
setattr(self, "update_one", func)
def benchmark_view_two(self):
"""Benchmark view creation with row and Split By."""
for i in range(len(PerspectiveBenchmark.group_by_OPTIONS)):
RP = PerspectiveBenchmark.group_by_OPTIONS[i]
CP = PerspectiveBenchmark.split_by_OPTIONS[i]
if len(RP) == 0 and len(CP) == 0:
continue
test_meta = make_meta("view", "two_{0}x{1}_pivot".format(len(RP), len(CP)))
view_constructor = partial(self._table.view, group_by=RP, split_by=CP)
func = Benchmark(lambda: view_constructor(), meta=test_meta)
setattr(self, "view_{0}".format(test_meta["name"]), func)
def benchmark_view_two_updates(self):
"""Benchmark how long it takes for each update to resolve fully, using
the on update callback that forces resolution of updates across
25 views."""
table = Table(self._schema)
views = [table.view(group_by=["State", "City"], split_by=["Category", "Sub-Category"]) for i in range(25)]
for v in views:
v.on_update(empty_callback)
update_data = self._get_update_data(1000)
def resolve_update():
table.update(update_data)
table.size()
func = Benchmark(resolve_update, meta=make_meta("update", "two"))
setattr(self, "update_two", func)
def benchmark_to_format_zero(self):
"""Benchmark each `to_format` method."""
for name in (
"arrow",
"csv",
"columns",
"records",
):
method = "to_{0}".format(name)
test_meta = make_meta("to_format", method)
func = Benchmark(getattr(self._view, method), meta=test_meta)
setattr(self, "to_format_{0}".format(name), func)
def benchmark_to_format_one(self):
"""Benchmark each `to_format` method for one-sided contexts."""
for name in (
"arrow",
"csv",
"columns",
"records",
):
for pivot in PerspectiveBenchmark.group_by_OPTIONS:
if len(pivot) == 0:
continue
test_meta = make_meta("to_format", "to_{0}_r{1}".format(name, len(pivot)))
view = self._table.view(group_by=pivot)
method = "to_{0}".format(name)
func = Benchmark(getattr(view, method), meta=test_meta)
setattr(self, "to_format_{0}".format(test_meta["name"]), func)
def benchmark_to_format_two(self):
"""Benchmark each `to_format` method for two-sided contexts."""
for name in (
"arrow",
"csv",
"columns",
"records",
):
for i in range(len(PerspectiveBenchmark.group_by_OPTIONS)):
RP = PerspectiveBenchmark.group_by_OPTIONS[i]
CP = PerspectiveBenchmark.split_by_OPTIONS[i]
if len(RP) == 0 and len(CP) == 0:
continue
test_meta = make_meta("to_format", "to_{0}_r{1}_c{2}".format(name, len(RP), len(CP)))
view = self._table.view(group_by=RP, split_by=CP)
method = "to_{0}".format(name)
func = Benchmark(getattr(view, method), meta=test_meta)
setattr(self, "to_format_{0}".format(test_meta["name"]), func)
if __name__ == "__main__":
VERSION = os.environ.get("PSP_VERSION", "Unknown Version")
# Initialize a suite and runner, then call `.run()`
suite = PerspectiveBenchmark()
runner = Runner(suite)
logging.info("Benchmarking perspective-python=={}".format(VERSION))
logging.info("Detected {} {}".format(perspective.__version__, perspective.__file__))
runner.run(VERSION)
runner.write_results()
@@ -0,0 +1,80 @@
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
# ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
# ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
# ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
# ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
# ┃ Copyright (c) 2017, the Perspective Authors. ┃
# ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
# ┃ This file is part of the Perspective library, distributed under the terms ┃
# ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
import os
import subprocess
from bench import VirtualEnvHandler
import logging
if __name__ == "__main__":
"""Benchmark the `perspective-python` runtime locally."""
VERSIONS = [
"master",
"2.7.0",
"2.6.0",
"2.5.0",
"2.4.0",
"2.3.2",
"2.3.1",
# "2.3.0",
"2.2.1",
"2.2.0",
]
# Access the benchmark virtualenv
HERE = os.path.abspath(os.path.dirname(__file__))
VIRTUALENV_NAME = "benchmark_venv"
VIRTUALENV_PATH = os.path.join(HERE, "..", "..", "..", "..", VIRTUALENV_NAME)
venv_handler = VirtualEnvHandler(VIRTUALENV_PATH)
print("Benchmarking perspective-python==master")
logging.info(venv_handler.activate_virtualenv())
env = {k: v for (k, v) in os.environ.items()}
env["PSP_VERSION"] = "master"
subprocess.check_output(
"python3 {}/perspective_benchmark.py master".format(HERE),
shell=True,
env=env,
)
# Run previous versions in virtualenv
if not venv_handler.virtualenv_exists():
venv_handler.create_virtualenv()
last_version = "master"
for version in VERSIONS[1:]:
env["PSP_VERSION"] = version
env["PYTHONPATH"] = ""
logging.info("Uninstalling perspective-python=={}".format(last_version))
last_version = version
logging.debug(
subprocess.check_output(
"{} && yes | python3 -m pip uninstall perspective-python".format(venv_handler.activate_virtualenv()),
shell=True,
env=env,
)
)
logging.info("Installing perspective-python=={}".format(version))
logging.debug(
subprocess.check_output(
"{} && yes | python3 -m pip install perspective-python[dev]=={}".format(venv_handler.activate_virtualenv(), version),
shell=True,
env=env,
)
)
logging.info("Benchmarking perspective-python=={}".format(version))
subprocess.check_output(
"{} && python3 {}/perspective_benchmark.py {}".format(venv_handler.activate_virtualenv(), HERE, version),
shell=True,
env=env,
)