diff options
| author | Bogdan Drutu <bdrutu@google.com> | 2017-03-27 18:38:35 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-03-27 18:38:35 -0700 |
| commit | f58a8560f5eff3119a99188215764342532bf83b (patch) | |
| tree | b5103630949fa579207fd7207efbf9a6814a4218 | |
| parent | cca79a3bb9ec616cd61d763dc37a0430d56784e0 (diff) | |
| download | platform_external_opencensus-java-f58a8560f5eff3119a99188215764342532bf83b.tar.gz platform_external_opencensus-java-f58a8560f5eff3119a99188215764342532bf83b.tar.bz2 platform_external_opencensus-java-f58a8560f5eff3119a99188215764342532bf83b.zip | |
Add a TimestampConverter that can be used to convert nanoTime to Timestamp. (#160)
* Add a TimestampConverter class that can be used to convert nanoTime to Timestamp.
6 files changed, 150 insertions, 18 deletions
diff --git a/core/src/main/java/com/google/instrumentation/common/Timestamp.java b/core/src/main/java/com/google/instrumentation/common/Timestamp.java index c1e736dc..c9c8f2a3 100644 --- a/core/src/main/java/com/google/instrumentation/common/Timestamp.java +++ b/core/src/main/java/com/google/instrumentation/common/Timestamp.java @@ -13,6 +13,8 @@ package com.google.instrumentation.common; +import javax.annotation.concurrent.Immutable; + /** * A representation of an instant in time. The instant is the number of nanoseconds after the number * of seconds since the Unix Epoch. @@ -20,11 +22,13 @@ package com.google.instrumentation.common; * <p>Use {@link TimestampFactory#now} to get the current timestamp since epoch * (1970-01-01T00:00:00Z). */ +@Immutable public final class Timestamp { private static final long MAX_SECONDS = 315576000000L; private static final int MAX_NANOS = 999999999; private static final long NUM_MILLIS_PER_SECOND = 1000L; private static final int NUM_NANOS_PER_MILLI = 1000 * 1000; + private static final long NUM_NANOS_PER_SECOND = NUM_NANOS_PER_MILLI * NUM_MILLIS_PER_SECOND; private final long seconds; private final int nanos; @@ -40,11 +44,9 @@ public final class Timestamp { * * @param seconds Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must * be from from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive. - * * @param nanos Non-negative fractions of a second at nanosecond resolution. Negative * second values with fractions must still have non-negative nanos values that count forward * in time. Must be from 0 to 999,999,999 inclusive. - * * @return new {@link Timestamp} with specified fields. For invalid inputs, a {@link Timestamp} * of zero is returned. */ @@ -59,13 +61,15 @@ public final class Timestamp { } /** - * Creates a new timestamp from given milliseconds. + * Creates a new timestamp from the given milliseconds. + * + * @return a new timestamp from the given milliseconds. */ public static Timestamp fromMillis(long millis) { long seconds = millis / NUM_MILLIS_PER_SECOND; int nanos = (int) (millis % NUM_MILLIS_PER_SECOND) * NUM_NANOS_PER_MILLI; if (nanos < 0) { - return new Timestamp(seconds - 1, MAX_NANOS + nanos + 1); + return new Timestamp(seconds - 1, (int)(nanos + NUM_NANOS_PER_SECOND)); } else { return new Timestamp(seconds, nanos); } @@ -90,6 +94,29 @@ public final class Timestamp { return nanos; } + /** + * Returns a {@code Timestamp} calculated as this {@code Timestamp} plus some number of + * nanoseconds. + * + * @param nanos the nanoseconds to be added to the current timestamp. + * @return a {@code Timestamp} calculated as this {@code Timestamp} plus some number of + * nanoseconds. + */ + public Timestamp addNanos(long nanos) { + long newSeconds = seconds + nanos / NUM_NANOS_PER_SECOND; + nanos %= NUM_NANOS_PER_SECOND; + // Cannot overflow because: abs(nanos) < NUM_NANOS_PER_SECOND AND + // this.nanos < NUM_NANOS_PER_SECOND. + long newNanos = nanos + this.nanos; + newSeconds += (newNanos / NUM_NANOS_PER_SECOND); + newNanos %= NUM_NANOS_PER_SECOND; + if (newNanos >= 0) { + return Timestamp.create(newSeconds, (int) newNanos); + } else { + return Timestamp.create(newSeconds - 1, (int)(newNanos + NUM_NANOS_PER_SECOND)); + } + } + @Override public boolean equals(Object obj) { if (obj == this) { diff --git a/core/src/main/java/com/google/instrumentation/common/TimestampFactory.java b/core/src/main/java/com/google/instrumentation/common/TimestampFactory.java index 27f14f6a..63762a6b 100644 --- a/core/src/main/java/com/google/instrumentation/common/TimestampFactory.java +++ b/core/src/main/java/com/google/instrumentation/common/TimestampFactory.java @@ -38,8 +38,9 @@ public final class TimestampFactory { return HANDLER.timeNow(); } - // This class cannot be final because in case of java8 runtime we can have a better granularity - // timestamp. + /** + * Interface to get the current {@link Timestamp}. + */ interface Handler { Timestamp timeNow(); } diff --git a/core/src/test/java/com/google/instrumentation/common/TimestampTest.java b/core/src/test/java/com/google/instrumentation/common/TimestampTest.java index 1e994def..d41733a7 100644 --- a/core/src/test/java/com/google/instrumentation/common/TimestampTest.java +++ b/core/src/test/java/com/google/instrumentation/common/TimestampTest.java @@ -10,23 +10,19 @@ import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class TimestampTest { @Test - public void testTimestampCreate() { + public void timestampCreate() { assertThat(Timestamp.create(24, 42).getSeconds()).isEqualTo(24); assertThat(Timestamp.create(24, 42).getNanos()).isEqualTo(42); assertThat(Timestamp.create(-24, 42).getSeconds()).isEqualTo(-24); assertThat(Timestamp.create(-24, 42).getNanos()).isEqualTo(42); - assertThat(Timestamp.create(315576000000L, 999999999).getSeconds()) - .isEqualTo(315576000000L); - assertThat(Timestamp.create(315576000000L, 999999999).getNanos()) - .isEqualTo(999999999); - assertThat(Timestamp.create(-315576000000L, 999999999).getSeconds()) - .isEqualTo(-315576000000L); - assertThat(Timestamp.create(-315576000000L, 999999999).getNanos()) - .isEqualTo(999999999); + assertThat(Timestamp.create(315576000000L, 999999999).getSeconds()).isEqualTo(315576000000L); + assertThat(Timestamp.create(315576000000L, 999999999).getNanos()).isEqualTo(999999999); + assertThat(Timestamp.create(-315576000000L, 999999999).getSeconds()).isEqualTo(-315576000000L); + assertThat(Timestamp.create(-315576000000L, 999999999).getNanos()).isEqualTo(999999999); } @Test - public void testTimestampCreateInvalidInput() { + public void timestampCreate_InvalidInput() { assertThat(Timestamp.create(-315576000001L, 0)).isEqualTo(Timestamp.create(0, 0)); assertThat(Timestamp.create(315576000001L, 0)).isEqualTo(Timestamp.create(0, 0)); assertThat(Timestamp.create(1, 1000000000)).isEqualTo(Timestamp.create(0, 0)); @@ -36,20 +32,43 @@ public class TimestampTest { } @Test - public void testTimestampFromMillis() { + public void timestampFromMillis() { assertThat(Timestamp.fromMillis(0)).isEqualTo(Timestamp.create(0, 0)); assertThat(Timestamp.fromMillis(987)).isEqualTo(Timestamp.create(0, 987000000)); assertThat(Timestamp.fromMillis(3456)).isEqualTo(Timestamp.create(3, 456000000)); } @Test - public void testTimestampFromMillisNegative() { + public void timestampFromMillis_Negative() { assertThat(Timestamp.fromMillis(-1)).isEqualTo(Timestamp.create(-1, 999000000)); assertThat(Timestamp.fromMillis(-999)).isEqualTo(Timestamp.create(-1, 1000000)); assertThat(Timestamp.fromMillis(-3456)).isEqualTo(Timestamp.create(-4, 544000000)); } @Test + public void timestampAddNanos() { + Timestamp timestamp = Timestamp.create(1234, 223); + assertThat(timestamp.addNanos(0)).isEqualTo(timestamp); + assertThat(timestamp.addNanos(999999777)).isEqualTo(Timestamp.create(1235, 0)); + assertThat(timestamp.addNanos(1300200500)).isEqualTo(Timestamp.create(1235, 300200723)); + assertThat(timestamp.addNanos(1999999777)).isEqualTo(Timestamp.create(1236, 0)); + assertThat(timestamp.addNanos(9876543789L)).isEqualTo(Timestamp.create(1243, 876544012)); + assertThat(timestamp.addNanos(Long.MAX_VALUE)) + .isEqualTo(Timestamp.create(1234L + 9223372036L, 223 + 854775807)); + } + + @Test + public void timestampAddNanos_Negative() { + Timestamp timestamp = Timestamp.create(1234, 223); + assertThat(timestamp.addNanos(-223)).isEqualTo(Timestamp.create(1234, 0)); + assertThat(timestamp.addNanos(-1000000223)).isEqualTo(Timestamp.create(1233, 0)); + assertThat(timestamp.addNanos(-1300200500)).isEqualTo(Timestamp.create(1232, 699799723)); + assertThat(timestamp.addNanos(-4123456213L)).isEqualTo(Timestamp.create(1229, 876544010)); + assertThat(timestamp.addNanos(Long.MIN_VALUE)) + .isEqualTo(Timestamp.create(1234L - 9223372036L - 1, 223 + 145224192)); + } + + @Test public void testTimestampEqual() { // Positive tests. assertThat(Timestamp.create(0, 0)).isEqualTo(Timestamp.create(0, 0)); diff --git a/core_impl/build.gradle b/core_impl/build.gradle index 531a1037..c2137d16 100644 --- a/core_impl/build.gradle +++ b/core_impl/build.gradle @@ -6,5 +6,7 @@ dependencies { libraries.disruptor, libraries.guava + testCompile project(':instrumentation-java-core') + signature "org.codehaus.mojo.signature:java16:+@signature" } diff --git a/core_impl/src/main/java/com/google/instrumentation/trace/TimestampConverter.java b/core_impl/src/main/java/com/google/instrumentation/trace/TimestampConverter.java new file mode 100644 index 00000000..92a76b8d --- /dev/null +++ b/core_impl/src/main/java/com/google/instrumentation/trace/TimestampConverter.java @@ -0,0 +1,50 @@ +/* + * Copyright 2017, Google Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.instrumentation.trace; + +import com.google.common.annotations.VisibleForTesting; +import com.google.instrumentation.common.Timestamp; +import com.google.instrumentation.common.TimestampFactory; +import javax.annotation.concurrent.Immutable; + +/** + * This class provides a mechanism for converting {@link System#nanoTime() nanoTime} values to + * {@link Timestamp}. + */ +@Immutable +final class TimestampConverter { + private final Timestamp timestamp; + private final long nanoTime; + + // Returns a WallTimeConverter initialized to now. + static TimestampConverter now() { + return new TimestampConverter(TimestampFactory.now(), System.nanoTime()); + } + + /** + * Converts a {@link System#nanoTime() nanoTime} value to {@link Timestamp}. + * + * @param nanoTime value to convert. + * @return the {@code Timestamp} representation of the {@code time}. + */ + Timestamp convertNanoTime(long nanoTime) { + return timestamp.addNanos(nanoTime - this.nanoTime); + } + + @VisibleForTesting + TimestampConverter(Timestamp timestamp, long nanoTime) { + this.timestamp = timestamp; + this.nanoTime = nanoTime; + } +} diff --git a/core_impl/src/test/java/com/google/instrumentation/trace/TimestampConverterTest.java b/core_impl/src/test/java/com/google/instrumentation/trace/TimestampConverterTest.java new file mode 100644 index 00000000..fbbb43ad --- /dev/null +++ b/core_impl/src/test/java/com/google/instrumentation/trace/TimestampConverterTest.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017, Google Inc. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.instrumentation.trace; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.instrumentation.common.Timestamp; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link TimestampConverter}. */ +@RunWith(JUnit4.class) +public class TimestampConverterTest { + @Test + public void convertNanoTime() { + Timestamp timestamp = Timestamp.create(1234, 5678); + TimestampConverter timeConverter = new TimestampConverter(timestamp, 2345); + assertThat(timeConverter.convertNanoTime(1234)).isEqualTo(timestamp.addNanos(-1111)); + assertThat(timeConverter.convertNanoTime(3456)).isEqualTo(timestamp.addNanos(1111)); + } +} |
