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 <[email protected]> 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