/** * Copyright 2013, Landz and its contributors. All rights reserved. * * 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 z.znr; import z.util.Unsafes; import java.lang.invoke.MethodHandle; import static jnr.x86asm.Asm.*; import static z.znr.MethodHandles.asm; public class Clock { //rdtsc private static final MethodHandle mh_rdtsc = MethodHandles.asm( long.class, // param regs are %rdi, %rsi, %rdx, %rcx, %r8 and %r9 a -> { a.xor_(rax, rax);//need? a.rdtsc(); a.shl(rdx, imm(32)); a.or_(rax, rdx); a.ret(); } ); /** * hardware counter with a small JNI overhead, which may has a larger * instruction throughput than {@link System#nanoTime()} in some * cases. But, please make sure you know all kinds of it's pitfall * (http://lwn.net/Articles/388188/). * <p> * Note: * it is better to use this hardware counter with {@link Affinity}, * although invariant TSC will mitigate this. So only recommend to only use * in the benchmark environment. * <p>see more, http://en.wikipedia.org/wiki/Time_Stamp_Counter and/or Intel * ASDM. */ public static final long rdtsc(){ try { return (long)mh_rdtsc.invokeExact(); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } private static final long ESTIMATED_TSC_FREQUENCY = estimateTSCFrequency(); private static final long TSC_LOADTIME = rdtsc(); private static final long PARK_TIME = 1000_000_000L; //rdtscp private static final MethodHandle mh_rdtscp = MethodHandles.asm( long.class, // param regs are %rdi, %rsi, %rdx, %rcx, %r8 and %r9 a -> { a.xor_(rax, rax);//need? a.rdtscp(); a.shl(rdx, imm(32)); a.or_(rax, rdx); a.ret(); } ); /** * serializing variant of rdtsc. see more {@link #rdtsc()}.<p> * Note: only available for Nehalem+. */ public static final long rdtscp(){ try { return (long)mh_rdtscp.invokeExact(); } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } /** * TODO: only works for invariant TSC? */ public static final long estimateTSCFrequency() { long tsc = rdtsc(); Unsafes.UNSAFE.park(false,PARK_TIME); return rdtsc()-tsc; } /** * Note: there will be less computation if using {@link #tscToNano}. * * @return returned nanoseconds are relative to some time point of the class * {@link Clock} loading. */ public static final long nanoTSCTime(){ try { return ((long)mh_rdtsc.invokeExact() -TSC_LOADTIME) *PARK_TIME/ESTIMATED_TSC_FREQUENCY; } catch (Throwable t) { throw new RuntimeException(t.getMessage()); } } /** * convert TSC number to nanoseconds by estimated TSC frequency */ public static final long tscToNano(long tsc){ return tsc*PARK_TIME/ESTIMATED_TSC_FREQUENCY; } }