xiangfu0 commented on code in PR #19800:
URL: https://github.com/apache/pinot/pull/19800#discussion_r4253915032


##########
pinot-query-runtime/src/main/java/org/apache/pinot/query/runtime/operator/MultistageGroupByExecutor.java:
##########
@@ -203,15 +258,15 @@ public List<Object[]> getResult(Comparator<Object[]> 
comparator, int maxRows) {
 
     int idx = 0;
     while (idx < numGroups && groupKeyIterator.hasNext()) {
-      Object[] row = getRow(groupKeyIterator, numKeys, numFunctions, 
resultStoredTypes);
+      T row = decorate.apply(getRow(groupKeyIterator, numKeys, numFunctions, 
resultStoredTypes));
       sortedRows.add(row);
       idx++;
     }
 
     while (groupKeyIterator.hasNext()) {
       idx++;
       // TODO: allocate new array row only if row enters set
-      Object[] row = getRow(groupKeyIterator, numKeys, numFunctions, 
resultStoredTypes);
+      T row = decorate.apply(getRow(groupKeyIterator, numKeys, numFunctions, 
resultStoredTypes));

Review Comment:
   Measured the object path before restructuring it, then fixed wrapper 
allocation in 
[1ca3cc9edc](https://github.com/apache/pinot/commit/1ca3cc9edc04a49b45236d02f63b2cf700109fec).
 Rejected candidates and entries polled from the heap are recycled, with their 
cached keys reset before reuse. This bounds `SortedRow` and key-array 
allocation to K+1 per trim; heap-owned entries are never modified and the 
original intermediate payloads remain mergeable.
   
   | Aggregate | K | Before ms/op | After ms/op | Before B/op | After B/op |
   |---|---:|---:|---:|---:|---:|
   | AVG | 500 | 14.262 ± 6.078 | 7.525 ± 2.529 | 11,202,562 | 6,426,586 |
   | AVG | 5,000 | 33.579 ± 29.211 | 16.044 ± 1.817 | 11,238,629 | 6,678,616 |
   | Raw HLL | 500 | 1366.643 ± 146.105 | 1160.987 ± 24.530 | 10,406,050 | 
5,630,094 |
   | Raw HLL | 5,000 | 4282.882 ± 267.221 | 4182.569 ± 51.501 | 10,445,520 | 
5,885,589 |
   | SUM control | 500 | 4.227 ± 0.484 | 3.807 ± 0.099 | 4,002,223 | 4,002,221 |
   | SUM control | 5,000 | 10.065 ± 0.464 | 8.819 ± 0.572 | 4,038,243 | 
4,038,239 |
   
   Total trim allocation falls 40.6–45.9% for the measured OBJECT cases. Native 
`SerializedHLL.compareTo()` still recomputes both operands' cardinalities: 
candidate raw-HLL trims take about 1.16s at K=500 and 4.18s at K=5,000 here. 
This change deliberately retains that native comparison contract; it does not 
add a public sketch cache or aggregation-function allowlist.
   
   JMH 1.37, Temurin 25.0.4.1 on an Apple M4 Pro shared host; one thread, two 
forks, 3 × 1s warmup and 5 measured iterations per fork, GC profiler, 512 MiB 
initial/1 GiB maximum heap. Object measurements use 2s iterations; funnel/copy 
measurements use 1s. Errors shown are JMH 99.9% confidence errors.
   
   The object fixture invokes production `getResult()` on 100,000 preaggregated 
groups, aggregate DESC then INT group ASC, with varied AVG counts and 
independent raw-HLL log2m=12 sketches containing 1–32 distinct inputs/group. 
Fixture creation, merging and correctness checks run in trial setup before 
warmup; the measured operation includes comparator construction, trimming and 
result draining. There are no allocating teardown checks. All 22 requested 
parameter cases completed and passed the independent result/preservation 
checks. The harness and raw results remain outside the PR.
   
   These are trim/finalizer measurements, excluding upstream aggregation, 
planning, networking and whole-query QPS/p95/p99. The baseline AVG timings are 
noisy, so I am claiming the measured allocation reduction rather than a general 
latency speedup. SUM allocation is effectively unchanged; the observed control 
timings show no regression in these fixtures.
   
   Validation: 67 focused MSE/funnel tests passed, as did all four 
affected-module `pinot-query-runtime` formatting/checkstyle/license checks. The 
new regression checks recycled-entry resets, ties, nulls, repeated trimming and 
payload preservation; a missing-reset mutant fails it. The fork branch and live 
PR head are verified at the pushed commit. Exact-head hosted CI is running. The 
recorded human approval is on the earlier `4292f86188` head; this follow-up has 
not received a fresh human review.
   



##########
pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/funnel/window/FunnelMaxStepAggregationFunction.java:
##########
@@ -51,6 +51,7 @@ public Integer extractFinalResult(@Nullable 
PriorityQueue<FunnelStepEvent> stepE
     if (stepEvents == null || stepEvents.isEmpty()) {
       return finalMaxStep;
     }
+    stepEvents = new PriorityQueue<>(stepEvents);

Review Comment:
   Completed the requested large-queue measurements for production MaxStep and 
MatchStep finalization at the pushed 
[1ca3cc9edc](https://github.com/apache/pinot/commit/1ca3cc9edc04a49b45236d02f63b2cf700109fec)
 head. The window-finalizer sources are unchanged from the measured 
`01a311b119` overlay. I kept the private queue copy because repeated extraction 
and subsequent merging must preserve the accumulator.
   
   | Function | Events | First-window completion µs/op | Full traversal µs/op | 
Early B/op | Full B/op |
   |---|---:|---:|---:|---:|---:|
   | MAX_STEP | 10,000 | 1.330 ± 0.285 | 470.149 ± 18.146 | 40,160 | 40,163 |
   | MAX_STEP | 100,000 | 8.430 ± 0.220 | 6241.274 ± 356.042 | 400,132 | 
400,203 |
   | MATCH_STEP | 10,000 | 0.914 ± 0.013 | 422.043 ± 12.989 | 40,160 | 40,219 |
   | MATCH_STEP | 100,000 | 8.581 ± 0.400 | 5981.614 ± 117.375 | 400,160 | 
400,258 |
   
   
   The early case completes with events at timestamps 0, 1 and 2 in a window of 
100, followed by a distant tail. It therefore terminates in the first 
three-event window while still copying all N references. The full case has no 
step-0 event, so it traverses the entire queue searching for a start; it is not 
a successful multi-window funnel.
   
   Separately, the exact JDK constructor used by the finalizer (`new 
PriorityQueue<>(queue)`) measured:
   
   | Queue events | Shallow copy µs/op | B/op |
   |---:|---:|---:|
   | 10,000 | 0.912 ± 0.093 | 40,048 |
   | 100,000 | 8.454 ± 0.883 | 400,048 |
   
   
   This confirms the O(N) shallow reference-copy allocation, including early 
completion; the events themselves are shared. The copy measurements are 
separate fixtures and should not be subtracted from finalization means to claim 
exact evaluator time.
   
   JMH 1.37, Temurin 25.0.4.1 on an Apple M4 Pro shared host; one thread, two 
forks, 3 × 1s warmup and 5 measured iterations per fork, GC profiler, 512 MiB 
initial/1 GiB maximum heap. Object measurements use 2s iterations; funnel/copy 
measurements use 1s. Errors shown are JMH 99.9% confidence errors.
   
   Fixtures are constructed before warmup. Setup checks two extractions and 
unchanged queue contents/event references after each; no teardown allocations 
contaminate the GC measurements. All eight finalizer cases and both 
isolated-copy cases completed. These are shared-host absolute costs, excluding 
real query resource-accounting/cancellation workloads and whole-query latency. 
The harness and raw results remain outside the PR.
   
   Validation at the verified pushed head: 67 focused MSE/funnel tests passed, 
including repeated extraction followed by merging for all five window variants, 
plus all four affected-module checks. Exact-head hosted CI is running; the 
existing human approval remains on the earlier `4292f86188` head.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to