[
https://issues.apache.org/jira/browse/LOG4J2-1415?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15318186#comment-15318186
]
Anthony Maire commented on LOG4J2-1415:
---------------------------------------
I don't think the way the "switch" is implemented as a major impact on
performance
I made a small JMH benchmark, running on a Xeon E5-2643 v3 with JVM 1.8.0_92
(same kind of results on my desktop with a core i7 2600) and the cost of
instanceof is barely noticeable (and less than the class name switch)
{noformat}
Benchmark Mode Cnt Score Error Units
SwitchClassTest.referenceWithCast avgt 25 1958.885 ± 7.773 ns/op
SwitchClassTest.referenceWithToString avgt 25 2050.443 ± 10.347 ns/op
SwitchClassTest.useClassName avgt 25 2015.931 ± 10.190 ns/op
SwitchClassTest.useInstanceOf avgt 25 1978.622 ± 10.030 ns/op
{noformat}
Here is the benchmark code:
{code}
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
@Warmup(iterations=5)
@Measurement(iterations=5)
@Fork(value=5)
public class SwitchClassTest {
private static final String STRING_CLASS_NAME = "java.lang.String";
private static final String CHARACTER_CLASS_NAME =
"java.lang.Character";
private static final String LONG_CLASS_NAME = "java.lang.Long";
private static final String INTEGER_CLASS_NAME = "java.lang.Integer";
private static final String BOOLEAN_CLASS_NAME = "java.lang.Boolean";
private static final String DOUBLE_CLASS_NAME = "java.lang.Double";
private static final String FLOAT_CLASS_NAME = "java.lang.Float";
private Object[] params = new Object[]{"abc", 'a', Long.MAX_VALUE,
Integer.MAX_VALUE, Double.MAX_VALUE, Float.MAX_VALUE, Boolean.TRUE};
private StringBuilder sb = new StringBuilder();
@Benchmark
public int referenceWithToString() {
for (Object param : params) {
sb.append(param);
}
int size = sb.length();
sb.setLength(0);
return size;
}
@Benchmark
public int referenceWithCast() {
sb.append(params[0]);
sb.append(((Character) params[1]).charValue());
sb.append(((Long) params[2]).longValue());
sb.append(((Integer) params[3]).intValue());
sb.append(((Double) params[4]).doubleValue());
sb.append(((Float) params[5]).floatValue());
sb.append(((Boolean) params[6]).booleanValue());
int size = sb.length();
sb.setLength(0);
return size;
}
@Benchmark
public int useInstanceOf() {
for (Object param : params) {
if (param instanceof String) {
sb.append(param);
} else if (param instanceof Character) {
sb.append(((Character) param).charValue());
} else if (param instanceof Long) {
sb.append(((Long) param).longValue());
} else if (param instanceof Integer) {
sb.append(((Integer) param).intValue());
} else if (param instanceof Double) {
sb.append(((Double) param).doubleValue());
} else if (param instanceof Float) {
sb.append(((Float) param).floatValue());
} else if (param instanceof Boolean) {
sb.append(((Boolean) param).booleanValue());
}
}
int size = sb.length();
sb.setLength(0);
return size;
}
@Benchmark
public int useClassName() {
for (Object param : params) {
String className = param.getClass().getName();
switch (className){
case STRING_CLASS_NAME:
sb.append(param);
break;
case CHARACTER_CLASS_NAME:
sb.append(((Character) param).charValue());
break;
case LONG_CLASS_NAME:
sb.append(((Long) param).longValue());
break;
case INTEGER_CLASS_NAME:
sb.append(((Integer) param).intValue());
break;
case DOUBLE_CLASS_NAME:
sb.append(((Double) param).doubleValue());
break;
case FLOAT_CLASS_NAME:
sb.append(((Float) param).floatValue());
break;
case BOOLEAN_CLASS_NAME:
sb.append(((Boolean) param).booleanValue());
break;
}
}
int size = sb.length();
sb.setLength(0);
return size;
}
}
{code}
> Avoid calling toString() on auto-boxed primitive message parameters
> -------------------------------------------------------------------
>
> Key: LOG4J2-1415
> URL: https://issues.apache.org/jira/browse/LOG4J2-1415
> Project: Log4j 2
> Issue Type: Improvement
> Affects Versions: 2.6
> Reporter: Anthony Maire
> Priority: Minor
>
> When using Log4j 2 through the SLF4J binding, the Unboxer mecanism is not
> available and a parameterized message with a primitive type parameter will be
> auto-boxed.
> Then this boxed value will be formatted by
> ParameterFormatter.recursiveDeepToString() and further allocations will happen
> To lower allocation rate for SLF4J users,
> ParameterFormatter.appendSpecialTypes() should handle boxed primitive types
> too.
> {code}
> private static boolean appendSpecialTypes(final Object o, final StringBuilder
> str) {
> ...
> } else if (o instanceof Long) {
> str.append(((Long) o).longValue());
> return true;
> } else if (o instanceof Integer) {
> str.append(((Integer) o).intValue());
> return true;
> } else if (o instanceof Double) {
> str.append(((Double) o).doubleValue());
> return true;
> } // similarly for float, short, boolean and char.
> ...
> }
> {code}
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]