Skip to content

Commit 551b8dc

Browse files
authored
Merge pull request GaijinEntertainment#2712 from GaijinEntertainment/bbatkin/linq-fold-sort-family
linq_fold: retire _old_fold; 3-tier cascade; order-family + select+where splice
2 parents ced9f51 + 1924fd8 commit 551b8dc

40 files changed

Lines changed: 1085 additions & 1251 deletions

benchmarks/sql/LINQ.md

Lines changed: 81 additions & 56 deletions
Large diffs are not rendered by default.

benchmarks/sql/all_match.das

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,6 @@ def run_m3(b : B?; n : int) {
3030
}
3131
}
3232
}
33-
34-
def run_m3f_old(b : B?; n : int) {
35-
let arr <- fixture_array(n)
36-
b |> run("m3f_old_array_fold/{n}", n) {
37-
let yes = _old_fold(each(arr)._all(_.price < 9999))
38-
if (!yes) {
39-
b->failNow()
40-
}
41-
}
42-
}
43-
4433
def run_m3f(b : B?; n : int) {
4534
let arr <- fixture_array(n)
4635
b |> run("m3f_array_fold/{n}", n) {
@@ -61,11 +50,6 @@ def all_match_m3(b : B?) {
6150
run_m3(b, 100000)
6251
}
6352

64-
[benchmark]
65-
def all_match_m3f_old(b : B?) {
66-
run_m3f_old(b, 100000)
67-
}
68-
6953
[benchmark]
7054
def all_match_m3f(b : B?) {
7155
run_m3f(b, 100000)

benchmarks/sql/any_match.das

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,6 @@ def run_m3(b : B?; n : int) {
3030
}
3131
}
3232
}
33-
34-
def run_m3f_old(b : B?; n : int) {
35-
let arr <- fixture_array(n)
36-
b |> run("m3f_old_array_fold/{n}", n) {
37-
let yes = _old_fold(each(arr)._any(_.price > THRESHOLD))
38-
if (!yes) {
39-
b->failNow()
40-
}
41-
}
42-
}
43-
4433
def run_m3f(b : B?; n : int) {
4534
let arr <- fixture_array(n)
4635
b |> run("m3f_array_fold/{n}", n) {
@@ -61,11 +50,6 @@ def any_match_m3(b : B?) {
6150
run_m3(b, 100000)
6251
}
6352

64-
[benchmark]
65-
def any_match_m3f_old(b : B?) {
66-
run_m3f_old(b, 100000)
67-
}
68-
6953
[benchmark]
7054
def any_match_m3f(b : B?) {
7155
run_m3f(b, 100000)

benchmarks/sql/average_aggregate.das

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ options persistent_heap
44
require _common public
55

66
// SQL: SELECT AVG(price) FROM Cars.
7-
// m3/m3f_old/m3f sum and divide on a single pass.
7+
// m3/m3f sum and divide on a single pass.
88

99
def run_m1(b : B?; n : int) {
1010
with_sqlite(":memory:") $(db) {
@@ -27,17 +27,6 @@ def run_m3(b : B?; n : int) {
2727
}
2828
}
2929
}
30-
31-
def run_m3f_old(b : B?; n : int) {
32-
let arr <- fixture_array(n)
33-
b |> run("m3f_old_array_fold/{n}", n) {
34-
let a = _old_fold(each(arr)._select(double(_.price)).average())
35-
if (a == 0.0lf) {
36-
b->failNow()
37-
}
38-
}
39-
}
40-
4130
def run_m3f(b : B?; n : int) {
4231
let arr <- fixture_array(n)
4332
b |> run("m3f_array_fold/{n}", n) {
@@ -58,11 +47,6 @@ def average_aggregate_m3(b : B?) {
5847
run_m3(b, 100000)
5948
}
6049

61-
[benchmark]
62-
def average_aggregate_m3f_old(b : B?) {
63-
run_m3f_old(b, 100000)
64-
}
65-
6650
[benchmark]
6751
def average_aggregate_m3f(b : B?) {
6852
run_m3f(b, 100000)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
options gen2
2+
options persistent_heap
3+
4+
require _common public
5+
6+
let THRESHOLD = 500
7+
8+
// _where(_.price > T) |> _order_by(_.price) — fused prefilter + sort, NO take.
9+
// SQL: WHERE price > T ORDER BY price.
10+
// m3 (plain LINQ) materializes a filter array, then sorts a clone (two allocations).
11+
// m3f (spliced via plan_order_family Phase 3c) emits a single fused loop that collects
12+
// matching elements into one pre-allocated buffer, then sort_inplace's the buffer.
13+
14+
def run_m1(b : B?; n : int) {
15+
with_sqlite(":memory:") $(db) {
16+
fixture_db(db, n)
17+
b |> run("m1_sql/{n}", n) {
18+
let rows <- _sql(db |> select_from(type<Car>)
19+
|> _where(_.price > THRESHOLD)
20+
|> _order_by(_.price))
21+
if (empty(rows)) {
22+
b->failNow()
23+
}
24+
}
25+
}
26+
}
27+
28+
def run_m3(b : B?; n : int) {
29+
let arr <- fixture_array(n)
30+
b |> run("m3_array/{n}", n) {
31+
let rows <- (arr |> _where(_.price > THRESHOLD)
32+
|> _order_by(_.price))
33+
if (empty(rows)) {
34+
b->failNow()
35+
}
36+
}
37+
}
38+
39+
def run_m3f(b : B?; n : int) {
40+
let arr <- fixture_array(n)
41+
b |> run("m3f_array_fold/{n}", n) {
42+
let rows <- _fold(each(arr)._where(_.price > THRESHOLD)
43+
._order_by(_.price)
44+
.to_array())
45+
if (empty(rows)) {
46+
b->failNow()
47+
}
48+
}
49+
}
50+
51+
[benchmark]
52+
def bare_order_where_m1(b : B?) {
53+
run_m1(b, 100000)
54+
}
55+
56+
[benchmark]
57+
def bare_order_where_m3(b : B?) {
58+
run_m3(b, 100000)
59+
}
60+
61+
[benchmark]
62+
def bare_order_where_m3f(b : B?) {
63+
run_m3f(b, 100000)
64+
}

benchmarks/sql/chained_where.das

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,6 @@ def run_m3(b : B?; n : int) {
3737
}
3838
}
3939
}
40-
41-
def run_m3f_old(b : B?; n : int) {
42-
let arr <- fixture_array(n)
43-
b |> run("m3f_old_array_fold/{n}", n) {
44-
let c = _old_fold(each(arr)._where(_.price > THRESHOLD)
45-
._where(_.year >= YEAR_FLOOR)
46-
.count())
47-
if (c == 0) {
48-
b->failNow()
49-
}
50-
}
51-
}
52-
5340
def run_m3f(b : B?; n : int) {
5441
let arr <- fixture_array(n)
5542
b |> run("m3f_array_fold/{n}", n) {
@@ -72,11 +59,6 @@ def chained_where_m3(b : B?) {
7259
run_m3(b, 100000)
7360
}
7461

75-
[benchmark]
76-
def chained_where_m3f_old(b : B?) {
77-
run_m3f_old(b, 100000)
78-
}
79-
8062
[benchmark]
8163
def chained_where_m3f(b : B?) {
8264
run_m3f(b, 100000)

benchmarks/sql/contains_match.das

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,6 @@ def run_m3(b : B?; n : int) {
3333
}
3434
}
3535
}
36-
37-
def run_m3f_old(b : B?; n : int) {
38-
let arr <- fixture_array(n)
39-
b |> run("m3f_old_array_fold/{n}", n) {
40-
let yes = _old_fold(each(arr)._select(_.id).contains(TARGET_ID))
41-
if (!yes) {
42-
b->failNow()
43-
}
44-
}
45-
}
46-
4736
def run_m3f(b : B?; n : int) {
4837
let arr <- fixture_array(n)
4938
b |> run("m3f_array_fold/{n}", n) {
@@ -64,11 +53,6 @@ def contains_match_m3(b : B?) {
6453
run_m3(b, 100000)
6554
}
6655

67-
[benchmark]
68-
def contains_match_m3f_old(b : B?) {
69-
run_m3f_old(b, 100000)
70-
}
71-
7256
[benchmark]
7357
def contains_match_m3f(b : B?) {
7458
run_m3f(b, 100000)

benchmarks/sql/count_aggregate.das

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ let THRESHOLD = 500
77

88
// SQL pushes COUNT(*) to the engine returning one row.
99
// m3 must materialize the full filtered array, then walk to count it.
10-
// m3f_old is the pre-rewrite baseline fold (frozen — diverges as splice mode lands).
1110
// m3f folds where+count into a single fused pass (no intermediate array).
1211

1312
// --- m1: _sql over :memory: ---
@@ -34,17 +33,6 @@ def run_m3(b : B?; n : int) {
3433
}
3534
}
3635

37-
// --- m3f_old: pre-rewrite baseline fold ---
38-
def run_m3f_old(b : B?; n : int) {
39-
let arr <- fixture_array(n)
40-
b |> run("m3f_old_array_fold/{n}", n) {
41-
let c = _old_fold(each(arr)._where(_.price > THRESHOLD).count())
42-
if (c == 0) {
43-
b->failNow()
44-
}
45-
}
46-
}
47-
4836
// --- m3f: array LINQ folded into a single fused pass ---
4937
def run_m3f(b : B?; n : int) {
5038
let arr <- fixture_array(n)
@@ -66,11 +54,6 @@ def count_aggregate_m3(b : B?) {
6654
run_m3(b, 100000)
6755
}
6856

69-
[benchmark]
70-
def count_aggregate_m3f_old(b : B?) {
71-
run_m3f_old(b, 100000)
72-
}
73-
7457
[benchmark]
7558
def count_aggregate_m3f(b : B?) {
7659
run_m3f(b, 100000)

benchmarks/sql/distinct_count.das

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,6 @@ def run_m3(b : B?; n : int) {
3131
}
3232
}
3333
}
34-
35-
def run_m3f_old(b : B?; n : int) {
36-
let arr <- fixture_array(n)
37-
b |> run("m3f_old_array_fold/{n}", n) {
38-
let rows <- _old_fold(each(arr)._select(_.brand).distinct().to_array())
39-
if (empty(rows)) {
40-
b->failNow()
41-
}
42-
}
43-
}
44-
4534
def run_m3f(b : B?; n : int) {
4635
let arr <- fixture_array(n)
4736
b |> run("m3f_array_fold/{n}", n) {
@@ -62,11 +51,6 @@ def distinct_count_m3(b : B?) {
6251
run_m3(b, 100000)
6352
}
6453

65-
[benchmark]
66-
def distinct_count_m3f_old(b : B?) {
67-
run_m3f_old(b, 100000)
68-
}
69-
7054
[benchmark]
7155
def distinct_count_m3f(b : B?) {
7256
run_m3f(b, 100000)

benchmarks/sql/first_match.das

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ let THRESHOLD = 500
77

88
// SQL: SELECT ... LIMIT 1 — engine stops at first hit.
99
// m3 materializes the full filtered array then indexes [0].
10-
// m3f_old / m3f should ideally early-exit at the first matching row;
11-
// splice mode is the main target here.
10+
// m3f should ideally early-exit at the first matching row; splice mode
11+
// is the main target here.
1212

1313
def run_m1(b : B?; n : int) {
1414
with_sqlite(":memory:") $(db) {
@@ -31,17 +31,6 @@ def run_m3(b : B?; n : int) {
3131
}
3232
}
3333
}
34-
35-
def run_m3f_old(b : B?; n : int) {
36-
let arr <- fixture_array(n)
37-
b |> run("m3f_old_array_fold/{n}", n) {
38-
let row = _old_fold(each(arr)._where(_.price > THRESHOLD).first())
39-
if (row.price == 0) {
40-
b->failNow()
41-
}
42-
}
43-
}
44-
4534
def run_m3f(b : B?; n : int) {
4635
let arr <- fixture_array(n)
4736
b |> run("m3f_array_fold/{n}", n) {
@@ -62,11 +51,6 @@ def first_match_m3(b : B?) {
6251
run_m3(b, 100000)
6352
}
6453

65-
[benchmark]
66-
def first_match_m3f_old(b : B?) {
67-
run_m3f_old(b, 100000)
68-
}
69-
7054
[benchmark]
7155
def first_match_m3f(b : B?) {
7256
run_m3f(b, 100000)

0 commit comments

Comments
 (0)