Repository navigation
Expand file tree
/
Copy pathregistration_scaling.py
More file actions
69 lines (53 loc) · 2.43 KB
/
Copy pathregistration_scaling.py
File metadata and controls
69 lines (53 loc) · 2.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#!/usr/bin/env python3
"""Registration time vs. native chunk count (issue #174).
`read_xarray_table` used to create one scan partition per native xarray chunk,
making registration O(num_chunks): ~25 us/partition, so a finely chunked store
(e.g. a GOES-16 variable with ~59M native chunks) took tens of minutes just to
register, if it finished at all.
Native chunks are now coalesced into at most `target_partitions` scan
partitions, so registration cost is bounded regardless of how finely the store
is chunked. This script registers a synthetic dataset at a range of native
chunk counts and prints registration time with coalescing on (bounded) vs. off
(`target_partitions=None`, the historical O(num_chunks) behavior).
No network or large memory needed: the dataset is tiny per-chunk; only the
*number* of chunks grows, which is exactly what drives registration cost.
Run: python perf_tests/registration_scaling.py
"""
import time
import numpy as np
import pandas as pd
import xarray as xr
import xarray_sql as xql
from xarray_sql.df import DEFAULT_TARGET_PARTITIONS
def make_dataset(n_time_chunks: int) -> xr.Dataset:
"""A (time, lat, lon) dataset with `n_time_chunks` native time chunks."""
time_coord = pd.date_range("2000-01-01", periods=n_time_chunks, freq="h")
lat = np.linspace(-90, 90, 4)
lon = np.linspace(-180, 180, 4)
data = np.zeros((n_time_chunks, 4, 4), dtype="float32")
ds = xr.Dataset(
{"v": (["time", "lat", "lon"], data)},
coords={"time": time_coord, "lat": lat, "lon": lon},
)
# One native chunk per time step -> n_time_chunks native partitions.
return ds.chunk({"time": 1, "lat": 4, "lon": 4})
def time_registration(ds: xr.Dataset, target_partitions) -> float:
t0 = time.perf_counter()
xql.read_xarray_table(ds, target_partitions=target_partitions)
return time.perf_counter() - t0
def main() -> None:
print(
f"{'native chunks':>14} {'coalesced (s)':>14} {'uncoalesced (s)':>16}"
)
print("-" * 48)
for n in (1_000, 10_000, 100_000, 1_000_000):
ds = make_dataset(n)
coalesced = time_registration(ds, DEFAULT_TARGET_PARTITIONS)
uncoalesced = time_registration(ds, None)
print(f"{n:>14,} {coalesced:>14.3f} {uncoalesced:>16.3f}")
print(
"\nCoalesced registration stays flat (bounded by target_partitions); "
"uncoalesced grows linearly with the native chunk count."
)
if __name__ == "__main__":
main()