Skip to content

Commit f3da892

Browse files
Iteration 260: 7 new benchmark pairs (613 total, +7 vs best 606)
Added benchmark pairs for toTimedelta conversion, toDateInput utility, Timedelta arithmetic (add/subtract/abs/scale), Timedelta property getters, Timedelta toString/formatTimedelta, IntervalIndex.indexOf/overlapping, and Interval closed-type variants. Run: https://github.com/githubnext/tsessebe/actions/runs/24680514348
1 parent 47f83d2 commit f3da892

14 files changed

Lines changed: 725 additions & 0 deletions
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""
2+
Benchmark: Interval closed types — both, neither, left, right endpoint variants.
3+
Tests pandas Interval properties with all 4 closed types.
4+
Outputs JSON: {"function": "interval_closed_types", "mean_ms": ..., "iterations": ..., "total_ms": ...}
5+
"""
6+
import json
7+
import time
8+
import pandas as pd
9+
10+
WARMUP = 5
11+
ITERATIONS = 100
12+
SIZE = 1_000
13+
14+
closed_types = ["both", "neither", "left", "right"]
15+
all_intervals = []
16+
for closed in closed_types:
17+
for i in range(SIZE // 4):
18+
all_intervals.append(pd.Interval(i, i + 1, closed=closed))
19+
20+
ref = pd.Interval(0, 1, closed="right")
21+
22+
for _ in range(WARMUP):
23+
for iv in all_intervals[:50]:
24+
_ = iv.closed
25+
_ = iv.mid
26+
_ = iv.length
27+
_ = (0.5 + all_intervals.index(iv) % (SIZE // 4)) in iv
28+
29+
times = []
30+
for _ in range(ITERATIONS):
31+
t0 = time.perf_counter()
32+
for iv in all_intervals:
33+
_ = iv.closed
34+
_ = iv.mid
35+
_ = iv.length
36+
times.append((time.perf_counter() - t0) * 1000)
37+
38+
total = sum(times)
39+
print(json.dumps({
40+
"function": "interval_closed_types",
41+
"mean_ms": round(total / ITERATIONS, 3),
42+
"iterations": ITERATIONS,
43+
"total_ms": round(total, 3),
44+
}))
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
Benchmark: IntervalIndex.get_indexer / IntervalIndex.overlaps — interval lookup and overlap queries.
3+
Mirrors tsb IntervalIndex.indexOf / IntervalIndex.overlapping methods.
4+
Outputs JSON: {"function": "interval_index_query", "mean_ms": ..., "iterations": ..., "total_ms": ...}
5+
"""
6+
import json
7+
import time
8+
import pandas as pd
9+
import numpy as np
10+
11+
WARMUP = 5
12+
ITERATIONS = 50
13+
14+
BREAKS = 501
15+
breaks = [i * 2 for i in range(BREAKS)]
16+
idx = pd.IntervalIndex.from_breaks(breaks)
17+
18+
queries = [i * 0.999 for i in range(1_000)]
19+
query_interval = pd.Interval(200, 400)
20+
21+
for _ in range(WARMUP):
22+
idx.get_indexer(queries[:50])
23+
idx.overlaps(query_interval)
24+
25+
times = []
26+
for _ in range(ITERATIONS):
27+
t0 = time.perf_counter()
28+
idx.get_indexer(queries)
29+
idx.overlaps(query_interval)
30+
times.append((time.perf_counter() - t0) * 1000)
31+
32+
total = sum(times)
33+
print(json.dumps({
34+
"function": "interval_index_query",
35+
"mean_ms": round(total / ITERATIONS, 3),
36+
"iterations": ITERATIONS,
37+
"total_ms": round(total, 3),
38+
}))
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""
2+
Benchmark: pandas Timedelta add/sub/abs — basic Timedelta arithmetic.
3+
Mirrors tsb bench_timedelta_arithmetic_fn.ts.
4+
Outputs JSON: {"function": "timedelta_arithmetic_fn", "mean_ms": ..., "iterations": ..., "total_ms": ...}
5+
"""
6+
import json
7+
import time
8+
import pandas as pd
9+
10+
WARMUP = 5
11+
ITERATIONS = 100
12+
13+
SIZE = 1_000
14+
td1 = pd.Timedelta(days=1, hours=6)
15+
td2 = pd.Timedelta(hours=2, minutes=30)
16+
ms_value = 7_200_000 # 2 hours in ms
17+
18+
deltas = [pd.Timedelta(milliseconds=(i - SIZE // 2) * 60_000) for i in range(SIZE)]
19+
20+
for _ in range(WARMUP):
21+
pd.Timedelta(milliseconds=ms_value)
22+
for td in deltas[:50]:
23+
td + td1
24+
td - td2
25+
abs(td)
26+
27+
times = []
28+
for _ in range(ITERATIONS):
29+
t0 = time.perf_counter()
30+
pd.Timedelta(milliseconds=ms_value)
31+
for td in deltas:
32+
td + td1
33+
td - td2
34+
abs(td)
35+
times.append((time.perf_counter() - t0) * 1000)
36+
37+
total_ms = sum(times)
38+
print(json.dumps({
39+
"function": "timedelta_arithmetic_fn",
40+
"mean_ms": round(total_ms / ITERATIONS, 3),
41+
"iterations": ITERATIONS,
42+
"total_ms": round(total_ms, 3),
43+
}))
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""
2+
Benchmark: Timedelta property getters — days, hours, minutes, seconds, microseconds, nanoseconds.
3+
Mirrors tsb Timedelta property accessors.
4+
Outputs JSON: {"function": "timedelta_props", "mean_ms": ..., "iterations": ..., "total_ms": ...}
5+
"""
6+
import json
7+
import time
8+
import pandas as pd
9+
import numpy as np
10+
11+
WARMUP = 5
12+
ITERATIONS = 100
13+
SIZE = 2_000
14+
15+
deltas = [pd.Timedelta(milliseconds=(i - SIZE // 2) * 3_661) for i in range(SIZE)]
16+
17+
for _ in range(WARMUP):
18+
for td in deltas[:100]:
19+
_ = td.days
20+
_ = td.seconds
21+
_ = td.microseconds
22+
_ = td.nanoseconds
23+
_ = td.total_seconds()
24+
_ = td.components
25+
26+
times = []
27+
for _ in range(ITERATIONS):
28+
t0 = time.perf_counter()
29+
for td in deltas:
30+
_ = td.days
31+
_ = td.seconds
32+
_ = td.microseconds
33+
_ = td.nanoseconds
34+
_ = td.total_seconds()
35+
_ = td.components
36+
times.append((time.perf_counter() - t0) * 1000)
37+
38+
total = sum(times)
39+
print(json.dumps({
40+
"function": "timedelta_props",
41+
"mean_ms": round(total / ITERATIONS, 3),
42+
"iterations": ITERATIONS,
43+
"total_ms": round(total, 3),
44+
}))
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""
2+
Benchmark: Timedelta.__str__() — formatting durations as strings.
3+
Mirrors tsb Timedelta.toString() / formatTimedelta().
4+
Outputs JSON: {"function": "timedelta_tostring", "mean_ms": ..., "iterations": ..., "total_ms": ...}
5+
"""
6+
import json
7+
import time
8+
import pandas as pd
9+
10+
WARMUP = 5
11+
ITERATIONS = 100
12+
SIZE = 1_000
13+
14+
deltas = [pd.Timedelta(milliseconds=(i - SIZE // 2) * 7_778) for i in range(SIZE)]
15+
16+
for _ in range(WARMUP):
17+
for td in deltas[:50]:
18+
str(td)
19+
20+
times = []
21+
for _ in range(ITERATIONS):
22+
t0 = time.perf_counter()
23+
for td in deltas:
24+
str(td)
25+
times.append((time.perf_counter() - t0) * 1000)
26+
27+
total = sum(times)
28+
print(json.dumps({
29+
"function": "timedelta_tostring",
30+
"mean_ms": round(total / ITERATIONS, 3),
31+
"iterations": ITERATIONS,
32+
"total_ms": round(total, 3),
33+
}))
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""
2+
Benchmark: pandas pd.Timestamp() — convert ISO strings, timestamps, and datetime objects to Timestamp.
3+
Mirrors tsb bench_to_date_input.ts (toDateInput).
4+
Outputs JSON: {"function": "to_date_input", "mean_ms": ..., "iterations": ..., "total_ms": ...}
5+
"""
6+
import json
7+
import time
8+
from datetime import datetime
9+
import pandas as pd
10+
11+
WARMUP = 5
12+
ITERATIONS = 50
13+
14+
iso_strings = [
15+
"2020-01-01",
16+
"2024-03-15T10:30:00Z",
17+
"2023-12-31T23:59:59.999Z",
18+
"2022-07-04",
19+
"2021-01-01T00:00:00",
20+
]
21+
22+
# millisecond timestamps
23+
timestamps = [
24+
0,
25+
1_577_836_800_000,
26+
1_704_067_200_000,
27+
1_609_459_200_000,
28+
1_672_531_200_000,
29+
]
30+
31+
date_objects = [
32+
datetime(2020, 1, 1),
33+
datetime(2024, 6, 15),
34+
datetime(2001, 9, 9, 1, 46, 40),
35+
]
36+
37+
SIZE = 10_000
38+
str_batch = [
39+
f"{2000 + (i % 25)}-{((i % 12) + 1):02d}-{((i % 28) + 1):02d}"
40+
for i in range(SIZE)
41+
]
42+
num_batch = [i * 86_400_000 for i in range(SIZE)]
43+
44+
for _ in range(WARMUP):
45+
for s in iso_strings:
46+
pd.Timestamp(s)
47+
for t in timestamps:
48+
pd.Timestamp(t, unit="ms")
49+
for d in date_objects:
50+
pd.Timestamp(d)
51+
52+
times = []
53+
for _ in range(ITERATIONS):
54+
t0 = time.perf_counter()
55+
for _ in range(1000):
56+
for s in iso_strings:
57+
pd.Timestamp(s)
58+
for t in timestamps:
59+
pd.Timestamp(t, unit="ms")
60+
for d in date_objects:
61+
pd.Timestamp(d)
62+
for s in str_batch:
63+
pd.Timestamp(s)
64+
for t in num_batch:
65+
pd.Timestamp(t, unit="ms")
66+
times.append((time.perf_counter() - t0) * 1000)
67+
68+
total_ms = sum(times)
69+
print(json.dumps({
70+
"function": "to_date_input",
71+
"mean_ms": round(total_ms / ITERATIONS, 3),
72+
"iterations": ITERATIONS,
73+
"total_ms": round(total_ms, 3),
74+
}))
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""
2+
Benchmark: pandas pd.to_timedelta() — convert strings, numbers, and arrays to timedelta.
3+
Mirrors tsb bench_to_timedelta_convert.ts.
4+
Outputs JSON: {"function": "to_timedelta_convert", "mean_ms": ..., "iterations": ..., "total_ms": ...}
5+
"""
6+
import json
7+
import time
8+
import pandas as pd
9+
10+
WARMUP = 5
11+
ITERATIONS = 50
12+
13+
strings = [
14+
"1 days 02:03:04",
15+
"0 days 00:30:00",
16+
"5 days 12:00:00.500",
17+
"PT1H30M",
18+
"P7D",
19+
"-PT2H45M30S",
20+
"2h 30m 15s",
21+
"1 day 00:00:00",
22+
]
23+
24+
numbers = [86400, 3600, 1800, 7200, 0, -3600]
25+
26+
SIZE = 1_000
27+
str_array = [f"{i % 100} days {(i % 24):02d}:00:00" for i in range(SIZE)]
28+
num_array = [i * 3600 for i in range(SIZE)]
29+
30+
for _ in range(WARMUP):
31+
for s in strings:
32+
pd.to_timedelta(s)
33+
for n in numbers:
34+
pd.to_timedelta(n, unit="s")
35+
pd.to_timedelta(str_array)
36+
pd.to_timedelta(num_array, unit="s")
37+
38+
times = []
39+
for _ in range(ITERATIONS):
40+
t0 = time.perf_counter()
41+
for _ in range(100):
42+
for s in strings:
43+
pd.to_timedelta(s)
44+
for n in numbers:
45+
pd.to_timedelta(n, unit="s")
46+
pd.to_timedelta(str_array)
47+
pd.to_timedelta(num_array, unit="s")
48+
times.append((time.perf_counter() - t0) * 1000)
49+
50+
total_ms = sum(times)
51+
print(json.dumps({
52+
"function": "to_timedelta_convert",
53+
"mean_ms": round(total_ms / ITERATIONS, 3),
54+
"iterations": ITERATIONS,
55+
"total_ms": round(total_ms, 3),
56+
}))
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* Benchmark: Interval closed types — both, neither, left, right endpoint variants.
3+
* Tests closedLeft, closedRight, isOpen, isClosed, equals, and contains with all 4 closed types.
4+
* Outputs JSON: {"function": "interval_closed_types", "mean_ms": ..., "iterations": ..., "total_ms": ...}
5+
*/
6+
import { Interval } from "../../src/index.ts";
7+
8+
const WARMUP = 5;
9+
const ITERATIONS = 100;
10+
11+
const SIZE = 1_000;
12+
const closedTypes = ["both", "neither", "left", "right"] as const;
13+
14+
const intervalSets = closedTypes.map((closed) =>
15+
Array.from({ length: SIZE / 4 }, (_, i) => new Interval(i, i + 1, closed)),
16+
);
17+
const all = intervalSets.flat();
18+
const ref = new Interval(0, 1, "right");
19+
20+
for (let w = 0; w < WARMUP; w++) {
21+
for (const iv of all.slice(0, 50)) {
22+
void iv.closedLeft;
23+
void iv.closedRight;
24+
void iv.isOpen;
25+
void iv.isClosed;
26+
void iv.mid;
27+
iv.contains(iv.mid);
28+
iv.equals(ref);
29+
}
30+
}
31+
32+
const times: number[] = [];
33+
for (let i = 0; i < ITERATIONS; i++) {
34+
const t0 = performance.now();
35+
for (const iv of all) {
36+
void iv.closedLeft;
37+
void iv.closedRight;
38+
void iv.isOpen;
39+
void iv.isClosed;
40+
void iv.mid;
41+
iv.contains(iv.mid);
42+
iv.equals(ref);
43+
}
44+
times.push(performance.now() - t0);
45+
}
46+
47+
const total = times.reduce((a, b) => a + b, 0);
48+
console.log(
49+
JSON.stringify({
50+
function: "interval_closed_types",
51+
mean_ms: round3(total / ITERATIONS),
52+
iterations: ITERATIONS,
53+
total_ms: round3(total),
54+
}),
55+
);
56+
57+
function round3(v: number): number {
58+
return Math.round(v * 1000) / 1000;
59+
}

0 commit comments

Comments
 (0)