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

Improve performance of getOperationName #16

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

loicmathieu
Copy link

I recently performance load test on an application using the java interceptor to send traces to Jaeger.
Inside a performance profile, I saw a high cost (3% total CPU cost, but more than 60% of span creation+start+finish time) for the getOperationMethod due to the usage of a StringFormatter.

I did some small experiment with JHM, and using a StringBuilder with an initial capacity seems a better option (10x quicker). As creating span occurs in the hot path of an application, I think it's a good thing to remove this hotspot.

I try several approach, this seems to be the better. We can go with simple string concatenation if the code seems too complex, as since Java 9 (and the string concatenation improvement) it is as performant as using a StringBuilder.

Here is my JMH benchmark

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
public class StringFormatVsJoinerVsBuilderVsConcat {

    private Method method;

    @Setup
    public void setup() throws NoSuchMethodException {
        method = TestClass.class.getMethod("testMethod");
    }

    @Benchmark
    public String stringFormat() {
        return String.format("%s.%s", method.getDeclaringClass().getName(), method.getName());
    }

    @Benchmark
    public String stringJoiner() {
        StringJoiner stringJoiner = new StringJoiner(".");
        stringJoiner.add(method.getDeclaringClass().getName());
        stringJoiner.add(method.getName());
        return stringJoiner.toString();
    }

    @Benchmark
    public String stringBuilder() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(method.getDeclaringClass().getName());
        stringBuilder.append('.');
        stringBuilder.append(method.getName());
        return stringBuilder.toString();
    }

    @Benchmark
    public String stringBuilderWithCapacity() {
        int capacity = method.getDeclaringClass().getName().length() + method.getName().length() + 1;
        StringBuilder stringBuilder = new StringBuilder(capacity);
        stringBuilder.append(method.getDeclaringClass().getName());
        stringBuilder.append('.');
        stringBuilder.append(method.getName());
        return stringBuilder.toString();
    }

    @Benchmark
    public String stringConcat() {
        return method.getDeclaringClass().getName() + '.' + method.getName();
    }

    public static class TestClass {
        public void testMethod() {
            //do nothing here
        }
    }
}

And the result on my laptop (Linux - Java 11 - 6 cores)

Benchmark                                                        Mode  Cnt    Score    Error  Units
StringFormatVsJoinerVsBuilderVsConcat.stringBuilder              avgt    5   59,093 ±  6,031  ns/op
StringFormatVsJoinerVsBuilderVsConcat.stringBuilderWithCapacity  avgt    5   40,480 ±  3,536  ns/op
StringFormatVsJoinerVsBuilderVsConcat.stringConcat               avgt    5   60,190 ±  5,230  ns/op
StringFormatVsJoinerVsBuilderVsConcat.stringFormat               avgt    5  543,775 ± 35,095  ns/op
StringFormatVsJoinerVsBuilderVsConcat.stringJoiner               avgt    5   62,161 ±  2,027  ns/op

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant