Skip to content

perf: optimize LID comparison in iterators#358

Open
cheb0 wants to merge 10 commits intomainfrom
0-fast-cmp-xor
Open

perf: optimize LID comparison in iterators#358
cheb0 wants to merge 10 commits intomainfrom
0-fast-cmp-xor

Conversation

@cheb0
Copy link
Member

@cheb0 cheb0 commented Feb 17, 2026

Description

Adds a zero-cost comparison for LIDs in iterators, unblocks NextGEQ (need fast comparisons and min function for NextGEQ to be effective)

Details

Instead of calling the n.less comparator, we introduce a new type which hides all comparison logic. It's a struct node.LID (name can be changed).

Struct size is 64 bits. For default order (desc) we keep two fields:
lid: LID (32 bits), XOR mask: 0 (32 bits)
For reverse (order asc) we keep:
lid: LID ^ 0xFFFFFFFFF (32 bits), mask: 0xFFFFFFFFF (32 bits)
To unpack a LID we just do lid ^ mask.

This makes masked LID value always go in ascending way (both orders). i.e. for default order (docs sort desc) LIDs remain unchanged, but for reverse odder (docs sort asc) higher LID values are transformed to lower values in lid field in LID struct. Therefore, nodes no longer need to maintain reverse flag and execute same code for both orders. We can also effieciently compare values via ordinary <. We can also support efficient min/max function.

Leaf nodes (IteratorDesc/Asc, staticAsc/Desc) return terminal values. For default order we return the last LID as MaxUint32, for reverse order it's 0. Inversion makes both values equal (first 32 bits), we can always tell if it's null value just by comparing with MaxUint32.

Because null values are represented as MaxUint32 masked lid, we can eliminate unneeded if checks. Previously we had:
n.hasLeft && n.less(n.leftID, n.rightID)
Now we can just:
leftID.Less(rightID)
Because null values are represented as MaxUint32, this if check will never pass if leftID is null.

The encoded LID value is yielded directly from eval tree (search) and passed right to agg tree, where it can also be effectively compared to different values.

Measurements

Fractions taken from prod:

service:large_service, count by k8_pod (hot, data cached)
master: ~470 ms
fast cmp: ~420 ms

service:small_service, count by k8_pod (hot, data cached)
master: ~400 ms
fast cmp: ~330ms


  • I have read and followed all requirements in CONTRIBUTING.md;
  • I used LLM/AI assistance to make this pull request;

@cheb0
Copy link
Member Author

cheb0 commented Feb 17, 2026

@seqbenchbot up main search-logbench

@github-actions
Copy link
Contributor

🔴 Performance Degradation

Some benchmarks have degraded compared to the previous run.
Click on Show table button to see full list of degraded benchmarks.

Show table
Name Previous Current Ratio Verdict
FindSequence_Random/small-4 b369fc 05d8ea
4974.22 MB/s 4303.93 MB/s 0.87 🔴

@cheb0 cheb0 changed the title perf: fast lid representation for optimized comparison in iterators perf: new lid representation for optimized comparison in iterators Feb 17, 2026
@cheb0 cheb0 marked this pull request as draft February 17, 2026 13:26
@ozontech ozontech deleted a comment from seqbenchbot Feb 18, 2026
@ozontech ozontech deleted a comment from seqbenchbot Feb 18, 2026
@cheb0 cheb0 changed the title perf: new lid representation for optimized comparison in iterators perf: new lid representation for efficient comparison in iterators Feb 18, 2026
@cheb0 cheb0 marked this pull request as ready for review February 18, 2026 07:02
@codecov-commenter
Copy link

codecov-commenter commented Feb 18, 2026

Codecov Report

❌ Patch coverage is 96.15385% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.44%. Comparing base (158eee6) to head (8c12ab3).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
node/lid.go 84.00% 4 Missing ⚠️
frac/processor/search.go 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #358      +/-   ##
==========================================
- Coverage   71.51%   71.44%   -0.08%     
==========================================
  Files         205      205              
  Lines       14872    14921      +49     
==========================================
+ Hits        10636    10660      +24     
- Misses       3468     3486      +18     
- Partials      768      775       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cheb0 cheb0 changed the title perf: new lid representation for efficient comparison in iterators perf: implement new LID representation for efficient comparison in iterators Feb 18, 2026
@cheb0 cheb0 changed the title perf: implement new LID representation for efficient comparison in iterators perf: optimize LID comparison in iterators Feb 20, 2026
@cheb0 cheb0 mentioned this pull request Feb 20, 2026
2 tasks
@ozontech ozontech deleted a comment from github-actions bot Mar 2, 2026
@ozontech ozontech deleted a comment from github-actions bot Mar 2, 2026
@ozontech ozontech deleted a comment from github-actions bot Mar 2, 2026
@ozontech ozontech deleted a comment from github-actions bot Mar 2, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 2, 2026

🔴 Performance Degradation

Some benchmarks have degraded compared to the previous run.
Click on Show table button to see full list of degraded benchmarks.

Show table
Name Previous Current Ratio Verdict
AggDeep/size=1000-4 8aefcc 16a906
4817.00 ns/op 5463.00 ns/op 1.13 🔴
AggDeep/size=1000000-4 8aefcc 16a906
4837044.00 ns/op 5560985.00 ns/op 1.15 🔴
AggWide/size=10000-4 8aefcc 16a906
47761.00 ns/op 54451.00 ns/op 1.14 🔴
AggWide/size=1000000-4 8aefcc 16a906
516.00 B/op 580.00 B/op 1.12 🔴
5419714.00 ns/op 6230424.00 ns/op 1.15 🔴
FindSequence_Random/medium-4 8aefcc 16a906
10747.09 MB/s 9189.63 MB/s 0.86 🔴
99.33 ns/op 111.40 ns/op 1.12 🔴
FindSequence_Random/small-4 8aefcc 16a906
6638.44 MB/s 4563.10 MB/s 0.69 🔴
46.45 ns/op 56.10 ns/op 1.21 🔴

@ozontech ozontech deleted a comment from github-actions bot Mar 2, 2026
@eguguchkin eguguchkin added this to the v0.69.0 milestone Mar 2, 2026
@eguguchkin eguguchkin requested review from dkharms, eguguchkin and forshev and removed request for dkharms March 2, 2026 10:29
withAggQuery(processor.AggQuery{GroupBy: aggField("level")})),
[]map[string]uint64{
{"gateway": 3, "proxy": 2, "scheduler": 1},
{gateway: 3, proxy: 2, "scheduler": 1},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use const scheduler here as well

}

func (c LID) Eq(other LID) bool {
return c.lid == other.lid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: is it possible scenario when user of this method compares asc lid and desc lid? at first glance looks like no. however, do we need to take order into account here and check mask?

for example

descLid := NewLIDOrderDesc(5)
ascLid := NewLIDOrderAsc(math.MaxUint32 - 5)
descLid.Eq(ascLid) // produces true now

}

// Less compares two values. It also does an implicit null check, since we store math.MaxUint32 for null values.
// Which means if we call x.Less(y), then we now for sure that x is not null. Therefore, this Less call can work
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: then we know for sure?

n.readLeft()
}
for n.hasLeft && n.hasRight && n.less(n.rightID, n.leftID) {
for !n.rightID.IsNull() && n.rightID.Less(n.leftID) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should it be !n.leftID.IsNull() && n.rightID.Less(n.leftID) so we check both ids for null?

// For reverse order LID is inverted as follows: "MaxUint32 - LID" formula using XOR mask. Terminal LID value is 0 instead
// of MaxUint32 in reverse order, but 0 is XORed to MaxUint32. Which means, null value will always have lid field set to
// 0xFFFFFFFF (math.MaxUint32) regardless of reverse (order) flag.
type LID struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe ComparableLID? a bit longer but gives more context imo

@ozontech ozontech deleted a comment from seqbenchbot Mar 3, 2026
@ozontech ozontech deleted a comment from seqbenchbot Mar 3, 2026
@cheb0
Copy link
Member Author

cheb0 commented Mar 3, 2026

@seqbenchbot up main search-logbench --skip-bulk-comparison

@seqbenchbot
Copy link

seqbenchbot commented Mar 3, 2026

Oh-oh, @cheb0 ('>o.o)'>!

Something went wrong and I couldn't process your request.
Please take a closer look at error message:

unknown flag --skip-bulk-comparison

@cheb0
Copy link
Member Author

cheb0 commented Mar 3, 2026

@seqbenchbot up main search-logbench --skip-bulk-comparison

@seqbenchbot
Copy link

seqbenchbot commented Mar 3, 2026

Nice, @cheb0 <(-^,^-)=b!

Your request was successfully served.
Identificator for your ongoing benchmark - 645dce7d.

Here is a list of helpful links:

  • Take a look at Grafana dashboard;
  • Live-tailing logs are also available;

Have a great time!

@ozontech ozontech deleted a comment from seqbenchbot Mar 3, 2026
@seqbenchbot
Copy link

Nice, @cheb0 <(-^,^-)=b!

The benchmark with identificator 645dce7d was finished.
I've prepared a summary for you. Click on Show summary button to see it:

Show summary
Query Type mean (ms) stddev (ms) p(50) (ms) p(95) (ms) p(99) (ms) iterations
base comp diff base comp diff base comp diff base comp diff base comp diff base comp diff
service:*
 | group by (10s) | count
cold 3049.20 2807.20 -7.94% 525.42 322.72 -38.58% 2729.00 2795.50 +2.44% 3582.50 3069.00 -14.33% 3582.50 3069.00 -14.33% 5.00 5.00 0.00%
service:*
 | group by (10s) | count
warm 395.88 336.12 -15.10% 47.87 44.20 -7.66% 378.50 331.00 -12.55% 483.00 410.50 -15.01% 509.00 437.00 -14.15% 25.00 25.00 0.00%
k8s_pod:payment-backend-us-*
AND message:"this error doesn't exist, do not try to find it"
AND level:[0 to 3]
cold 739.80 679.20 -8.19% 91.35 68.77 -24.72% 682.00 663.50 -2.71% 832.50 742.50 -10.81% 832.50 742.50 -10.81% 5.00 5.00 0.00%
k8s_pod:payment-backend-us-*
AND message:"this error doesn't exist, do not try to find it"
AND level:[0 to 3]
warm 4.44 4.76 +7.21% 0.65 1.09 +67.66% 4.00 4.00 0.00% 5.50 7.00 +27.27% 6.00 7.00 +16.67% 25.00 25.00 0.00%
service:payment-backend-us
AND level:[0 to 3]
cold 126.00 112.20 -10.95% 63.62 34.71 -45.44% 99.00 93.00 -6.06% 173.00 144.00 -16.76% 173.00 144.00 -16.76% 5.00 5.00 0.00%
service:payment-backend-us
AND level:[0 to 3]
warm 4.24 4.12 -2.83% 0.52 0.53 +0.61% 4.00 4.00 0.00% 5.00 5.00 0.00% 5.00 5.00 0.00% 25.00 25.00 0.00%
service:* | group by (k8s_pod) | count
cold 2054.20 1841.60 -10.35% 140.55 155.02 +10.29% 1978.00 1777.00 -10.16% 2200.50 1979.50 -10.04% 2200.50 1979.50 -10.04% 5.00 5.00 0.00%
service:* | group by (k8s_pod) | count
warm 901.48 737.04 -18.24% 74.97 55.44 -26.05% 881.00 730.00 -17.14% 1006.00 846.00 -15.90% 1052.50 855.00 -18.76% 25.00 25.00 0.00%
service:payment-backend-eu
 | group by (k8s_pod) | count
cold 1052.20 981.40 -6.73% 179.83 109.62 -39.04% 971.00 933.00 -3.91% 1191.00 1069.50 -10.20% 1191.00 1069.50 -10.20% 5.00 5.00 0.00%
service:payment-backend-eu
 | group by (k8s_pod) | count
warm 329.96 284.20 -13.87% 25.58 30.23 +18.17% 325.00 277.50 -14.62% 369.00 332.00 -10.03% 386.50 344.50 -10.87% 25.00 25.00 0.00%
service:payment-backend-eu
 | group by (k8s_pod, 10s) | min(level)
cold 3203.00 3102.00 -3.15% 392.04 530.85 +35.41% 3056.00 2764.00 -9.55% 3562.50 3667.00 +2.93% 3562.50 3667.00 +2.93% 5.00 5.00 0.00%
service:payment-backend-eu
 | group by (k8s_pod, 10s) | min(level)
warm 487.52 423.24 -13.19% 43.71 36.66 -16.13% 467.00 415.50 -11.03% 565.50 487.00 -13.88% 583.00 497.00 -14.75% 25.00 25.00 0.00%
service:payment-backend-eu
 | group by (1s) | count
cold 2358.00 2325.00 -1.40% 212.13 502.04 +136.66% 2270.00 2071.50 -8.74% 2558.00 2822.00 +10.32% 2558.00 2822.00 +10.32% 5.00 5.00 0.00%
service:payment-backend-eu
 | group by (1s) | count
warm 62.88 66.48 +5.73% 13.57 12.85 -5.28% 66.00 73.50 +11.36% 78.00 77.50 -0.64% 78.50 78.50 0.00% 25.00 25.00 0.00%
k8s_pod:payment-* | group by (10s) | count
cold 2921.80 2860.80 -2.09% 262.72 1442.25 +448.97% 2767.00 2196.50 -20.62% 3174.50 3923.50 +23.59% 3174.50 3923.50 +23.59% 5.00 5.00 0.00%
k8s_pod:payment-* | group by (10s) | count
warm 365.08 284.08 -22.19% 33.40 33.67 +0.82% 354.00 275.00 -22.32% 431.00 332.50 -22.85% 436.00 354.50 -18.69% 25.00 25.00 0.00%
service:api-gateway-us
 | group by (method) | avg(size)
cold 3246.60 3337.00 +2.78% 119.04 212.72 +78.69% 3224.00 3287.00 +1.95% 3345.50 3539.00 +5.78% 3345.50 3539.00 +5.78% 5.00 5.00 0.00%
service:api-gateway-us
 | group by (method) | avg(size)
warm 1917.60 1890.48 -1.41% 37.84 37.45 -1.02% 1909.00 1878.50 -1.60% 1968.00 1952.00 -0.81% 2001.00 1977.00 -1.20% 25.00 25.00 0.00%
k8s_namespace:prod
AND level:[0 to 3]
 | group by (15s) | count
cold 2570.60 2155.00 -16.17% 787.33 274.03 -65.19% 2111.00 2096.50 -0.69% 3298.00 2388.00 -27.59% 3298.00 2388.00 -27.59% 5.00 5.00 0.00%
k8s_namespace:prod
AND level:[0 to 3]
 | group by (15s) | count
warm 116.20 106.08 -8.71% 19.92 14.29 -28.29% 121.50 106.00 -12.76% 145.00 130.00 -10.34% 148.00 130.50 -11.82% 25.00 25.00 0.00%
service:payment-backend-eu
 | group by (k8s_pod) | min(level)
cold 1423.00 1256.00 -11.74% 160.24 102.27 -36.18% 1341.50 1195.50 -10.88% 1583.00 1361.00 -14.02% 1583.00 1361.00 -14.02% 5.00 5.00 0.00%
service:payment-backend-eu
 | group by (k8s_pod) | min(level)
warm 454.04 374.44 -17.53% 35.70 29.23 -18.13% 441.50 375.00 -15.06% 515.50 418.50 -18.82% 531.50 426.50 -19.76% 25.00 25.00 0.00%
k8s_pod:payment-backend-us-*
AND transaction_id:'*needle*'
cold 1187.40 1162.20 -2.12% 88.06 152.73 +73.44% 1160.00 1106.50 -4.61% 1268.00 1294.50 +2.09% 1268.00 1294.50 +2.09% 5.00 5.00 0.00%
k8s_pod:payment-backend-us-*
AND transaction_id:'*needle*'
warm 113.28 109.08 -3.71% 15.50 15.07 -2.79% 116.00 107.00 -7.76% 134.00 133.00 -0.75% 137.00 140.50 +2.55% 25.00 25.00 0.00%
service:payment-backend-eu
AND level:[0 to 3]
 | group by (10s) | count
cold 2318.20 2277.40 -1.76% 273.60 333.42 +21.86% 2206.00 2092.50 -5.15% 2549.00 2610.00 +2.39% 2549.00 2610.00 +2.39% 5.00 5.00 0.00%
service:payment-backend-eu
AND level:[0 to 3]
 | group by (10s) | count
warm 63.72 56.68 -11.05% 10.57 12.87 +21.72% 67.50 59.50 -11.85% 74.00 70.50 -4.73% 75.00 71.50 -4.67% 25.00 25.00 0.00%
k8s_pod:payment-backend-us-*
AND transaction_id:'tx-needle-*'
cold 631.80 592.20 -6.27% 77.55 67.82 -12.55% 620.50 570.50 -8.06% 701.50 642.50 -8.41% 701.50 642.50 -8.41% 5.00 5.00 0.00%
k8s_pod:payment-backend-us-*
AND transaction_id:'tx-needle-*'
warm 13.64 11.40 -16.42% 1.44 1.00 -30.55% 13.00 11.00 -15.38% 15.50 13.00 -16.13% 17.50 14.00 -20.00% 25.00 25.00 0.00%
service:api-gateway-us
AND method:'GET'
AND status:200 AND size:[990 TO *]
AND resource:'/assets/css/bootstrap.css'
cold 379.40 369.80 -2.53% 63.24 49.17 -22.25% 356.00 355.00 -0.28% 441.50 413.50 -6.34% 441.50 413.50 -6.34% 5.00 5.00 0.00%
service:api-gateway-us
AND method:'GET'
AND status:200 AND size:[990 TO *]
AND resource:'/assets/css/bootstrap.css'
warm 94.76 86.76 -8.44% 8.47 7.62 -9.97% 94.50 86.00 -8.99% 108.00 97.00 -10.19% 110.00 102.00 -7.27% 25.00 25.00 0.00%
service:api-gateway-us
 | group by (method) | avg(size)
cold 3277.20 3337.00 +1.82% 135.97 212.72 +56.44% 3236.50 3287.00 +1.56% 3398.50 3539.00 +4.13% 3398.50 3539.00 +4.13% 5.00 5.00 0.00%
service:api-gateway-us
 | group by (method) | avg(size)
warm 1903.72 1890.48 -0.70% 40.04 37.45 -6.47% 1897.50 1878.50 -1.00% 1964.50 1952.00 -0.64% 2006.00 1977.00 -1.45% 25.00 25.00 0.00%
k8s_pod:payment-backend-us-*
AND level:[3 to 7]
AND NOT message:'health check'
AND NOT message:'payment authorized'
cold 75.20 71.20 -5.32% 5.81 7.19 +23.86% 75.50 69.50 -7.95% 79.50 77.50 -2.52% 79.50 77.50 -2.52% 5.00 5.00 0.00%
k8s_pod:payment-backend-us-*
AND level:[3 to 7]
AND NOT message:'health check'
AND NOT message:'payment authorized'
warm 4.12 4.60 +11.65% 0.67 2.22 +233.02% 4.00 4.00 0.00% 5.50 5.00 -9.09% 6.00 10.00 +66.67% 25.00 25.00 0.00%
service:payment-backend-us
AND NOT message:'payment authorization failed'
AND NOT message:'authentication failed'
AND NOT message:'payment gateway timeout'
cold 85.00 74.60 -12.24% 9.75 25.26 +159.21% 84.00 62.00 -26.19% 93.50 97.50 +4.28% 93.50 97.50 +4.28% 5.00 5.00 0.00%
service:payment-backend-us
AND NOT message:'payment authorization failed'
AND NOT message:'authentication failed'
AND NOT message:'payment gateway timeout'
warm 3.76 4.04 +7.45% 0.52 0.54 +3.00% 4.00 4.00 0.00% 4.00 4.50 +12.50% 4.50 5.50 +22.22% 25.00 25.00 0.00%
service:payment-backend-eu
 | group by (k8s_pod, 10s) | count
cold 2954.00 2592.00 -12.25% 336.08 416.88 +24.04% 2838.00 2497.50 -12.00% 3221.50 2917.00 -9.45% 3221.50 2917.00 -9.45% 5.00 5.00 0.00%
service:payment-backend-eu
 | group by (k8s_pod, 10s) | count
warm 371.56 319.12 -14.11% 34.89 32.05 -8.15% 366.50 319.00 -12.96% 423.50 365.50 -13.70% 451.00 386.50 -14.30% 25.00 25.00 0.00%
k8s_pod:payment-backend-us-*
AND transaction_id:'tx-needle-0000'
cold 407.20 446.60 +9.68% 12.52 83.49 +566.99% 404.50 419.50 +3.71% 419.00 517.50 +23.51% 419.00 517.50 +23.51% 5.00 5.00 0.00%
k8s_pod:payment-backend-us-*
AND transaction_id:'tx-needle-0000'
warm 3.92 3.68 -6.12% 1.00 0.56 -44.14% 4.00 4.00 0.00% 5.50 4.00 -27.27% 6.50 4.50 -30.77% 25.00 25.00 0.00%
service:payment-backend-us
cold 48.60 53.80 +10.70% 14.59 27.68 +89.75% 40.50 39.50 -2.47% 61.00 77.00 +26.23% 61.00 77.00 +26.23% 5.00 5.00 0.00%
service:payment-backend-us
warm 3.84 3.88 +1.04% 0.69 0.93 +34.79% 4.00 4.00 0.00% 5.00 5.50 +10.00% 5.00 6.00 +20.00% 25.00 25.00 0.00%

Have a great time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants