log4j
This tests are done using log4j version 1.2.9, and java version: 1.4.2_05.
Refer to the results in org.apache.log4j.performance.Logging for other tests
If you are reading log4j docs for example log4j.PatternLayout
you already noticed statements like this:
WARNING Generating the caller class information is slow. Thus, it's use should be avoided unless execution speed is not an issue.
So I decided to measure how slow it is and also I'm suggesting the way to make it faster. Since for me execution speed is an issue and I'd like to see caller information.
Looking at current log4j code you will see that the function call LoggingEvent.getLocationInformation(); is the common way to receive the location information. Lest get the numbers for this calls assuming it the really expensive function.
public interface PseudoLogger { public abstract LocationInfo getLocationInfo(); } public class Log4jWay implements PseudoLogger { protected final String fqnOfCategoryClass = this.getClass().getName(); public LocationInfo getLocationInfo() { return new LocationInfo(new Throwable(), fqnOfCategoryClass); } } public class Java14Way implements PseudoLogger { protected final String fqnOfCategoryClass = this.getClass().getName(); public LocationInfo getLocationInfo() { return new Java14LocationInfo(new Throwable(), fqnOfCategoryClass); } } /** * The test in nutshell */ public double measureLog(PseudoLogger aLog) throws Exception { // Timer start for (int i = 0; i < 1000; ++ i) { li = aLog.getLocationInfo(); li.getFileName(); li.getLineNumber(); li.getClassName(); li.getMethodName(); } // Timer end return time / 1000 }
The class LocationInfoPerformance is used to measure the speed of this method. You could see the full code in CVS
Java1.4Way it based on Java14LocationInfo (extends LocationInfo) and gets the stack using java 1.4 Throwable.getStackTrace()
Experimental results average duration of call returned by measureLog are listed below in units of milliseconds. Accuracy 10%.
java version: 1.4.2_05.
System | OS | StackSize | Log4jWay | Java1.4Way |
AMD Athlon 1.2 GHz | XP-sp2 | 5 | 0.138 | 0.060 |
- | - | 15 | 0.300 | 0.130 |
- | - | 25 | 0.500 | 0.200 |
Intel P4 2.6 GHz Hyper-Threading | XP-sp2 | 5 | 0.098 | 0.038 |
- | - | 15 | 0.210 | 0.073 |
- | - | 25 | 0.370 | 0.120 |
So class Java14LocationInfo proves to be two times faster
Lets get to real tests.
Experimental results average duration of calls to log.debug listed below in units of milliseconds. Accuracy 10%.
java version: 1.4.2_05.
This test use: org.apache.log4j.RollingFileAppender
StackSize ~10
1) ConversionPattern1 "%d \t %m \n"
2) ConversionPattern2 "%d \t %L %m \n"
//FileAppenderNoLI.xml <appender name="file-appender" class="org.apache.log4j.RollingFileAppender"> <param name="File" value="clientTests_NoLI.log"/> <param name="Append" value="true"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="NoLI %d \t %m \n" /> </layout> </appender> //FileAppenderLI.xml <appender name="file-appender" class="org.apache.log4j.RollingFileAppender"> <param name="File" value="clientTests_LI.log"/> <param name="Append" value="true"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="LI %d \t %L %m \n" /> </layout> </appender>
3) The last test is actually a hack. I just changed the log4j.spi.LoggingEvent class to see how it goes.
public LocationInfo getLocationInformation() { if(locationInfo == null) { //locationInfo = new LocationInfo(new Throwable(), fqnOfCategoryClass); locationInfo = new net.sf.jour.log4j.Java14LocationInfo(new Throwable(), fqnOfCategoryClass); } return locationInfo; }
System | OS | 1) No caller location | 2) Include caller location | 3) Include caller location use Java1.4 |
AMD Athlon 1.2 GHz | XP-sp2 | 0.020 | 0.440 | 0.191 |
Intel P4 2.6 GHz Hyper-Threading | XP-sp2 | 0.019 | 0.320 | 0.130 |
So again class Java14LocationInfo proves to be two times faster.
This is numbers for J2EE application Weblogic + JRun running on Intel P4 2.6 GHz M$ Windows XP. DB is remote
In one of the tests Log4j patch has been applied LoggingEvent and
LocationInfo.
When I have priority value="info" the application runs 10% faster.
If PatternLayout does not include location information the performance is nearly the same as debug OFF.
For Java 1.4 version of LocationInfo all the difference I could see is 1-2% but this could be described by the accuracy of the test.
Definitely more performance tests should be done to prove that changes to LocationInfo should be done.
It would be nice to extend next version for log4j 1.3.0 with support for java 1.4. Or allow to customize LocationInfo class.
Classes WrapedLocationInfo and
Java14LocationInfo are just the examples.
They allow log4j to run on JVM before 1.4.
Converting LocationInfo to the Interface and using different implementation would be excellent.
Another way to improve performance is to make StackSize smaller. This is to call new Throwable() in constructor of LoggingEvent when it is know that this event will need LocationInformation. And build LocationInfo base on this Throwable later on when really required.
public LoggingEvent(....) { .... if (level.isGreaterOrEqual(Level.DEBUG)) { this.throwableInfo = new ThrowableInformation(throwable); } } public LocationInfo getLocationInformation() { if(locationInfo == null) { // vlads test patch. if (level.isGreaterOrEqual(Level.DEBUG)) { locationInfo = new LocationInfo(this.throwable, fqnOfCategoryClass); //locationInfo = new net.sf.jour.log4j.Java14LocationInfo(this.throwable, fqnOfCategoryClass); } else { locationInfo = new LocationInfo(new Throwable(), fqnOfCategoryClass); //locationInfo = new net.sf.jour.log4j.Java14LocationInfo(new Throwable(), fqnOfCategoryClass); } } return locationInfo; }
<logger name="co.myproject.hot"> <level value="DEBUG" /> <getLocationInformationForDebug value = "true"/> <appender-ref ref="file-appender"/> </logger> <root> <getLocationInformationForDebug value = "true"/> .. </root>
This modification | 1) No caller location | 2) Include caller location | 3) Include caller location use Java1.4 |
before | 0.020 | 0.440 | 0.191 |
after | 0.030 | 0.260 | 0.121 |