88import java .io .IOException ;
99import java .io .PrintStream ;
1010import java .util .*;
11+ import java .util .regex .Pattern ;
1112
1213import one .convert .*;
1314import one .jfr .DictionaryInt ;
@@ -37,12 +38,14 @@ public void addStack(long id, long[] methods, int[] locations, byte[] types, int
3738
3839 public void beforeChunk () {
3940 state .methodCache .clear ();
41+ state .includeCache .clear ();
4042 }
4143
4244 public void finish (long startMs ) {
4345 this .startMs = startMs ;
4446 state .methodCache .clear ();
4547 state .stackTracesCache .clear ();
48+ state .includeCache .clear ();
4649 }
4750
4851 private EvaluationContext evaluate () {
@@ -394,8 +397,11 @@ private static class State {
394397 // Maps stack trace ID to prototype ID in stackTracesRemap
395398 final DictionaryInt stackTracesCache = new DictionaryInt ();
396399 final Map <MethodKey , Integer > methodCache = new HashMap <>();
397- final Index <Method > methods = new Index <>(Method .class , Method .EMPTY );
398- final Index <String > symbolTable = new Index <>(String .class , "" );
400+ final BidirectionalIndex <Method > methods = new BidirectionalIndex <>(Method .class , Method .EMPTY );
401+ final BidirectionalIndex <String > symbolTable = new BidirectionalIndex <>(String .class , "" );
402+
403+ // Cache for exclude/include filter results per prototype ID
404+ final Map <Integer , Boolean > includeCache = new HashMap <>();
399405
400406 // reusable array to (temporary) store (potentially) new stack trace
401407 int [] cachedStackTrace = new int [4096 ];
@@ -406,14 +412,52 @@ private static class State {
406412 this .sampleList = new SampleList (blockDurationMs );
407413 }
408414
415+ private String resolveFrameName (Method method ) {
416+ if (method .className == 0 ) {
417+ return symbolTable .getKey (method .methodName );
418+ }
419+ if (method .methodName == 0 ) {
420+ return symbolTable .getKey (method .className );
421+ }
422+ return symbolTable .getKey (method .className ) + '.' + symbolTable .getKey (method .methodName );
423+ }
424+
425+ private boolean includeStack (int prototypeId ) {
426+ if (args .include == null && args .exclude == null ) {
427+ return true ;
428+ }
429+ return includeCache .computeIfAbsent (prototypeId , stackId -> applyIncludeExcludeFilter (stackId ));
430+ }
431+
432+ // Returns true if the stack should be included
433+ private boolean applyIncludeExcludeFilter (int stackId ) {
434+ int [] stack = stackTracesRemap .get (stackId );
435+ Pattern include = args .include ;
436+ Pattern exclude = args .exclude ;
437+ for (int i = 0 ; i < stack .length ; i ++) {
438+ Method method = methods .getKey (stack [i ]);
439+ String name = resolveFrameName (method );
440+ if (exclude != null && exclude .matcher (name ).matches ()) {
441+ return false ;
442+ }
443+ if (include != null && include .matcher (name ).matches ()) {
444+ if (exclude == null ) return true ;
445+ include = null ;
446+ }
447+ }
448+ return include == null ;
449+ }
450+
409451 public void addEvent (int stackTraceId , int threadId , int classId , byte type , long timeMs ) {
410- if (sampleList .getRecordsCount () >= LIMIT ) {
452+ if (sampleList .getRecordsCount () >= LIMIT || stackTraceId == 0 ) {
411453 return ;
412454 }
413455
414456 int prototypeId = stackTracesCache .get (stackTraceId );
415457 if (classId == 0 && !args .threads ) {
416- sampleList .add (prototypeId , timeMs );
458+ if (includeStack (prototypeId )) {
459+ sampleList .add (prototypeId , timeMs );
460+ }
417461 return ;
418462 }
419463
@@ -435,7 +479,10 @@ public void addEvent(int stackTraceId, int threadId, int classId, byte type, lon
435479 cachedStackTrace [stackSize - 1 ] = getMethodIndex (key );
436480 }
437481
438- sampleList .add (stackTracesRemap .index (cachedStackTrace , stackSize ), timeMs );
482+ int newStackId = stackTracesRemap .index (cachedStackTrace , stackSize );
483+ if (includeStack (newStackId )) {
484+ sampleList .add (newStackId , timeMs );
485+ }
439486 }
440487
441488 public void addStack (long id , long [] methods , int [] locations , byte [] types , int size ) {
0 commit comments