github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/bench/qpc/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"syscall"
     6  	"time"
     7  	"unsafe"
     8  )
     9  
    10  // precision timing
    11  var (
    12  	modkernel32                   = syscall.NewLazyDLL("kernel32.dll")
    13  	procQueryPerformanceFrequency = modkernel32.NewProc("QueryPerformanceFrequency")
    14  	procQueryPerformanceCounter   = modkernel32.NewProc("QueryPerformanceCounter")
    15  )
    16  
    17  func asmQPC() int64
    18  
    19  var (
    20  	_QueryPerformanceFrequency uintptr
    21  	_QueryPerformanceCounter   uintptr
    22  )
    23  
    24  type stdFunction unsafe.Pointer
    25  
    26  // now returns time.Duration using queryPerformanceCounter
    27  func QPC() int64 {
    28  	var now int64
    29  	syscall.Syscall(procQueryPerformanceCounter.Addr(), 1, uintptr(unsafe.Pointer(&now)), 0, 0)
    30  	return now
    31  }
    32  
    33  // now returns time.Duration using queryPerformanceCounter
    34  func QPC2() int64 {
    35  	var now int64
    36  	syscall.SyscallN(procQueryPerformanceCounter.Addr(), uintptr(unsafe.Pointer(&now)))
    37  	return now
    38  }
    39  
    40  // QPCFrequency returns frequency in ticks per second
    41  func QPCFrequency() int64 {
    42  	var freq int64
    43  	r1, _, _ := syscall.Syscall(procQueryPerformanceFrequency.Addr(), 1, uintptr(unsafe.Pointer(&freq)), 0, 0)
    44  	if r1 == 0 {
    45  		panic("call failed")
    46  	}
    47  	return freq
    48  }
    49  
    50  func main() {
    51  	_QueryPerformanceFrequency = procQueryPerformanceFrequency.Addr()
    52  	_QueryPerformanceCounter = procQueryPerformanceCounter.Addr()
    53  	const N = 10000000
    54  
    55  	{
    56  		start := QPC()
    57  		for i := 0; i < N; i++ {
    58  			QPC()
    59  		}
    60  		finish := QPC()
    61  		fmt.Println("QPC", delta(finish, start)/N)
    62  	}
    63  
    64  	{
    65  		start := QPC()
    66  		for i := 0; i < N; i++ {
    67  			QPC2()
    68  		}
    69  		finish := QPC()
    70  		fmt.Println("QPC2", delta(finish, start)/N)
    71  	}
    72  
    73  	{
    74  		start := QPC()
    75  		for i := 0; i < N; i++ {
    76  			asmQPC()
    77  		}
    78  
    79  		finish := QPC()
    80  		fmt.Println("asmQPC", delta(finish, start)/N)
    81  		fmt.Println("check", asmQPC()-QPC())
    82  	}
    83  
    84  	{
    85  		start := QPC()
    86  		for i := 0; i < N; i++ {
    87  			time.Now()
    88  		}
    89  		finish := QPC()
    90  		fmt.Println("time.Now", delta(finish, start)/N)
    91  	}
    92  }
    93  
    94  func delta(a, b int64) time.Duration {
    95  	return time.Duration(a-b) * time.Second / (time.Duration(QPCFrequency()) * time.Nanosecond)
    96  }