I am using 

openjdk version "11.0.10" 2021-01-19 LTS
OpenJDK Runtime Environment Corretto-11.0.10.9.1 (build 11.0.10+9-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.10.9.1 (build 11.0.10+9-LTS, mixed mode)

Our test uses
<dependency>
  <groupId>com.google.code.java-allocation-instrumenter</groupId>
  <artifactId>java-allocation-instrumenter</artifactId>
  <version>3.3.0</version>
</dependency>
to validate that it is not allocating any objects.

If you want to test it yourself you can do

git clone https://github.com/apache/logging-log4j2.git 
<https://github.com/apache/logging-log4j2.git>
cd logging-log4j2
mvn -DskipTests=true clean install
cd log4j-core
mvn surefire:test -Dtest=GcFreeSynchronousLoggingTest 
-Dmaven.surefire.debug="-Dlog4j2.usePreciseClock=true”

When it fails you will see a strange message with 

I just allocated the object 2021-04-06T21:55:20.878377Z of type 
java/time/Instant whose size is 24 ==> expected: <true> but was: <false>

Ralph

> On Apr 6, 2021, at 9:53 AM, Peter Levart <peter.lev...@gmail.com> wrote:
> 
> Hi Ralph,
> 
> 
> Which version of JDK did you try running the code. I tried the following 
> benchmark:
> 
> 
> @BenchmarkMode(Mode.AverageTime)
> @Fork(value = 1)
> @Warmup(iterations = 5, time = 1)
> @Measurement(iterations = 10, time = 1)
> @OutputTimeUnit(TimeUnit.NANOSECONDS)
> @State(Scope.Benchmark)
> public class InstantBench {
> 
>     @Benchmark
>     public long epochMilli() {
>         Instant instant = Clock.systemUTC().instant();
>         return instant.toEpochMilli();
>     }
> }
> 
> 
> And didn't get any heap allocation on either JDK 11:
> 
> 
> Benchmark Mode  Cnt   Score    Error   Units
> InstantBench.epochMilli                      avgt   10  34.722 ±  0.328   
> ns/op
> InstantBench.epochMilli:·gc.alloc.rate       avgt   10  ≈ 10⁻⁴           
> MB/sec
> InstantBench.epochMilli:·gc.alloc.rate.norm  avgt   10  ≈ 10⁻⁵             
> B/op
> InstantBench.epochMilli:·gc.count            avgt   10     ≈ 0           
> counts
> 
> 
> ..nor on JDK 16:
> 
> 
> Benchmark Mode  Cnt   Score    Error   Units
> InstantBench.epochMilli                      avgt   10  33.612 ±  0.258   
> ns/op
> InstantBench.epochMilli:·gc.alloc.rate       avgt   10  ≈ 10⁻⁴           
> MB/sec
> InstantBench.epochMilli:·gc.alloc.rate.norm  avgt   10  ≈ 10⁻⁵             
> B/op
> InstantBench.epochMilli:·gc.count            avgt   10     ≈ 0           
> counts
> 
> 
> Regards, Peter
> 
> On 4/6/21 8:17 AM, Ralph Goers wrote:
>> Yes, I am aware that the Instant is constructed from the two values. That is 
>> exactly why I was hoping I could pass in an object where the values of those 
>> two fields could be injected. This would still allow Instant to be immutable 
>> but allow Log4j to update one of the pre-existing Clock instances it is 
>> managing. That would require that a new Interface be defined with the two 
>> set methods and a new static method in the Clock class.
>> 
>> Getting the value in microseconds would probably be a middle ground that 
>> could also work considering that is the best resolution available on most 
>> hardware today.
>> 
>> Whichever is implemented I suspect getting it back ported to Java 11 is 
>> unlikely? According to the surveys I’ve seen the majority of users are still 
>> on Java 8. Given that, I’d be surprised if there is a mad rush to adopt Java 
>> 17 very soon. Given where things are I’m not even sure how likely it is this 
>> could make it in for Java 17.  The irony here is that the folks who need to 
>> run garbage free are also the ones most likely to need a Clock with higher 
>> resolution. Right now they can’t have both.
>> 
>> Ralph
>> 
>>> On Apr 5, 2021, at 1:26 PM, Roger Riggs <roger.ri...@oracle.com> wrote:
>>> 
>>> Hi,
>>> 
>>> Java does not have a data type with enough resolution to hold a full 
>>> nanosecond value.
>>> Hence the implementation of Instant holding seconds and nanos.
>>> 
>>> There is an long dormant enhancement request to return micro-seconds as a 
>>> long.
>>> 8196003 <https://bugs.openjdk.java.net/browse/JDK-8196003> java.time 
>>> Instant and Duration methods for microseconds
>>> 
>>> That might be useful if the application gets enough resolution from 
>>> microseconds.
>>> There might be some clever interpolation between System.currentTimeMillis()
>>> and adjusting with System.nanoTime().
>>> Though it would likely not be exactly synchronized with the values from 
>>> Instant.
>>> 
>>> Regards, Roger
>>> 
>>> 
>>> On 4/5/21 3:56 PM, Brian Goetz wrote:
>>>> Project Valhalla will allow Instant to be migrated to a primitive class, 
>>>> which would address your problem.
>>>> 
>>>> On 4/2/2021 7:47 PM, Ralph Goers wrote:
>>>>> Log4j 2 supports the notion of a PreciseClock - one that can be 
>>>>> initialized to something more precise than a millisecond. At the same 
>>>>> time it also supports running with no heap allocations in certain 
>>>>> circumstances. I am in the process of moving our master branch to require 
>>>>> Java 11 as the minimum. In doing so I am encountering unit test errors 
>>>>> while verifying that logging is garbage free. They all occur allocating 
>>>>> an Instant.
>>>>> 
>>>>> The code we have simply does
>>>>> 
>>>>> public void init(MutableInstant mutableInstant) {
>>>>>      Instant instant = java.time.Clock.systemUTC().instant();
>>>>> mutableInstant.initFromEpochSecond(instant.getEpochSecond(), 
>>>>> instant.getNano());
>>>>> }
>>>>> In our previous tests we had thought the allocation was being eliminated 
>>>>> due to escape analysis since the data is being extracted from the Instant 
>>>>> and not passed along. However, after upgrading the Google test library 
>>>>> and the JDK version it appears that is not the case.
>>>>> Ideally we would really like something like
>>>>> 
>>>>> public void init(MutableInstant mutableInstant) {
>>>>>         java.time.Clock.systemUTC().initInstant(mutableInstant);
>>>>> }
>>>>> 
>>>>> where Mutable instant would implement an interface that has the two set 
>>>>> methods.The method would execute the same logic that is in the instant() 
>>>>> method but instead of creating a new Instant it would call the set 
>>>>> methods for the provided object.
>>>>> 
>>>>> This would allow us to either have the MutableInstants in ThreadLocals or 
>>>>> some other mechanism to ensure they are thread safe and have no heap 
>>>>> allocations. As it stands now I see no way to gain access to the higher 
>>>>> precision clock without memory allocation.
>>>>> 
>>>>> Do you know of another way to do this? Am I missing something?
>>>>> 
>>>>> Ralph
>>> 
>> 
> 

Reply via email to