There is cost to examine the stack frames. The StackWalker API allows
you to fetch the stack frames one batch at a time to avoid unnecessary
deoptimization to frames that are not traversed. In addition,it can
specify to include/exclude the hidden frames and/or reflection
implementation-specific frames.
It is true that there is more setup to do for StackWalker to count the
frames. It's possible to provide a specialized stack walker
implementation to optimize getting the stack depth where the object
allocation can be eliminated (e.g. StackWalker::getCallerClass uses a
specialized implementation for performance). However, the stack depth
is just a workaround for you.
BTW, you can call Stream::count to count the stack frames:
StackWalker.getInstance().walk(s -> { return s.count(); })
Mandy
On 10/24/19 9:32 AM, seth lytle wrote:
The use case that's always interested me is checking to see if a
callback to a recursive method (eg during parsing) is "too deep" so
you can bail out (eg, to a non-recursive one or using message
passing). For that purpose, it's already suspended and the native
method is close to what I'd like if it wasn't deprecated.
You started this discussion by claiming that "The StackWalker API is a
much better solution for code that is interested in the number of
stack frames". Seems like a benchmark is a critical part of that
claim. The stack walker approach looked 8x-ish slower for deep stacks
(eg, 1000 and 5000), which is about what I expected given all the
unnecessary object allocations. The walker API also seemed more prone
to stack overflows, but I didn't take the time to quantify that.
Here's one example run (java 11 with defaults):
Benchmark (stackDepth) Mode Cnt Score Error Units
StackWalkerJmh.count 1000 avgt 3 0.030 ± 0.002 ms/op
StackWalkerJmh.count 5000 avgt 3 0.151 ± 0.015 ms/op
Benchmark (stackDepth) Mode Cnt Score Error Units
StackWalkerJmh.walk 1000 avgt 3 0.261 ± 0.027 ms/op
StackWalkerJmh.walk 5000 avgt 3 1.313 ± 1.131 ms/op
@Benchmark
public int walk() { return recStackWalker(stackDepth); }
private static int recStackWalker(int depth) {
return depth == 0 ? getWalker() : recStackWalker(depth-1);
}
private static int getWalker() {
Count cc = new Count();
StackWalker.getInstance().forEach(x -> cc.count++);
return cc.count;
}
static class Count { int count; }
@Benchmark
public int count() { return recStackTrace(stackDepth); }
private static int recStackTrace(int depth) {
return depth == 0 ? getDepth() : recStackTrace(depth-1);
}
private static int getDepth() {
return Thread.currentThread().countStackFrames();
}
What would be even more useful than stack depth would be an estimate
of the number of bytes remaining in the stack, esp if it was fast. Any
chance that that could get added to the stack walker API ?
On Thu, Oct 24, 2019 at 4:21 AM Alan Bateman <alan.bate...@oracle.com> wrote:
On 23/10/2019 23:00, seth lytle wrote:
At least a couple appear to be recently active, though I don't have
current access. Maybe an IDE generates boilerplate for proxies and
ignores deprecation ?
is the speed of the StackWalker approach to counting frames comparable
to the current native method ?
countStackFrames has always been ill-defined, and it requires the thread
to be suspended. We've been directly people to StackWalker and several
releases so best to try it yourself and come back with your results/issues.
-Alan