Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5934d0a
feat(wasm): add missing core exports to coverage manifest and audit a…
github-actions[bot] Jul 2, 2026
9ba5624
ci: trigger checks
github-actions[bot] Jul 2, 2026
a303d08
chore(wasm): update benchmark results from Run 4 verification
github-actions[bot] Jul 2, 2026
041f89f
ci: trigger checks
github-actions[bot] Jul 2, 2026
bc4c7a7
feat(wasm): add method-level coverage manifest + scalar/rolling Rust …
github-actions[bot] Jul 2, 2026
69841b1
ci: trigger checks
github-actions[bot] Jul 2, 2026
7d992f4
fix: resolve lint errors in series.ts (complexity + noNonNullAssertion)
github-actions[bot] Jul 5, 2026
d5058c0
ci: trigger checks
github-actions[bot] Jul 5, 2026
1cd2c8a
fix: resolve noUncheckedIndexedAccess errors in radix sort (series.ts)
github-actions[bot] Jul 7, 2026
2c41d31
ci: trigger checks
github-actions[bot] Jul 7, 2026
3d360bc
fix: resolve biome format errors in accelerated.ts and wasm-coverage.…
github-actions[bot] Jul 9, 2026
1a5e00c
ci: trigger checks
github-actions[bot] Jul 9, 2026
5612dec
fix(series): use bracket notation for index-signature properties (TS4…
github-actions[bot] Jul 9, 2026
384a36d
ci: trigger checks
github-actions[bot] Jul 9, 2026
3f8d5bc
fix: resolve Biome lint errors in series.ts and frame.ts
github-actions[bot] Jul 10, 2026
fb488e9
ci: trigger checks
github-actions[bot] Jul 10, 2026
8238b6d
fix(typecheck): use bracket notation for index signature access (TS4111)
github-actions[bot] Jul 10, 2026
c973976
ci: trigger checks
github-actions[bot] Jul 10, 2026
7d62585
fix(lint): add explicit return types to iterator next() methods
github-actions[bot] Jul 10, 2026
47efeac
ci: trigger checks
github-actions[bot] Jul 10, 2026
2f9c3a3
fix: resolve Biome lint errors in series.ts and to_from_dict.ts
github-actions[bot] Jul 10, 2026
5cdb3ed
ci: trigger checks
github-actions[bot] Jul 10, 2026
5c80424
fix(series): use bracket notation for index-signature properties
github-actions[bot] Jul 10, 2026
ea22389
ci: trigger checks
github-actions[bot] Jul 10, 2026
e9f7ad2
Extract index-oriented dict builder
mrjf Jul 10, 2026
584d806
Merge branch 'main' into goal/349-goal-add-rust-wasm-acceleration-cov…
github-actions[bot] Jul 10, 2026
a051143
fix: clear Biome lint errors in frame, options, series, timestamp
github-actions[bot] Jul 10, 2026
dc7e137
ci: trigger checks
github-actions[bot] Jul 10, 2026
79eeb25
fix: use bracket notation for index-signature properties (TS4111)
github-actions[bot] Jul 10, 2026
feeb297
ci: trigger checks
github-actions[bot] Jul 10, 2026
cf80ebf
fix: apply Biome formatter to series.ts, accelerated.ts, parity.test.ts
github-actions[bot] Jul 10, 2026
85a42b3
ci: trigger checks
github-actions[bot] Jul 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 50 additions & 50 deletions benchmarks/results-wasm-core.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,160 +3,160 @@
{
"function": "searchsorted_f64",
"tsb": {
"mean_ms": 0.0008374999999999986,
"mean_ms": 0.0016710259999999978,
"iterations": 1000,
"total_ms": 0.8374999999999986
"total_ms": 1.6710259999999977
},
"tsb_wasm": {
"mean_ms": 0.0021370410000000036,
"mean_ms": 0.028031712999999996,
"iterations": 1000,
"total_ms": 2.1370410000000035
"total_ms": 28.031712999999996
},
"wasm_speedup": 0.39189702022562845
"wasm_speedup": 0.05961198304220645
},
{
"function": "searchsorted_many_f64",
"tsb": {
"mean_ms": 0.0034607080000000037,
"mean_ms": 0.003219333999999989,
"iterations": 1000,
"total_ms": 3.460708000000004
"total_ms": 3.2193339999999893
},
"tsb_wasm": {
"mean_ms": 0.005887209000000006,
"mean_ms": 0.034363152,
"iterations": 1000,
"total_ms": 5.887209000000006
"total_ms": 34.363152
},
"wasm_speedup": 0.5878350845026905
"wasm_speedup": 0.09368564327277047
},
{
"function": "argsort_f64",
"tsb": {
"mean_ms": 0.1133425,
"mean_ms": 0.21699383,
"iterations": 1000,
"total_ms": 113.3425
"total_ms": 216.99383
},
"tsb_wasm": {
"mean_ms": 0.01931533300000001,
"mean_ms": 0.057585872999999996,
"iterations": 1000,
"total_ms": 19.31533300000001
"total_ms": 57.58587299999999
},
"wasm_speedup": 5.8680065210369365
"wasm_speedup": 3.768178178005568
},
{
"function": "searchsorted_str",
"tsb": {
"mean_ms": 0.00027391700000001153,
"mean_ms": 0.0009189930000000004,
"iterations": 1000,
"total_ms": 0.2739170000000115
"total_ms": 0.9189930000000004
},
"tsb_wasm": {
"mean_ms": 0.002622792000000004,
"mean_ms": 0.007566859999999963,
"iterations": 1000,
"total_ms": 2.622792000000004
"total_ms": 7.566859999999963
},
"wasm_speedup": 0.10443717992124847,
"wasm_speedup": 0.12144971626275694,
"notes": "String arrays are copied for each WASM call; raw kernel speedup is partially offset by copy overhead."
},
{
"function": "argsort_str",
"tsb": {
"mean_ms": 0.0004121250000000032,
"mean_ms": 0.002078239999999994,
"iterations": 1000,
"total_ms": 0.4121250000000032
"total_ms": 2.078239999999994
},
"tsb_wasm": {
"mean_ms": 0.0014684579999999982,
"mean_ms": 0.004294708000000014,
"iterations": 1000,
"total_ms": 1.4684579999999983
"total_ms": 4.294708000000014
},
"wasm_speedup": 0.28065154059564773,
"wasm_speedup": 0.4839071713373731,
"notes": "Same array-copy caveat as searchsorted_str."
},
{
"function": "nat_compare",
"tsb": {
"mean_ms": 0.0004783749999999998,
"mean_ms": 0.0010837179999999762,
"iterations": 1000,
"total_ms": 0.4783749999999998
"total_ms": 1.0837179999999762
},
"tsb_wasm": {
"mean_ms": 0.001035334000000006,
"mean_ms": 0.004259321,
"iterations": 1000,
"total_ms": 1.035334000000006
"total_ms": 4.259321
},
"wasm_speedup": 0.4620489619774846
"wasm_speedup": 0.25443445093712735
},
{
"function": "nat_sorted",
"tsb": {
"mean_ms": 0.16902662499999996,
"mean_ms": 0.226383055,
"iterations": 1000,
"total_ms": 169.02662499999997
"total_ms": 226.383055
},
"tsb_wasm": {
"mean_ms": 0.257211584,
"mean_ms": 0.5151697199999998,
"iterations": 1000,
"total_ms": 257.211584
"total_ms": 515.1697199999999
},
"wasm_speedup": 0.6571501266443737
"wasm_speedup": 0.4394339306277552
},
{
"function": "nat_argsort",
"tsb": {
"mean_ms": 0.03192166599999996,
"mean_ms": 0.05495564300000001,
"iterations": 1000,
"total_ms": 31.92166599999996
"total_ms": 54.95564300000001
},
"tsb_wasm": {
"mean_ms": 0.035225500000000014,
"mean_ms": 0.06736009400000012,
"iterations": 1000,
"total_ms": 35.22550000000001
"total_ms": 67.36009400000012
},
"wasm_speedup": 0.9062090247122099
"wasm_speedup": 0.815848668500966
}
],
"coverage": {
"unclassified": 0,
"eligible_missing": 0,
"total_core_entries": 121,
"total_core_entries": 143,
"rust_wasm": 6,
"ts_only_ineligible": 115
"ts_only_ineligible": 137
},
"timestamp": "2026-06-27T02:33:54.386Z",
"timestamp": "2026-07-02T09:46:21.112Z",
"slower_than_typescript": [
{
"function": "searchsorted_f64",
"wasm_speedup": 0.39189702022562845,
"wasm_speedup": 0.05961198304220645,
"explanation": "WASM/JS boundary overhead exceeds kernel speedup at this array size."
},
{
"function": "searchsorted_many_f64",
"wasm_speedup": 0.5878350845026905,
"wasm_speedup": 0.09368564327277047,
"explanation": "WASM/JS boundary overhead exceeds kernel speedup at this array size."
},
{
"function": "searchsorted_str",
"wasm_speedup": 0.10443717992124847,
"wasm_speedup": 0.12144971626275694,
"explanation": "String arrays are copied for each WASM call; raw kernel speedup is partially offset by copy overhead."
},
{
"function": "argsort_str",
"wasm_speedup": 0.28065154059564773,
"wasm_speedup": 0.4839071713373731,
"explanation": "Same array-copy caveat as searchsorted_str."
},
{
"function": "nat_compare",
"wasm_speedup": 0.4620489619774846,
"wasm_speedup": 0.25443445093712735,
"explanation": "WASM/JS boundary overhead exceeds kernel speedup at this array size."
},
{
"function": "nat_sorted",
"wasm_speedup": 0.6571501266443737,
"wasm_speedup": 0.4394339306277552,
"explanation": "WASM/JS boundary overhead exceeds kernel speedup at this array size."
},
{
"function": "nat_argsort",
"wasm_speedup": 0.9062090247122099,
"wasm_speedup": 0.815848668500966,
"explanation": "WASM/JS boundary overhead exceeds kernel speedup at this array size."
}
]
Expand Down
43 changes: 43 additions & 0 deletions benchmarks/wasm-core/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,49 @@ const benchmarks: BenchmarkEntry[] = [];
});
}

// ─── sum_f64 ──────────────────────────────────────────────────────────────────

{
const sumF64Wasm = getWasmFn("sum_f64");
const DATA_F64 = Float64Array.from({ length: 10_000 }, (_, i) => i * 0.5);
const DATA_ARR = Array.from(DATA_F64);
const tsResult = bench(() => DATA_ARR.reduce((acc, v) => acc + v, 0), ITERS);
const wasmResult = bench(() => sumF64Wasm(DATA_F64), ITERS);
benchmarks.push({
function: "sum_f64",
tsb: tsResult,
tsb_wasm: wasmResult,
wasm_speedup: tsResult.mean_ms / wasmResult.mean_ms,
notes: "Scalar sum over 10 000-element f64 array; WASM avoids JS→TS dispatch overhead.",
});
}

// ─── rolling_mean_f64 ────────────────────────────────────────────────────────

{
const rollingMeanWasm = getWasmFn("rolling_mean_f64");
const ROLL_DATA = Float64Array.from({ length: 1_000 }, (_, i) => i * 1.0);
const ROLL_ARR = Array.from(ROLL_DATA);
const window = 10;
const minPeriods = 10;
const tsResult = bench(() => {
return ROLL_ARR.map((_, i) => {
const start = Math.max(0, i + 1 - window);
const slice = ROLL_ARR.slice(start, i + 1).filter((v) => !Number.isNaN(v));
if (slice.length < minPeriods) return null;
return slice.reduce((a, b) => a + b, 0) / slice.length;
});
}, ITERS);
const wasmResult = bench(() => rollingMeanWasm(ROLL_DATA, window, minPeriods), ITERS);
benchmarks.push({
function: "rolling_mean_f64",
tsb: tsResult,
tsb_wasm: wasmResult,
wasm_speedup: tsResult.mean_ms / wasmResult.mean_ms,
notes: "Rolling window mean over 1 000 elements with window=10.",
});
}

// ─── coverage summary ─────────────────────────────────────────────────────────

const coverageManifest = JSON.parse(
Expand Down
115 changes: 115 additions & 0 deletions rust/pkg/tsb_wasm.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,66 @@ export function argsort_f64(arr: Float64Array): Uint32Array;
*/
export function argsort_str(arr: string[]): Uint32Array;

/**
* Expanding maximum.
*/
export function expanding_max_f64(data: Float64Array, min_periods: number): Float64Array;

/**
* Expanding mean.
*/
export function expanding_mean_f64(data: Float64Array, min_periods: number): Float64Array;

/**
* Expanding median.
*/
export function expanding_median_f64(data: Float64Array, min_periods: number): Float64Array;

/**
* Expanding minimum.
*/
export function expanding_min_f64(data: Float64Array, min_periods: number): Float64Array;

/**
* Expanding standard deviation (delta degrees-of-freedom `ddof`).
*/
export function expanding_std_f64(data: Float64Array, min_periods: number, ddof: number): Float64Array;

/**
* Expanding sum.
*/
export function expanding_sum_f64(data: Float64Array, min_periods: number): Float64Array;

/**
* Expanding variance (delta degrees-of-freedom `ddof`).
*/
export function expanding_var_f64(data: Float64Array, min_periods: number, ddof: number): Float64Array;

/**
* Maximum of non-NaN values. Returns `NaN` for empty / all-NaN input.
*/
export function max_f64(data: Float64Array): number;

/**
* Arithmetic mean of non-NaN values. Returns `NaN` for empty / all-NaN input,
* matching `Series.mean()`.
*/
export function mean_f64(data: Float64Array): number;

/**
* Median of non-NaN values (middle value of sorted data; average of two
* middle values for even-length arrays). Returns `NaN` for empty / all-NaN
* input, matching `Series.median()`.
*/
export function median_f64(data: Float64Array): number;

/**
* Minimum of non-NaN values. Returns `NaN` for empty / all-NaN input,
* matching `Series.min()` returning `undefined` (coerced to NaN in numeric
* contexts).
*/
export function min_f64(data: Float64Array): number;

/**
* Return the indices that would sort `arr` in natural order.
*/
Expand All @@ -38,6 +98,42 @@ export function nat_compare(a: string, b: string, ignore_case: boolean, reverse:
*/
export function nat_sorted(arr: string[], ignore_case: boolean, reverse: boolean): string[];

/**
* Rolling maximum.
*/
export function rolling_max_f64(data: Float64Array, window: number, min_periods: number): Float64Array;

/**
* Rolling arithmetic mean.
*/
export function rolling_mean_f64(data: Float64Array, window: number, min_periods: number): Float64Array;

/**
* Rolling median.
*/
export function rolling_median_f64(data: Float64Array, window: number, min_periods: number): Float64Array;

/**
* Rolling minimum.
*/
export function rolling_min_f64(data: Float64Array, window: number, min_periods: number): Float64Array;

/**
* Rolling standard deviation (delta degrees-of-freedom `ddof`).
*/
export function rolling_std_f64(data: Float64Array, window: number, min_periods: number, ddof: number): Float64Array;

/**
* Rolling sum. Positions with fewer than `min_periods` non-NaN values → NaN.
*/
export function rolling_sum_f64(data: Float64Array, window: number, min_periods: number): Float64Array;

/**
* Rolling variance (delta degrees-of-freedom `ddof`).
* Positions with fewer than `ddof + 1` valid values → NaN.
*/
export function rolling_var_f64(data: Float64Array, window: number, min_periods: number, ddof: number): Float64Array;

/**
* Binary-search a sorted f64 slice for `value`.
*
Expand Down Expand Up @@ -65,3 +161,22 @@ export function searchsorted_many_str(arr: string[], values: string[], side_righ
* Binary-search a sorted array of strings for `value`.
*/
export function searchsorted_str(arr: string[], value: string, side_right: boolean): number;

/**
* Sample standard deviation with delta degrees-of-freedom `ddof`.
* Returns `NaN` when fewer than `ddof + 1` valid values exist.
*/
export function std_f64(data: Float64Array, ddof: number): number;

/**
* Sum of non-NaN values. Returns `0.0` when there are no valid values,
* matching `Series.sum()` on an all-null / empty series.
*/
export function sum_f64(data: Float64Array): number;

/**
* Sample variance of non-NaN values with delta degrees-of-freedom `ddof`.
* Returns `NaN` when fewer than `ddof + 1` valid values exist, matching
* `Series.var(ddof)`.
*/
export function var_f64(data: Float64Array, ddof: number): number;
Loading
Loading