github-actions[bot] commented on code in PR #65354:
URL: https://github.com/apache/doris/pull/65354#discussion_r3541448517


##########
fe/be-java-extensions/paimon-scanner/src/main/java/org/apache/doris/paimon/PaimonJniScanner.java:
##########
@@ -363,10 +405,159 @@ protected TableSchema parseTableSchema() throws 
UnsupportedOperationException {
     @Override
     public Map<String, String> getStatistics() {
         Map<String, String> statistics = new HashMap<>();
-        statistics.put("counter:PaimonJniIOManagerEnabled", ioManager != null 
? "1" : "0");
+        statistics.put("gauge:PaimonJniIOManagerEnabled", ioManager != null ? 
"1" : "0");
+        statistics.put("gauge:PaimonJniActiveScannerCount", 
String.valueOf(ACTIVE_SCANNERS.get()));
+        statistics.put("peak:PaimonJniActiveScannerPeakCount", 
String.valueOf(PEAK_ACTIVE_SCANNERS.get()));
+        statistics.put("gauge:PaimonJniAsyncReaderThreadCount",
+                String.valueOf(currentAsyncReaderThreadCount()));
+        statistics.put("peak:PaimonJniAsyncReaderThreadPeakCount",
+                String.valueOf(PEAK_ASYNC_READER_THREADS.get()));
+        statistics.put("gauge:PaimonJniRequiredFieldCount", 
String.valueOf(fields.length));
+        statistics.put("counter:PaimonJniSplitEncodedLength", 
String.valueOf(lengthOfParam("paimon_split")));
+        statistics.put("counter:PaimonJniPredicateEncodedLength", 
String.valueOf(lengthOfParam("paimon_predicate")));
+        statistics.put("gauge:PaimonJniAsyncThresholdConfigured",
+                hasPaimonOption(FILE_READER_ASYNC_THRESHOLD) ? "1" : "0");
+        
parseDataSizeBytes(paimonOption(FILE_READER_ASYNC_THRESHOLD)).ifPresent(
+                bytes -> 
statistics.put("bytes_gauge:PaimonJniAsyncThresholdBytes", 
String.valueOf(bytes)));
+        statistics.put("counter:PaimonJniReadBatchCalls", 
String.valueOf(readBatchCalls));
+        statistics.put("counter:PaimonJniEmptyReadBatchCalls", 
String.valueOf(emptyReadBatchCalls));
+        statistics.put("counter:PaimonJniRowsRead", String.valueOf(rowsRead));
+        statistics.put("timer:PaimonJniScannerOpenTime", 
String.valueOf(openTimeNanos));
+        statistics.put("timer:PaimonJniReadBatchTime", 
String.valueOf(readBatchTimeNanos));
+        putMemoryStatistics(statistics);
         return statistics;
     }
 
+    private int lengthOfParam(String key) {
+        String value = params.get(key);
+        return value == null ? 0 : value.length();
+    }
+
+    private boolean hasPaimonOption(String key) {
+        return paimonOption(key) != null;
+    }
+
+    private String paimonOption(String key) {
+        if (table != null) {
+            String tableOption = table.options().get(key);
+            if (tableOption != null) {
+                return tableOption;
+            }
+        }
+        return params.get(PAIMON_OPTION_PREFIX + key);
+    }
+
+    private static void putMemoryStatistics(Map<String, String> statistics) {
+        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
+        MemoryUsage heapUsage = memoryMXBean.getHeapMemoryUsage();
+        MemoryUsage nonHeapUsage = memoryMXBean.getNonHeapMemoryUsage();
+        statistics.put("bytes_gauge:PaimonJniJvmHeapUsed", 
String.valueOf(nonNegative(heapUsage.getUsed())));
+        statistics.put("bytes_gauge:PaimonJniJvmHeapCommitted", 
String.valueOf(nonNegative(heapUsage.getCommitted())));
+        statistics.put("bytes_gauge:PaimonJniJvmHeapMax", 
String.valueOf(nonNegative(heapUsage.getMax())));
+        statistics.put("bytes_gauge:PaimonJniJvmNonHeapUsed", 
String.valueOf(nonNegative(nonHeapUsage.getUsed())));
+        statistics.put("bytes_gauge:PaimonJniJvmNonHeapCommitted",
+                String.valueOf(nonNegative(nonHeapUsage.getCommitted())));
+        statistics.put("bytes_gauge:PaimonJniJvmNonHeapMax", 
String.valueOf(nonNegative(nonHeapUsage.getMax())));
+    }
+
+    private static long nonNegative(long value) {
+        return Math.max(value, 0L);
+    }
+
+    private static int currentAsyncReaderThreadCount() {
+        int currentCount = 
countThreadsByNamePrefix(ASYNC_READER_THREAD_NAME_PREFIX);
+        updatePeak(PEAK_ASYNC_READER_THREADS, currentCount);
+        return currentCount;
+    }
+
+    static int countThreadsByNamePrefix(String threadNamePrefix) {
+        int count = 0;
+        for (Thread thread : Thread.getAllStackTraces().keySet()) {
+            if (thread.getName().startsWith(threadNamePrefix)) {

Review Comment:
   `getStatistics()` now calls `currentAsyncReaderThreadCount()` for every 
Paimon JNI scanner close, and this helper uses 
`Thread.getAllStackTraces().keySet()` even though only thread names are needed. 
That API builds stack traces for every live JVM thread, so a query with many 
Paimon JNI splits will repeat a JVM-wide stack walk and allocate stack trace 
arrays once per split in both the legacy and v2 collectors. This makes the new 
observability path much heavier than intended, especially on BEs with many JVM 
threads. Please avoid collecting full stack traces here, for example by using 
`ThreadMXBean.getAllThreadIds()` plus `getThreadInfo(ids, 0)`/thread names, or 
another lightweight way to track the Paimon async-reader executor thread count.



-- 
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