2020-03-20 22:03:52 +00:00
# Constantine
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
# ############################################################
#
# Benchmark of finite fields
#
# ############################################################
import
# Internals
2020-07-24 20:02:30 +00:00
.. / constantine / config / [ curves , common ] ,
2020-03-20 22:03:52 +00:00
.. / constantine / arithmetic ,
2020-04-14 00:05:42 +00:00
.. / constantine / towers ,
2020-03-20 22:03:52 +00:00
# Helpers
2020-04-15 19:24:18 +00:00
.. / helpers / [ prng_unsafe , static_for ] ,
. / platforms ,
2020-03-20 22:03:52 +00:00
# Standard library
std / [ monotimes , times , strformat , strutils , macros ]
var rng : RngState
let seed = uint32 ( getTime ( ) . toUnix ( ) and ( 1 'i64 shl 32 - 1 ) ) # unixTime mod 2^32
rng . seed ( seed )
2020-03-21 01:31:31 +00:00
echo " bench xoshiro512** seed: " , seed
2020-03-20 22:03:52 +00:00
# warmup
proc warmup * ( ) =
# Warmup - make sure cpu is on max perf
let start = cpuTime ( )
var foo = 123
for i in 0 .. < 300_000_000 :
foo + = i * i mod 456
foo = foo mod 789
# Compiler shouldn't optimize away the results as cpuTime rely on sideeffects
let stop = cpuTime ( )
echo & " Warmup: {stop - start:>4.4f} s, result {foo} (displayed to avoid compiler optimizing warmup away) \n "
warmup ( )
when defined ( gcc ) :
echo " \n Compiled with GCC "
elif defined ( clang ) :
echo " \n Compiled with Clang "
elif defined ( vcc ) :
echo " \n Compiled with MSVC "
elif defined ( icc ) :
echo " \n Compiled with ICC "
else :
echo " \n Compiled with an unknown compiler "
2020-07-24 20:02:30 +00:00
echo " Optimization level => "
echo " no optimization: " , not defined ( release )
echo " release: " , defined ( release )
echo " danger: " , defined ( danger )
echo " inline assembly: " , UseX86ASM
2020-04-15 19:24:18 +00:00
when ( sizeof ( int ) = = 4 ) or defined ( Constantine32 ) :
echo " ⚠️ Warning: using Constantine with 32-bit limbs "
else :
echo " Using Constantine with 64-bit limbs "
when SupportsCPUName :
echo " Running on " , cpuName ( ) , " "
when SupportsGetTicks :
echo " \n ⚠️ Cycles measurements are approximate and use the CPU nominal clock: Turbo-Boost and overclocking will skew them. "
echo " i.e. a 20% overclock will be about 20% off (assuming no dynamic frequency scaling) "
echo " \n ================================================================================================================= \n "
2020-03-20 22:03:52 +00:00
2020-04-15 17:38:02 +00:00
proc separator * ( ) =
2020-06-17 20:44:52 +00:00
echo " - " . repeat ( 145 )
2020-04-15 17:38:02 +00:00
2020-03-20 22:03:52 +00:00
proc report ( op , field : string , start , stop : MonoTime , startClk , stopClk : int64 , iters : int ) =
2020-04-15 17:38:02 +00:00
let ns = inNanoseconds ( ( stop - start ) div iters )
let throughput = 1 e9 / float64 ( ns )
2020-06-04 20:09:30 +00:00
when SupportsGetTicks :
2020-06-17 20:44:52 +00:00
echo & " {op:<50} {field:<18} {throughput:>15.3f} ops/s {ns:>9} ns/op {(stopClk - startClk) div iters:>9} CPU cycles (approx) "
2020-06-04 20:09:30 +00:00
else :
2020-06-17 20:44:52 +00:00
echo & " {op:<50} {field:<18} {throughput:>15.3f} ops/s {ns:>9} ns/op "
2020-03-20 22:03:52 +00:00
2020-07-24 20:02:30 +00:00
proc notes * ( ) =
echo " Notes: "
echo " - Compilers: "
echo " Compilers are severely limited on multiprecision arithmetic. "
echo " Inline Assembly is used by default (nimble bench_fp). "
echo " Bench without assembly can use \" nimble bench_fp_gcc \" or \" nimble bench_fp_clang \" . "
echo " GCC is significantly slower than Clang on multiprecision arithmetic due to catastrophic handling of carries. "
echo " - The simplest operations might be optimized away by the compiler. "
echo " - Fast Squaring and Fast Multiplication are possible if there are spare bits in the prime representation (i.e. the prime uses 254 bits out of 256 bits) "
2020-03-20 22:03:52 +00:00
macro fixFieldDisplay ( T : typedesc ) : untyped =
# At compile-time, enums are integers and their display is buggy
# we get the Curve ID instead of the curve name.
let instantiated = T . getTypeInst ( )
var name = $ instantiated [ 1 ] [ 0 ] # Fp
name . add " [ " & $ Curve ( instantiated [ 1 ] [ 1 ] . intVal ) & " ] "
result = newLit name
template bench ( op : string , T : typedesc , iters : int , body : untyped ) : untyped =
let start = getMonotime ( )
2020-06-04 20:09:30 +00:00
when SupportsGetTicks :
let startClk = getTicks ( )
2020-03-20 22:03:52 +00:00
for _ in 0 .. < iters :
body
2020-06-04 20:09:30 +00:00
when SupportsGetTicks :
let stopClk = getTicks ( )
2020-03-20 22:03:52 +00:00
let stop = getMonotime ( )
2020-06-04 20:09:30 +00:00
when not SupportsGetTicks :
let startClk = - 1 'i64
let stopClk = - 1 'i64
2020-03-20 22:03:52 +00:00
report ( op , fixFieldDisplay ( T ) , start , stop , startClk , stopClk , iters )
2020-03-21 01:31:31 +00:00
proc addBench * ( T : typedesc , iters : int ) =
2020-04-15 00:12:45 +00:00
var x = rng . random_unsafe ( T )
let y = rng . random_unsafe ( T )
2020-03-21 01:31:31 +00:00
bench ( " Addition " , T , iters ) :
2020-03-20 22:03:52 +00:00
x + = y
2020-03-21 01:31:31 +00:00
proc subBench * ( T : typedesc , iters : int ) =
2020-04-15 00:12:45 +00:00
var x = rng . random_unsafe ( T )
let y = rng . random_unsafe ( T )
2020-03-20 22:03:52 +00:00
preventOptimAway ( x )
2020-03-21 01:31:31 +00:00
bench ( " Substraction " , T , iters ) :
2020-03-20 22:03:52 +00:00
x - = y
2020-03-21 01:31:31 +00:00
proc negBench * ( T : typedesc , iters : int ) =
2020-03-20 22:03:52 +00:00
var r : T
2020-04-15 00:12:45 +00:00
let x = rng . random_unsafe ( T )
2020-03-21 01:31:31 +00:00
bench ( " Negation " , T , iters ) :
2020-03-20 22:03:52 +00:00
r . neg ( x )
2020-03-21 01:31:31 +00:00
proc mulBench * ( T : typedesc , iters : int ) =
2020-03-20 22:03:52 +00:00
var r : T
2020-04-15 00:12:45 +00:00
let x = rng . random_unsafe ( T )
let y = rng . random_unsafe ( T )
2020-03-20 22:03:52 +00:00
preventOptimAway ( r )
2020-03-21 01:31:31 +00:00
bench ( " Multiplication " , T , iters ) :
2020-03-20 22:03:52 +00:00
r . prod ( x , y )
2020-03-21 01:31:31 +00:00
proc sqrBench * ( T : typedesc , iters : int ) =
2020-03-20 22:03:52 +00:00
var r : T
2020-04-15 00:12:45 +00:00
let x = rng . random_unsafe ( T )
2020-03-20 22:03:52 +00:00
preventOptimAway ( r )
2020-03-21 01:31:31 +00:00
bench ( " Squaring " , T , iters ) :
2020-03-20 22:03:52 +00:00
r . square ( x )
2020-03-21 01:31:31 +00:00
proc invBench * ( T : typedesc , iters : int ) =
2020-03-20 22:03:52 +00:00
var r : T
2020-04-15 00:12:45 +00:00
let x = rng . random_unsafe ( T )
2020-03-20 22:03:52 +00:00
preventOptimAway ( r )
2020-06-17 20:44:52 +00:00
bench ( " Inversion (constant-time Euclid) " , T , iters ) :
2020-03-20 22:03:52 +00:00
r . inv ( x )
2020-06-17 20:44:52 +00:00
proc powFermatInversionBench * ( T : typedesc , iters : int ) =
let x = rng . random_unsafe ( T )
bench ( " Inversion via exponentiation p-2 (Little Fermat) " , T , iters ) :
var r = x
r . powUnsafeExponent ( T . C . getInvModExponent ( ) )
proc sqrtBench * ( T : typedesc , iters : int ) =
let x = rng . random_unsafe ( T )
bench ( " Square Root + square check (constant-time) " , T , iters ) :
var r = x
discard r . sqrt_if_square ( )
proc powBench * ( T : typedesc , iters : int ) =
let x = rng . random_unsafe ( T )
let exponent = rng . random_unsafe ( BigInt [ T . C . getCurveOrderBitwidth ( ) ] )
bench ( " Exp curve order (constant-time) - " & $ exponent . bits & " -bit " , T , iters ) :
var r = x
r . pow ( exponent )
proc powUnsafeBench * ( T : typedesc , iters : int ) =
let x = rng . random_unsafe ( T )
let exponent = rng . random_unsafe ( BigInt [ T . C . getCurveOrderBitwidth ( ) ] )
bench ( " Exp curve order (Leak exponent bits) - " & $ exponent . bits & " -bit " , T , iters ) :
var r = x
r . powUnsafeExponent ( exponent )