1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283# 2 "backoff.ml"(****************************************************************************)(* *)(* OxCaml *)(* *)(* Copyright (c) 2015, Théo Laurent <theo.laurent@ens.fr> *)(* Copyright (c) 2015, KC Sivaramakrishnan <sk826@cl.cam.ac.uk> *)(* Copyright (c) 2023, Vesa Karvonen <vesa.a.j.k@gmail.com> *)(* *)(* Permission to use, copy, modify, and/or distribute this software for any *)(* purpose with or without fee is hereby granted, provided that the above *)(* copyright notice and this permission notice appear in all copies. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *)(* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *)(* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *)(* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *)(* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *)(* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *)(* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *)(* *)(****************************************************************************)typet=intexternalis_runtime5:unit->bool@@portable="%runtime5"externalpoll:unit->unit@@portable="%poll"letcpu_relax=ifis_runtime5()thenDomain.cpu_relaxelsepollletrecommended_domain_count=ifis_runtime5()thenDomain.recommended_domain_countelsefun()->1letsingle_mask=Bool.to_int(recommended_domain_count()=1)-1letbits=5letmax_wait_log=30(* [Random.bits] returns 30 random bits. *)letmask=(1lslbits)-1letcreate?(lower_wait_log=4)?(upper_wait_log=17)()=assert(0<=lower_wait_log&&lower_wait_log<=upper_wait_log&&upper_wait_log<=max_wait_log);(upper_wait_loglsl(bits*2))lor(lower_wait_loglslbits)lorlower_wait_logletget_upper_wait_logbackoff=backofflsr(bits*2)letget_lower_wait_logbackoff=(backofflsrbits)landmaskletget_wait_logbackoff=backofflandmaskletresetbackoff=letlower_wait_log=get_lower_wait_logbackoffinbackofflandlnotmasklorlower_wait_log(* We don't want [once] to be inlined. This may avoid code bloat. *)let[@inlinenever]oncebackoff=(* We call [Random.bits] first. In this case this helps to reduce register
pressure so that fewer words will be allocated from the stack. *)lett=Random.bits()inletwait_log=get_wait_logbackoffinletwait_mask=(1lslwait_log)-1in(* We use a ref and a countdown while-loop (uses one variable) instead of a
for-loop (uses two variables) to reduce register pressure. Local ref does
not allocate with native compiler. *)lett=ref(tlandwait_masklandsingle_mask)inwhile0<=!tdocpu_relax();t:=!t-1done;letupper_wait_log=get_upper_wait_logbackoffin(* We recompute [wait_log] to reduce register pressure. *)letwait_log=get_wait_logbackoffin(* [Bool.to_int] generates branchless code, this reduces branch predictor
pressure and generates shorter code. *)letnext_wait_log=wait_log+Bool.to_int(wait_log<upper_wait_log)inbackoff-wait_log+next_wait_logletdefault=create()