Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
875d45c
das_hash_map: add insert-only variants, switch Module fields, add has…
borisbat May 19, 2026
11566a1
das_hash_map: guard insert-only overloads under DAS_CUSTOM_HASH=0; bu…
borisbat May 19, 2026
4bdebc8
Merge pull request #2722 from GaijinEntertainment/claude/determined-t…
borisbat May 19, 2026
4299eba
mouse-data: cache PR #2721 splice patterns
borisbat May 19, 2026
13f239e
linq_fold group_by: inner-select-sum splice — closes deferred follow-…
borisbat May 19, 2026
8d58e6a
Merge pull request #2723 from GaijinEntertainment/bbatkin/linq-fold-i…
borisbat May 19, 2026
95c531d
linq_fold group_by: min/max/first reducers + multi-reducer fused pass
borisbat May 19, 2026
354803c
linq_fold group_by: benchmarks + LINQ.md doc refresh for min/max/firs…
borisbat May 19, 2026
dd85a67
Merge pull request #2724 from GaijinEntertainment/bbatkin/linq-fold-m…
borisbat May 19, 2026
7c599b9
linq_fold group_by: fuse upstream where_/select* into per-element loop
borisbat May 19, 2026
26ebee5
linq_fold group_by: benchmarks + LINQ.md doc refresh for upstream whe…
borisbat May 19, 2026
72fc82f
linq_fold group_by: emit upstream selects lazily (after each where gu…
borisbat May 19, 2026
7856fb8
daslang-live: --live-port + port-keyed lock + .das resolution chain
borisbat May 19, 2026
723642e
address PR review: strict port parse, --live-port=N form, MCP digit-o…
borisbat May 19, 2026
47303d2
Merge pull request #2725 from GaijinEntertainment/bbatkin/linq-fold-g…
borisbat May 19, 2026
7b38c34
tests/aot: register live_api.das as AOT module-file
borisbat May 19, 2026
843cdf2
linq_fold group_by: splice _having between group_by_lazy and select
borisbat May 19, 2026
8156634
linq_fold group_by: safety scan for unhandled having predicate shapes
borisbat May 19, 2026
cf58023
stateless port resolution + RST audit (review round 2)
borisbat May 19, 2026
7ea1498
address review round 3: last-occurrence-wins symmetric on invalid input
borisbat May 19, 2026
9866534
Merge pull request #2727 from GaijinEntertainment/bbatkin/linq-fold-g…
borisbat May 19, 2026
e1a9289
linq_fold group_by: average reducer + inner-select-average + multi-re…
borisbat May 19, 2026
48c97a6
linq_fold group_by: benchmark + LINQ.md doc refresh for average reducer
borisbat May 19, 2026
4be2b0c
linq_fold group_by: handle positional tuple in avg result-build synth…
borisbat May 19, 2026
f0c826f
Merge pull request #2726 from GaijinEntertainment/claude/recursing-co…
borisbat May 19, 2026
55bd15d
Merge pull request #2728 from GaijinEntertainment/bbatkin/linq-fold-g…
borisbat May 19, 2026
9dd8936
linq_fold reverse: backward index loop for reverse |> take(N) on arra…
borisbat May 19, 2026
d611d0e
linq_fold reverse: LINQ.md refresh for backward index loop (PR-C)
borisbat May 19, 2026
bee9c0d
linq_fold reverse: address Copilot review on PR #2729
borisbat May 19, 2026
832b719
Merge pull request #2729 from GaijinEntertainment/bbatkin/linq-fold-r…
borisbat May 19, 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
224 changes: 216 additions & 8 deletions benchmarks/sql/LINQ.md

Large diffs are not rendered by default.

63 changes: 63 additions & 0 deletions benchmarks/sql/groupby_average.das
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
options gen2
options persistent_heap

require _common public

// _group_by(_.brand) |> _select((Brand=key, AvgPrice=avg of price per group)).
// SQL: SELECT brand, AVG(price) GROUP BY brand.
// Splice mode (PR-A2 follow-up) fuses the inner select+average per group via a
// 2-slot per-key acc (sum : double + count : uint64) and divides at result-build.

def run_m1(b : B?; n : int) {
with_sqlite(":memory:") $(db) {
fixture_db(db, n)
b |> run("m1_sql/{n}", n) {
let groups <- _sql(db |> select_from(type<Car>)
|> _group_by(_.brand)
|> _select((Brand = _._0,
AvgPrice = _._1 |> select($(c : Car) => c.price) |> average())))
if (empty(groups)) {
b->failNow()
}
}
}
}

def run_m3(b : B?; n : int) {
let arr <- fixture_array(n)
b |> run("m3_array/{n}", n) {
let groups <- (arr._group_by(_.brand)._select((Brand = _._0,
AvgPrice = _._1 |> select($(c : Car) => c.price) |> average())))
if (empty(groups)) {
b->failNow()
}
}
}
def run_m3f(b : B?; n : int) {
let arr <- fixture_array(n)
b |> run("m3f_array_fold/{n}", n) {
let groups <- _fold(each(arr)
._group_by(_.brand)
._select((Brand = _._0,
AvgPrice = _._1 |> select($(c : Car) => c.price) |> average()))
.to_array())
if (empty(groups)) {
b->failNow()
}
}
}

[benchmark]
def groupby_average_m1(b : B?) {
run_m1(b, 100000)
}

[benchmark]
def groupby_average_m3(b : B?) {
run_m3(b, 100000)
}

[benchmark]
def groupby_average_m3f(b : B?) {
run_m3f(b, 100000)
}
42 changes: 42 additions & 0 deletions benchmarks/sql/groupby_first.das
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
options gen2
options persistent_heap

require _common public

// _group_by(_.brand) |> _select((Brand=key, FirstCar=first source elem per group)).
// No direct SQL aggregator for "first source-order row per group" → m1 omitted; m3 vs m3f
// is the headline comparison. Splice (PR-A2) emits miss-branch-only loop (no hit update).

def run_m3(b : B?; n : int) {
let arr <- fixture_array(n)
b |> run("m3_array/{n}", n) {
let groups <- (arr._group_by(_.brand)._select((Brand = _._0,
FirstCar = _._1 |> first())))
if (empty(groups)) {
b->failNow()
}
}
}
def run_m3f(b : B?; n : int) {
let arr <- fixture_array(n)
b |> run("m3f_array_fold/{n}", n) {
let groups <- _fold(each(arr)
._group_by(_.brand)
._select((Brand = _._0,
FirstCar = _._1 |> first()))
.to_array())
if (empty(groups)) {
b->failNow()
}
}
}

[benchmark]
def groupby_first_m3(b : B?) {
run_m3(b, 100000)
}

[benchmark]
def groupby_first_m3f(b : B?) {
run_m3f(b, 100000)
}
64 changes: 64 additions & 0 deletions benchmarks/sql/groupby_having_count.das
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
options gen2
options persistent_heap

require _common public

// _group_by(_.brand) |> _having(_._1 |> length >= 5) |> _select((Brand=key, N=length)).
// SQL: SELECT brand, COUNT(*) FROM cars GROUP BY brand HAVING COUNT(*) >= 5.
// Splice mode (PR-D) recognizes that the having predicate's length(_._1) matches the
// select's length slot — the predicate rewrites to `kv._{slot} >= 5` and wraps the
// result-build push_clone in a per-bucket filter. Per-element loop is unchanged from
// PR-A2's count splice; the only extra cost is the post-table filter.

def run_m1(b : B?; n : int) {
with_sqlite(":memory:") $(db) {
fixture_db(db, n)
b |> run("m1_sql/{n}", n) {
let groups <- _sql(db |> select_from(type<Car>)
|> _group_by(_.brand)
|> _having(_._1 |> length >= 5)
|> _select((Brand = _._0, N = _._1 |> length)))
if (empty(groups)) {
b->failNow()
}
}
}
}

def run_m3(b : B?; n : int) {
let arr <- fixture_array(n)
b |> run("m3_array/{n}", n) {
let groups <- (arr._group_by(_.brand)._having(_._1 |> length >= 5)._select((Brand = _._0, N = _._1 |> length)))
if (empty(groups)) {
b->failNow()
}
}
}
def run_m3f(b : B?; n : int) {
let arr <- fixture_array(n)
b |> run("m3f_array_fold/{n}", n) {
let groups <- _fold(each(arr)
._group_by(_.brand)
._having(_._1 |> length >= 5)
._select((Brand = _._0, N = _._1 |> length))
.to_array())
if (empty(groups)) {
b->failNow()
}
}
}

[benchmark]
def groupby_having_count_m1(b : B?) {
run_m1(b, 100000)
}

[benchmark]
def groupby_having_count_m3(b : B?) {
run_m3(b, 100000)
}

[benchmark]
def groupby_having_count_m3f(b : B?) {
run_m3f(b, 100000)
}
63 changes: 63 additions & 0 deletions benchmarks/sql/groupby_max.das
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
options gen2
options persistent_heap

require _common public

// _group_by(_.brand) |> _select((Brand=key, MaxPrice=max of price per group)).
// SQL: SELECT brand, MAX(price) GROUP BY brand.
// Splice mode (PR-A2) fuses the inner select+max per group into the per-element
// miss/hit branches — no bucket array, single hash op per element.

def run_m1(b : B?; n : int) {
with_sqlite(":memory:") $(db) {
fixture_db(db, n)
b |> run("m1_sql/{n}", n) {
let groups <- _sql(db |> select_from(type<Car>)
|> _group_by(_.brand)
|> _select((Brand = _._0,
MaxPrice = _._1 |> select($(c : Car) => c.price) |> max())))
if (empty(groups)) {
b->failNow()
}
}
}
}

def run_m3(b : B?; n : int) {
let arr <- fixture_array(n)
b |> run("m3_array/{n}", n) {
let groups <- (arr._group_by(_.brand)._select((Brand = _._0,
MaxPrice = _._1 |> select($(c : Car) => c.price) |> max())))
if (empty(groups)) {
b->failNow()
}
}
}
def run_m3f(b : B?; n : int) {
let arr <- fixture_array(n)
b |> run("m3f_array_fold/{n}", n) {
let groups <- _fold(each(arr)
._group_by(_.brand)
._select((Brand = _._0,
MaxPrice = _._1 |> select($(c : Car) => c.price) |> max()))
.to_array())
if (empty(groups)) {
b->failNow()
}
}
}

[benchmark]
def groupby_max_m1(b : B?) {
run_m1(b, 100000)
}

[benchmark]
def groupby_max_m3(b : B?) {
run_m3(b, 100000)
}

[benchmark]
def groupby_max_m3f(b : B?) {
run_m3f(b, 100000)
}
63 changes: 63 additions & 0 deletions benchmarks/sql/groupby_min.das
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
options gen2
options persistent_heap

require _common public

// _group_by(_.brand) |> _select((Brand=key, MinPrice=min of price per group)).
// SQL: SELECT brand, MIN(price) GROUP BY brand.
// Splice mode (PR-A2) fuses the inner select+min per group into the per-element
// miss/hit branches — no bucket array, single hash op per element.

def run_m1(b : B?; n : int) {
with_sqlite(":memory:") $(db) {
fixture_db(db, n)
b |> run("m1_sql/{n}", n) {
let groups <- _sql(db |> select_from(type<Car>)
|> _group_by(_.brand)
|> _select((Brand = _._0,
MinPrice = _._1 |> select($(c : Car) => c.price) |> min())))
if (empty(groups)) {
b->failNow()
}
}
}
}

def run_m3(b : B?; n : int) {
let arr <- fixture_array(n)
b |> run("m3_array/{n}", n) {
let groups <- (arr._group_by(_.brand)._select((Brand = _._0,
MinPrice = _._1 |> select($(c : Car) => c.price) |> min())))
if (empty(groups)) {
b->failNow()
}
}
}
def run_m3f(b : B?; n : int) {
let arr <- fixture_array(n)
b |> run("m3f_array_fold/{n}", n) {
let groups <- _fold(each(arr)
._group_by(_.brand)
._select((Brand = _._0,
MinPrice = _._1 |> select($(c : Car) => c.price) |> min()))
.to_array())
if (empty(groups)) {
b->failNow()
}
}
}

[benchmark]
def groupby_min_m1(b : B?) {
run_m1(b, 100000)
}

[benchmark]
def groupby_min_m3(b : B?) {
run_m3(b, 100000)
}

[benchmark]
def groupby_min_m3f(b : B?) {
run_m3f(b, 100000)
}
69 changes: 69 additions & 0 deletions benchmarks/sql/groupby_multi_reducer.das
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
options gen2
options persistent_heap

require _common public

// _group_by(_.brand) |> _select 4-slot named tuple — fuses count + sum + max into one pass.
// SQL: SELECT brand, COUNT(*), SUM(price), MAX(price) GROUP BY brand.
// Splice (PR-A2 A.4) walks the ReducerSpec array once per source element, emitting per-slot
// miss-init + hit-update for all 3 reducers — no per-reducer separate passes.

def run_m1(b : B?; n : int) {
with_sqlite(":memory:") $(db) {
fixture_db(db, n)
b |> run("m1_sql/{n}", n) {
let groups <- _sql(db |> select_from(type<Car>)
|> _group_by(_.brand)
|> _select((Brand = _._0,
N = _._1 |> length,
TotalPrice = _._1 |> select($(c : Car) => c.price) |> sum(),
MaxPrice = _._1 |> select($(c : Car) => c.price) |> max())))
if (empty(groups)) {
b->failNow()
}
}
}
}

def run_m3(b : B?; n : int) {
let arr <- fixture_array(n)
b |> run("m3_array/{n}", n) {
let groups <- (arr._group_by(_.brand)._select((Brand = _._0,
N = _._1 |> length,
TotalPrice = _._1 |> select($(c : Car) => c.price) |> sum(),
MaxPrice = _._1 |> select($(c : Car) => c.price) |> max())))
if (empty(groups)) {
b->failNow()
}
}
}
def run_m3f(b : B?; n : int) {
let arr <- fixture_array(n)
b |> run("m3f_array_fold/{n}", n) {
let groups <- _fold(each(arr)
._group_by(_.brand)
._select((Brand = _._0,
N = _._1 |> length,
TotalPrice = _._1 |> select($(c : Car) => c.price) |> sum(),
MaxPrice = _._1 |> select($(c : Car) => c.price) |> max()))
.to_array())
if (empty(groups)) {
b->failNow()
}
}
}

[benchmark]
def groupby_multi_reducer_m1(b : B?) {
run_m1(b, 100000)
}

[benchmark]
def groupby_multi_reducer_m3(b : B?) {
run_m3(b, 100000)
}

[benchmark]
def groupby_multi_reducer_m3f(b : B?) {
run_m3f(b, 100000)
}
Loading
Loading