Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use StackWalker to deduce main application class #31665

Closed
GGGGGHT opened this issue Jul 11, 2022 · 4 comments
Closed

Use StackWalker to deduce main application class #31665

GGGGGHT opened this issue Jul 11, 2022 · 4 comments
Labels
status: superseded An issue that has been superseded by another type: task A general task

Comments

@GGGGGHT
Copy link
Contributor

GGGGGHT commented Jul 11, 2022

Recently I am learning new features after jdk9, I saw an interesting feature. Stack-Walking API.
This API allows us to iterator the current stack in a streaming fashion. So I want to use this method to rewrite the deduceMainApplicationClass method. This will make the code look more concise.
This method can be optimized like this:

return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
            .walk((s) -> s.filter(e -> e.getMethodName().equals("main")).findFirst().map(
                StackWalker.StackFrame::getDeclaringClass))
            .orElseThrow(ClassNotFoundException::new);
JMH demo
package com.ggggght.jmh;

import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@Fork(2) @Warmup(iterations = 1, time = 1) @State(Scope.Benchmark)
@BenchmarkMode(value = {Mode.Throughput}) public class StackWalkBench {
    private static final StackDriver STACK_DRIVER = new StackDriver();
    @Param({"50", "100", "200"}) private int initialDepth;

    @Param({"10", "20"}) private int callDepth;

    @Benchmark() public void stackWalkWalk() {
        StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
        List<StackTraceElement> stackTraceElements = walker.walk(
            stackFrameStream -> stackFrameStream.map(StackWalker.StackFrame::toStackTraceElement)
                .collect(Collectors.toList()));
        STACK_DRIVER.deepCall(initialDepth, callDepth, FQCN -> walker.walk(
            s -> s.dropWhile(f -> !f.getClassName().equals(FQCN))
                .dropWhile(f -> f.getClassName().equals(FQCN))
                .findFirst()).get().toStackTraceElement());
    }

    @Benchmark() public void throwableSearch() {
        STACK_DRIVER.deepCall(initialDepth, callDepth, FQCN -> {
            StackTraceElement[] stackTrace = new Throwable().getStackTrace();
            boolean found = false;
            for (int i = 0; i < stackTrace.length; i++) {
                String className = stackTrace[i].getClassName();
                if (FQCN.equals(className)) {
                    found = true;
                    continue;
                }

                if (found && !FQCN.equals(className)) {
                    return stackTrace[i];
                }
            }
            return null;
        });
    }

    public static void main(String[] args) throws RunnerException {
        Options opt =
            new OptionsBuilder().include(StackWalkBench.class.getSimpleName()).build();

        new Runner(opt).run();
    }
}

class StackDriver {
    public StackTraceElement deepCall(int initialDepth, int targetDepth,
        Function<String, StackTraceElement> supplier) {
        if (--initialDepth == 0) {
            Processor processor = new Processor();

            return processor.apply(targetDepth, supplier);
        }

        return deepCall(initialDepth, targetDepth, supplier);
    }

    private static class Processor
        implements BiFunction<Integer, Function<String, StackTraceElement>, StackTraceElement> {
        private static final String FQCN = Processor.class.getName();

        @Override public StackTraceElement apply(Integer depth,
            Function<String, StackTraceElement> function) {
            if (--depth == 0) {
                return function.apply(FQCN);
            }

            return apply(depth, function);
        }
    }
}

Here are the results of a benchmark I did with hotspot17 and jmh. The complete information I put in the file below.
image

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jul 11, 2022
@GGGGGHT
Copy link
Contributor Author

GGGGGHT commented Jul 11, 2022

benchmark.txt

@wilkinsona wilkinsona changed the title Refactor org.springframework.boot.SpringApplication#deduceMainApplicationClass method with jep259 Use StackWalker to deduce main application class Jul 12, 2022
@wilkinsona
Copy link
Member

Thanks very much for the suggestion, @GGGGGHT. Would you like to open a pull request for this change?

@wilkinsona wilkinsona added type: task A general task and removed status: waiting-for-triage An issue we've not yet triaged labels Jul 12, 2022
@wilkinsona wilkinsona added this to the 3.0.x milestone Jul 12, 2022
@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Jul 12, 2022
@GGGGGHT
Copy link
Contributor Author

GGGGGHT commented Jul 13, 2022

Thanks very much for the suggestion, @GGGGGHT. Would you like to open a pull request for this change?

Ofcourse,it's my pleasure.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Jul 13, 2022
@wilkinsona
Copy link
Member

Thank you. I'll close this in favor of your PR.

@wilkinsona wilkinsona closed this as not planned Won't fix, can't repro, duplicate, stale Jul 13, 2022
@wilkinsona wilkinsona added status: superseded An issue that has been superseded by another and removed status: feedback-provided Feedback has been provided labels Jul 13, 2022
@wilkinsona wilkinsona removed this from the 3.0.x milestone Jul 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: superseded An issue that has been superseded by another type: task A general task
Projects
None yet
Development

No branches or pull requests

3 participants