Draft JEP: Efficient Stack Walking API (original) (raw)

David M. Lloyd david.lloyd at redhat.com
Wed Jul 9 13:42:42 UTC 2014


Just want to say that I am also looking forward to progress on this.

On 07/09/2014 12:25 AM, Jeremy Manson wrote: > Thanks for the response, Mandy. I'm looking forward to seeing the final > version. >> For CallerFinder, we use reflective goop to get at > sun.misc.JavaLangAccess.getStackTraceElement. It requires us to build a > Throwable (with associated stacktrace), but not to generate all of those > StackTraceElement[] strings. This saves a lot of CPU cycles over something > like Thread.getStackTrace(), but in this case, cheaper is better, and we'd > definitely prefer a better solution. Functions like > JavajavalangThrowablefillInStackTrace are still big cycle consumers. >> Jeremy >>> On Mon, Jul 7, 2014 at 8:06 PM, Mandy Chung <mandy.chung at oracle.com> wrote: >>> Hi Jeremy, >>>> Thanks for the feedback and the CallerFinder API you have. >>>>>> On 7/7/2014 9:55 AM, Jeremy Manson wrote: >>>> Hey folks, >>>> I don't know if Mandy's draft JEP has gotten any love, >>>>>> The JEP process is in transition to 2.0 version. Hope this JEP will come >> out soon. >>>>>> but this is something that has (in the past) been a major CPU cycle >> consumer for us, and we've had to invent / reinvent many wheels to fix it >> internally, so we'd love to see a principled solution. >>>> A couple of notes: >>>> - A large percentage of the time, you just want to find one of: >> 1) The direct caller of the method, >> 2) The first caller outside a given package. >>>>>> The current thinking is to allow you to find the direct caller as well as >> express the predicate for filtering that will cover these cases. >>>>>> We added a CallerFinder API that basically looks like this: >>>> // Finds the caller of the invoking method in the current stack that >> isn't in one of the excluded classes >> public static StackTraceElement findCaller(Class<?>... excludedClasses); >>>> // Finds the first caller of a given class >> public static StackTraceElement findCallerOf(Class<?>... classesToFind); >>>> This isn't the ideal API (it is more the one that happened to be >> convenient when we threw together the class), but it gets the vast majority >> of use cases. >>>>>> Does it use Thread.getStackTrace() to implement this CallerFinder API? >> Thread.getStackTrace or Throwable.getStackTrace both eagerly capture the >> entire stack trace that is expensive. We want to have the VM to be able to >> only capture the stack frames that the client needs and the implementation >> as efficient as possible. >>>>>> 2) Even with a super-efficient stack walker, anyone who uses the >> java.util.logging framework pervasively is going to see a lot of CPU cycles >> consumed by determining the caller. >>>>>> The current LogRecord implementation calls new Throwable that has to pay >> the cost of capturing the entire stack. >>>>>> We've had a lot of luck minimizing this by using a bytecode rewriter to >> change callers of log(msg) to log(sourceClass, sourceMethod, msg). This is >> almost certainly something that could be done (even in a principled way!) >> by the VM; improvements to CPU usage in such apps have been dramatic. >>>>>> Thanks. I'll make sure to measure and compare the performance with >> java.util.logging using the new stack walk API and also may ask your help >> to determine if you observe the performance difference comparing the >> rewritten bytecode vs the java.util.logging using the new API. >>>> Mandy >>>>>> Jeremy >>>>>>>> On Sun, Mar 30, 2014 at 4:02 PM, Mandy Chung <mandy.chung at oracle.com> >> wrote: >>>>> Below is a draft JEP we are considering submitting for JDK 9. >>>>>> Mandy >>>>>> ---------------------------- >>> Title: Efficient API for Stack Walking >>>>>> Goal >>> ---- >>>>>> Define a standard API for stack walking that will be efficient and >>> performant. >>>>>> Non-goal >>> -------- >>>>>> It is not a goal for this API be easy to use via Reflection for example >>> use in code that is compiled for an older JDK. >>>>>> Motivation >>> ---------- >>>>>> There is no standard API to obtain information about the caller's class >>> and traverse the execution stack in a performant way. Existing libraries >>> and frameworks such as Log4j and Groovy have to resort to using the >>> JDK internal API sun.reflect.Reflection.getCallerClass(int depth). >>>>>> This JEP proposes to define a standard API for stack walking that will >>> be efficient and performant and also enable the implementation up >>> level the stack walk machinery from the VM to Java and replaces >>> the current mechanism of Throwable.fillInStackTrace._ >>>>>> _Description_ >>> _-----------_ >>>>>> _There is no standard API to traverse certain frames on the execution_ >>> _stack efficiently and access the Class instance of each frame._ >>>>>> _There are APIs that allow to access the stack trace information:_ >>> _- Throwable.getStackTrace()andThread.getStackTrace()that returns_ >>> _an array ofStackTraceElementwhich contains the classname_ >>> _and method name of a stack trace._ >>> _-SecurityManager.getClassContext()which is a protected method_ >>> _such that onlySecurityManagersubclass can access the class_ >>> _context._ >>>>>> _These APIs require the VM to eagerly capture a snapshot of the entire_ >>> _stack trace and returns the information representing the entire stack._ >>> _There is no other way to avoid the cost to examine all frames if_ >>> _the caller is only interested in the top few frames on the stack._ >>> _BothThrowable.getStackTrace()andThread.getStackTrace()methods_ >>> _return an array ofStackTraceElementthat contains the classname and_ >>> _method name of a stack frame but theClassinstance._ >>>>>> _In fact, for applications interested in the entire stack, the_ >>> _specification_ >>> _allows VM implementation to omit some frames in the stack for performance._ >>> _In other words,Thread.getStackTrace()may return a partial stack trace._ >>>>>> _These APIs do not satisfy the use cases that currently depend on_ >>> _thegetCallerClass(int depth) method or its performance overhead_ >>> _is intolerable. The use cases include:_ >>>>>> _- JDK caller-sensitive APIs look up its immediate caller's class_ >>> _which will be used to determine the behavior of the API. For example_ >>> _Class.forName(String classname) and_ >>> _ResourceBundle.getBundle(String rbname) methods use the immediate_ >>> _caller's class loader to load a class and a resource bundle_ >>> _respectively._ >>> _Class.getMethodetc will use the immediate caller's class loader_ >>> _to determine the security checks to be performed._ >>>>>> _-java.util.logging, Log4j and Groovy runtime filter the intermediary_ >>> _stack frames (typically implementation-specific and reflection frames)_ >>> _and find the caller's class to be used by the runtime of such library_ >>> _or framework._ >>>>>> _- Traverse the entire stack trace or the stack trace of a Throwbale_ >>> _and obtain additional information about classes for enhanced_ >>> _diagnosibility in addition to the class and method name._ >>>>>> _This JEP will define a stack walk API that allows laziness, frame_ >>> _filtering,_ >>> _supports short reaches to stop at a frame matching some criteria_ >>> _as well as long reaches to traverse the entire stack trace. This would_ >>> _need the JVM to provide a flexible mechanism to traverse and materialize_ >>> _the specific stack frame information to be used and allow efficient_ >>> _lazy access to additional stack frames when required._ >>> _Native JVM transitions should be minimzed._ >>>>>> _The API will define how it works when running with a security manager_ >>> _that allows access to a Classinstance_ >>> _of any frame ensuring that the security is not compromised._ >>>>>> _An example API to walk the stack can be like:_ >>> _Thread.walkStack(Consumer<StackFrameInfo> action, int depthLimit)_ >>>>>> _that takes a callback to be invoked for each frame traversed. A variant_ >>> _of the walkStack method will take a predicate for stack frame filtering._ >>>>>> _Thread.getCaller(Function<StackFrameInfo, R> function)_ >>> _Thread.findCaller(Predicate<StackFrameInfo> predicate,_ >>> _Function<StackFrameInfo, R> function)_ >>>>>> _finds the caller frame with or without filtering._ >>>>>> _Testing_ >>> _-------_ >>>>>> _Unit tests and JCK tests for the new SE API will need to be developed._ >>> _In addition, the performance of the new API for different use cases_ >>> _will be assessed._ >>>>>>>>> _Impact_ >>> _------_ >>>>>> _- Performance/scalability: performance measurement shall be performed_ >>> _using micro-benchmarks as well as real world usage ofgetCallerClass` >>> replaced with the new API. >>>>>> - TCK: New JCK test cases shall be developed. >>>>>>>>>>



More information about the core-libs-dev mailing list