Skip to content

Instantly share code, notes, and snippets.

@achille
Last active October 7, 2016 06:36
Show Gist options
  • Save achille/bbf64aa93494fb0b0a4695f6dca636ff to your computer and use it in GitHub Desktop.
Save achille/bbf64aa93494fb0b0a4695f6dca636ff to your computer and use it in GitHub Desktop.
import numpy as np
import scipy.optimize as spo
ir = lambda n: int(round(n))
# Constants
s_freq = 500 #server-server heartbeat frequency ms
c_freq = 10000 #client-server heartbeat frequency ms
# Simulation boundaries
threshold = 300000 # 5 minute max lag/skew
argmin = [0,-threshold,0,0,0,0,0]
argmax = [threshold,threshold,c_freq,c_freq,1000,1000,s_freq]
arglabels = ["True Lag", "Clock skew (Client to Prim)", "Last Primary ping (ms ago)", "Last Secondary ping (ms ago)", "Client Primary latency", "Client Secondary latency", "Last server write (ms ago)"]
res = 1 #simulation resolution in ms
time = threshold * 10 #arbitrary time on the primary (to avoid dealing with negative indexes)
def main():
#Attempt to find global minima using an optimizer
num_iterations = 500
step=2000
interval=10
print("SPO Params: Iter: {}, step: {}, interval:{}".format(num_iterations,step,interval))
result = spo.basinhopping(func=simulate_staleness
,x0= (10,200000,5000 ,3000 ,250 ,250 ,250)
,niter=num_iterations
,minimizer_kwargs = dict(
method="L-BFGS-B"
,bounds = zip(argmin,argmax) )
,stepsize=step
,interval=interval
,disp= True)
print("Server update frequency: {}\n"
"Client update frequency: {}\n"\
"Potential calculation error: {}".format(s_freq,c_freq,abs(round(result.fun))))
print("\nArguments: ")
for i in range(len(arglabels)):
print("val: {} \t {}".format(round(result.x[i]),arglabels[i]))
# Simulate staleness "error" given the absolute true lag, clock skew, and last time P/S were pinged, etc
def simulate_staleness(inputs): #input clobbered into a tuple for optimizer to digest
true_lag, c_clock_skew, last_P_ago, last_S_ago, cp_latency, cs_latency,p_offset = inputs
#Array of reported lastWrite times, reverse order
#first element represents the currently reported lastWrite
#second element represents lastwrite as of 'res' ms ago
p_writes = np.arange(time, time-ir(2.5*threshold),-res) #this is expensive :( but simple to simulate
p_writes -= p_writes % s_freq #truncate to every 500ms resolution
# Offset since last server write happened (anywhere 0-500ms)
p_writes = p_writes[ir(float(p_offset)/res):]
#shift the primary writes to account for lag & latency on secondary
s_offset = ir(float(true_lag)/res)
s_writes = p_writes[s_offset:]
#calculate last updated date from client's frame (ie: absolute time + skew)
s_last_ut = time - last_S_ago + c_clock_skew
p_last_ut = time - last_P_ago + c_clock_skew
#client connects to S and receiving a response last_s_ago
cs_offset = ir(float(last_S_ago+cs_latency)/res)
s_last_w = s_writes[cs_offset] # reported S writeTime at that time
cp_offset = ir(float(last_P_ago+cp_latency)/res)
p_last_w = p_writes[cp_offset] #reported P last_write at that time
lag = (s_last_ut - s_last_w) - (p_last_ut- p_last_w) + c_freq
return -abs(lag-true_lag)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment