Hi Jason,

Yes, the code was mentioned in SLF4J PR 271.

The benchmark can be found at

https://github.com/ceki/logback-perf/tree/master/src/main/java/ch/qos/logback/perf/caller

Here is the gist of the StackWalker variant:

public class CallerCompute {

    static private StackWalker WALKER = StackWalker.getInstance();

    static public String getCallerClass(int depth) {

        List<StackFrame> frames = WALKER.walk(s -> s.limit(4).toList());
        .... process the returned frames
    }
}

The above executes at around 1.8 microseconds per call whereas the code
in LogRecord.getSourceClassName() executes at 5 microseconds per call.
The cost of LogRecord constructor is negligible at around 25 nanoseconds.

Anyway, thank you for the suggestion.

--
Ceki


On 4/7/2022 12:27 AM, Jason Mehrens wrote:
> Ceki,
> 
> Looks like the benchmark code is from https://github.com/qos-ch/slf4j/pull/271
> 
> Looks like the benchmark code is doing a collection so perhaps that is some 
> of the performance hit?
> Have you benchmarked java.util.LogRecord.getSourceClassName() to compare with 
> your StackWalker benchmark?
> 
> https://github.com/openjdk/jdk/blob/master/src/java.logging/share/classes/java/util/logging/LogRecord.java#L754
> 
> Jason
> 
> ________________________________________
> From: core-libs-dev <core-libs-dev-r...@openjdk.java.net> on behalf of Ceki 
> Gülcü <c...@qos.ch>
> Sent: Wednesday, April 6, 2022 4:26 PM
> To: core-libs-dev
> Subject: Re: fast way to infer caller
> 
> 
> Hi Rémi,
> 
> Thank you for your answer.
> 
> According to some benchmarks on a i7-8565U Intel CPU (quite average
> CPU), here are the costs of computing the caller class via different
> methods:
> 
> using new Throwable().getStackTrace: 11 microseconds per call
> using StackWalker API: 1.8 microseconds per call
> using SecurityManager: 0.9 microseconds per call
> 
> While a six fold improvement (StackWalker compared to new Thorowable) is
> nothing to sneeze at, the performance of StackWalker is not as good as
> with a custom SecurityManager.
> 
> I have not said so explicitly but the aim here is to allow the user to
> obtain a new logger by calling LoggerFactory.getLogger() with no
> arguments with the returned logger named after the caller class.
> 
> Spending 1 or 2 microseconds for this call is OK if the logger is a
> static field. However, if the logger is an instance field, then spending
> 2 microseconds per host object instance just to obtain a logger might
> have a noticeable impact on performance. It follows that the performance
> of LoggerFactory.getLogger() must be exceptionally good, assuming we
> wish to avoid having the user accidentally shooting herself on the foot,
> ergo the 100 nanosecond performance per call requirement.
> 
> Noting that invoking MethodHandles.lookup().lookupClass() seems very
> fast (about 2 nanoseconds), I would be very interested if  new
> lookup(int index) method were added to java.lang.invoke.MethodHandles
> class, with index designating the desired index on the call stack.
> 
> Does the above make sense? How difficult would it be to add such a method?
> 
> --
> Ceki Gülcü
> 
> 
> On 4/6/2022 5:52 PM, Remi Forax wrote:
>> ----- Original Message -----
>>> From: "Ceki Gülcü" <c...@qos.ch>
>>> To: "core-libs-dev" <core-libs-dev@openjdk.java.net>
>>> Sent: Wednesday, April 6, 2022 5:30:51 PM
>>> Subject: fast way to infer caller
>>
>>> Hello,
>>
>> Hello,
>>
>>>
>>> As you are probably aware, one of the important primitives used in
>>> logging libraries is inferring the caller of a given logging statement.
>>> The current common practice is to create a throwable and process its
>>> stack trace. This is rather wasteful and rather slow. As an alternative,
>>> I have tried using the StackWalker API to infer the caller but was
>>> unsatisfied with the performance.
>>>
>>> MethodHandles.lookup().lookupClass() looks very promising except that
>>> there is no way to specify the depth.
>>>
>>> I am looking for a method to obtain the Nth caller at a cost of around
>>> 100 to 200 nanoseconds of CPU time.  Do you think the JDK could cater
>>> for this use case?
>>
>> We have designed the StackWalker with that in mind
>> https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StackWalker.html
>>
>> see the discussion on StackWalker.getCallerClass()
>> https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StackWalker.html#getCallerClass()
>>
> 

Reply via email to