java.time.ZoneId.systemDefalut() overhead

Claes Redestad claes.redestad at oracle.com
Sun Feb 22 21:21:43 UTC 2015


Hi Peter,

On 2015-02-22 21:21, Peter Levart wrote:
> Hi,
>
> I noticed internal JDK class java.util.zip.ZipUtils uses deprecated 
> java.util.Date API for implementing two methods for converting DOS to 
> Java time and back. I thought I'd try translating them to use new 
> java.time API. Translation was straightforward, but I noticed that new 
> implementations are not on par with speed to old java.util.Date 
> versions. Here's a JMH benchmark implementing those two conversion 
> methods with java.util.Date and java.time.ZonedDateTime APIs:
>
> http://cr.openjdk.java.net/~plevart/jdk9-dev/ZoneId.systemDefault/ZipUtilsTest.java 
>

https://bugs.openjdk.java.net/browse/JDK-8066644 was filed to fix the 
deprecation warnings of practically identical code in 
jdk/nio/zipfs/ZipUtils.java, maybe this could be fixed at the same time?

I did a similar experiment recently and think I saw better throughput 
going from LocalDateTime to the sufficient second precision via 
toEpochSecond:

-    @SuppressWarnings("deprecation")
      public static long dosToJavaTime(long dtime) {
-        Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
-                          (int)(((dtime >> 21) & 0x0f) - 1),
-                          (int)((dtime >> 16) & 0x1f),
-                          (int)((dtime >> 11) & 0x1f),
-                          (int)((dtime >> 5) & 0x3f),
-                          (int)((dtime << 1) & 0x3e));
-        return d.getTime();
+        LocalDateTime time = LocalDateTime.of((int) (((dtime >> 25) & 
0x7f) + 1980),
+                (int) ((dtime >> 21) & 0x0f),
+                (int) ((dtime >> 16) & 0x1f),
+                (int) ((dtime >> 11) & 0x1f),
+                (int) ((dtime >> 5) & 0x3f),
+                (int) ((dtime << 1) & 0x3e));
+        return 
time.toEpochSecond(ZoneId.systemDefault().getRules().getOffset(time)) * 
1000L;
      }

This avoids a few allocations.

Similarly for the javaToDos case going from an Instant to LocalDateTime 
with a ZoneOffset seemed to win out:

+        Instant instant = Instant.ofEpochMilli(time);
+        LocalDateTime d = LocalDateTime.ofInstant(instant,
+ ZoneOffset.systemDefault().getRules().getOffset(instant));

>
> The results show the following:
>
> Benchmark                               Mode   Samples Score Score 
> error    Units
> j.t.ZipUtilsTest.dosToJavaTime_Date     avgt         5 101.890       
> 17.570    ns/op
> j.t.ZipUtilsTest.dosToJavaTime_ZDT      avgt         5 137.587       
> 13.533    ns/op
> j.t.ZipUtilsTest.javaToDosTime_Date     avgt 5       67.114 10.382    
> ns/op
> j.t.ZipUtilsTest.javaToDosTime_ZDT      avgt         5 143.739       
> 15.243    ns/op
>
>
> Quick sampling with jvisualvm shows that a substantial time is spent 
> repeatedly obtaining ZoneId.systemDefault() instance. I checked the 
> implementation and came up with the following optimization:
>
> http://cr.openjdk.java.net/~plevart/jdk9-dev/ZoneId.systemDefault/webrev.01/ 
>
>
> TimeZone is a mutable object and has to be defensively cloned when 
> TimeZone.getDefault() is invoked. So there's no point in caching a 
> ZoneId instance inside TimeZone instance if we cache it on a clone 
> that is thrown away each time ZoneId.systemDefault() is invoked. I use 
> SharedSecrets to access the uncloned TimeZone.defaultTimeZone instance 
> where caching of ZoneId pays of.
>
> I think that it was never meant to change TimeZone's ID 
> (TimeZone.setID()) after such instance was put into operation (for 
> example installed as default time zone with TimeZone.setDefault()). 
> Such use is unintended and buggy. So I also changed the implementation 
> of TimeZone.setDefault() to save a defensive copy of TimeZone object 
> as default time zone instead of a reference to it.
>
> With this patch, the DOS/Java time conversion benchmark shows an 
> improvement:
>
> Benchmark                               Mode   Samples Score Score 
> error    Units
> j.t.ZipUtilsTest.dosToJavaTime_Date     avgt 5       97.986 18.379    
> ns/op
> j.t.ZipUtilsTest.dosToJavaTime_ZDT      avgt 5       85.010 10.863    
> ns/op
> j.t.ZipUtilsTest.javaToDosTime_Date     avgt 5       71.073 25.408    
> ns/op
> j.t.ZipUtilsTest.javaToDosTime_ZDT      avgt 5       95.298 17.620    
> ns/op
>
>
> Is this patch correct or did I miss something from the internals of 
> java.time API that does not permit such caching?
>

Seems OK to me - perhaps an alternative would be to add a public static 
ZoneId getDefaultZoneId() on TimeZone rather than adding backdoors to 
the getDefaultRef? The caching seems sound, and I guess we don't have to 
worry about making it volatile.

The defensive copy in TimeZone.setDefault() seems like maybe it should 
be a separate bug.

Thanks!

/Claes

>
> Regards, Peter
>




More information about the core-libs-dev mailing list