Hakky54 / gatekeeper

🔐 A lightweight java library which guards your publicly accessible internal implementations.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Performance: Faster method caller lookup

Col-E opened this issue · comments

commented

For a performance improvement you can replace Thread.currentThread().getStackTrace() with new Exception().getStackTrace()

Additional context
The Thread#getStackTrace() approach is slower because it has to be thread-safe. More details on performance are in the comments.

Thank you for the suggestion! I didn't know about this.
The bug report at the page of java mentions this is resolved from java 6 onwards and this library works from java 8 onwards, so is the alternative still valid?

I have run a test with a loop of n=1.000.000

  • with getting the stack-trace from a new Exception has a total time of 52.085 ms
  • with getting the stack-trace from Thread.currentThread() has a total time of 52.038 ms

The results are similar, but maybe I am doing something wrong?

commented

Ah it is indeed largely fixed in Java 8. I overlooked that.

// Thread.java
    public StackTraceElement[] getStackTrace() {
        if (this != Thread.currentThread()) {
            // check for getStackTrace permission
            SecurityManager security = System.getSecurityManager();
            if (security != null) {
                security.checkPermission(
                    SecurityConstants.GET_STACK_TRACE_PERMISSION);
            }
            // optimization so we do not call into the vm for threads that
            // have not yet started or have terminated
            if (!isAlive()) {
                return EMPTY_STACK_TRACE;
            }
            StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this});
            StackTraceElement[] stackTrace = stackTraceArray[0];
            // a thread that was alive during the previous isAlive call may have
            // since terminated, therefore not having a stacktrace.
            if (stackTrace == null) {
                stackTrace = EMPTY_STACK_TRACE;
            }
            return stackTrace;
        } else {
            // Don't need JVM help for current thread
            return (new Exception()).getStackTrace();
        }
    }

In the use case of GateKeeper the extra work done here is the call to public static native Thread currentThread() and the redundant call to Thread.currentThread() inside the method shown above to check vs the current instance.

Swapping to new Exception() will remove this minor redundancy but its a minor improvement.

Thank you for the detailed explanation and investigation! I like the alternative as it would not need to do the additional checks under the covers as you mentioned. I will switch to new Exception() for getting the stacktrace. See here for the related commit: c636100