Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of git+ssh://scm.gforge.inria.fr//gitroot/simgrid/simgrid
[simgrid.git] / contrib / network_model / calibrate_piecewise.py
1 #!/usr/bin/env python
2
3
4 import sys
5 from math import sqrt
6
7
8 if len(sys.argv) < 5:
9    print("Usage : %s datafile links latency bandwidth [size...]" % sys.argv[0])
10    print("where : datafile is a SkaMPI pingpong measurement log file"); 
11    print("        links is the number of links between nodes")
12    print("        latency is the nominal latency given in the platform file")
13    print("        bandwidth is the nominal bandwidth given in the platform file")
14    print("        size are segments limits")
15    sys.exit(-1)
16
17 ##-----------------------------------------
18 ## avg : return average of a list of values
19 ## param l list of values
20 ##-----------------------------------------
21 def avg (l):
22    sum = 0
23    for e in l:
24       sum += float(e);
25    return sum / len(l)
26
27 ##-------------------------------------------------
28 ## cov : covariance
29 ## param X first data vector (..x_i..)
30 ## param Y second data vector (..x_i..)
31 ## = 1/n \Sum_{i=1}^n (x_i - avg(x)) * (y_i - avg(y))
32 ##--------------------------------------------------
33 def cov (X, Y):
34    assert len(X) == len(Y)
35    n = len(X)   #  n=len(X)=len(Y)
36    avg_X = avg(X)
37    avg_Y = avg(Y)
38    S_XY = 0.0
39    for i in range(n):
40       S_XY += (X[i] - avg_X) * (Y[i] - avg_Y)
41    return (S_XY / n)
42
43 ##---------------------------------------------------------------------
44 ## variance : variance
45 ## param X data vector ( ..x_i.. )
46 ## (S_X)^2 = (Sum ( x_i - avg(x) )^2 ) / n
47 ##---------------------------------------------------------------------
48 def variance (X):
49    n = len(X)
50    avg_X = avg (X)
51    S_X2 = 0.0
52    for i in range(n):
53       S_X2 += (X[i] - avg_X) ** 2
54    return (S_X2 / n)
55
56 ##---------------------------------------------------------------------
57 ## calibrate : output correction factors, c_lat on latency, c_bw on bw
58 ## such that bandwidth * c_bw = bw_regr, latency * c_lat = lat_regr
59 ## where bw_regr and lat_regr are the values approximating experimental
60 ## observations.
61 ##
62 ## param links number of links traversed during ping-pong
63 ## param latency as specified on command line, in s
64 ## param bandwidth as specified on command line, in Byte/s
65 ## param sizes vector of data sizes, in Bytes
66 ## param timings vector of time taken: timings[i] for sizes[i], in us
67 ##---------------------------------------------------------------------
68 def calibrate (links, latency, bandwidth, sizes, timings):
69    assert len(sizes) == len(timings)
70    if len(sizes) < 2:
71       return None
72    # compute linear regression : find an affine form  time = a*size+b
73    S_XY = cov(sizes, timings)
74    S_X2 = variance(sizes)
75    a = S_XY / S_X2
76    b = avg(timings) - a * avg(sizes)
77    # corresponding bandwith, in byte/s (was in byte/us in skampi dat)
78    bw_regr = 1e6 / a     
79    # corresponding latency, in s (was in us in skampi dat)
80    lat_regr = b*1e-6
81    print("\nregression: {0} * x + {1}".format(a,b))
82    print("corr_bw = bw_regr/bandwidth= {0}/{1}={2}     lat_regr/(lat_xml*links)={3}/({4}*{5}))".format(bw_regr,bandwidth,bw_regr/bandwidth,lat_regr,latency,links))
83    # return linear regression result and corresponding correction factors c_bw,c_lat
84    return a,b, bw_regr/bandwidth, lat_regr/(latency*links)
85
86
87 ##---------------------------------------------------------------------
88 ## outputs a C formatted conditional return value for factor
89 ##
90 ## param lb lower bound
91 ## param ub upper bound
92 ## param lb_included boolean to tell if bound is included (<=) or exclude (<) 
93 ## param ub_included boolean to tell if bound is included (<=) or exclude (<) 
94 ##---------------------------------------------------------------------
95 def c_code_print (lb,ub, retval, lb_included, ub_included):
96         lb_cmp = ub_cmp = "<"
97         if lb_included:
98                 lb_cmp ="<="
99         if ub_included:
100                 ub_cmp ="<="
101
102         ub_kib=ub/1024.
103         lb_kib=lb/1024.
104         print("\t /* case {0:.1f} KiB {1} size {2} {3:.1f} KiB */".format(lb_kib,lb_cmp,ub_cmp,ub_kib))
105         print("\t if ({0:d} {1}  size && size {2} {3:d}) ".format(lb,lb_cmp,ub_cmp,ub))
106         print("\t       return({0});" . format(retval))
107
108
109 ##-----------------------------------------------------------------------------------------------
110 ## main
111 ##-----------------------------------------------------------------------------------------------
112 links = int(sys.argv[2])
113 latency = float(sys.argv[3])
114 bandwidth = float(sys.argv[4])
115 skampidat = open(sys.argv[1], "r")
116
117 ## read data from skampi logs.
118 timings = []
119 sizes = []
120 readdata =[]
121 for line in skampidat:
122         l = line.split();
123         if line[0] != '#' and len(l) >= 3:   # is it a comment ?
124       ## expected format
125       ## ---------------
126       #count= 8388608  8388608  144916.1       7.6       32  144916.1  143262.0
127       #("%s %d %d %f %f %d %f %f\n" % (countlbl, count, countn, time, stddev, iter, mini, maxi)
128                 readdata.append( (int(l[1]),float(l[3]) / 2) );   # divide by 2 because of ping-pong measured
129
130 ## These may not be sorted so sort it by message size before processing.
131 sorteddata = sorted( readdata, key=lambda pair: pair[0])
132 sizes,timings= zip(*sorteddata)
133
134
135 ## adds message sizes of interest: if values are specified starting from the 6th command line arg 
136 ## and these values are found as message sizes in te log file, add it to the limits list.
137 ## Each of these value si considered a potential inflexion point between two segments.
138 ##
139 ## If no value specified, a single segment is considered from 1st to last message size logged.
140 limits = []
141 if len(sys.argv) > 5:
142    for i in range(5, len(sys.argv)):
143       limits += [idx for idx in range(len(sizes)) if sizes[idx] == int(sys.argv[i])]
144 limits.append(len(sizes) - 1)
145
146 factors = []
147 low = 0
148 for lim in limits:
149    correc = calibrate(links, latency, bandwidth, sizes[low:lim + 1], timings[low:lim + 1])
150    if correc:
151         # save interval [lb,ub] correction, regression line direction and origin
152       # and corresponding correction factors for bw and lat resp. 
153         (dircoef,origin,factor_bw,factor_lat) = correc
154         factors.append( (sizes[low],sizes[lim], dircoef, origin, factor_bw,factor_lat) )
155         print("Segment [%d:%d] --Bandwidth factor=%g --Latency factor=%g " % (sizes[low], sizes[lim], factor_bw,factor_lat))
156    low = lim + 1
157
158 # now computes joining lines between segments
159 joinseg=[]
160
161 print("\n/**\n *------------------ <copy/paste C code snippet in surf/network.c> ----------------------")
162 print(" *\n * produced by: {0}\n *".format(' '.join(sys.argv)))
163 print(" *---------------------------------------------------------------------------------------\n **/")
164
165 # print correction factor for bandwidth for each segment
166 print("static double smpi_bandwidth_factor(double size)\n{")                                
167 for (lb,ub,a,b,factor_bw,factor_lat) in factors:
168         c_code_print(lb,ub,factor_bw,True,True)
169
170         # save ends and starts of segments 
171         if lb != sizes[0]:
172                 joinseg.append( (lb,timings[sizes.index(lb)]) )
173         if ub != sizes[-1]:
174                 joinseg.append( (ub,timings[sizes.index(ub)]) )
175
176 # print correction factor for bandwidth between segments
177 joinseg.reverse()
178 print("\n\t /* ..:: inter-segment corrections ::.. */");
179 inx=len(joinseg)-1
180 while inx>=1:
181         (x0,y0) = joinseg[inx]
182         inx = inx -1
183         (x1,y1) = joinseg[inx]
184         inx = inx -1
185         # line eq. is y = (y1-y0)/(x0-x1) * x +  (y0 x1 - y1 x0)/(x1-x0)
186         a = (y1-y0) / (x1-x0)
187         bw_join = 1e6 / a
188         factor_join_bw = bw_join / bandwidth
189         #print("Joining points (%f,%f) -> (%f,%f)  : line dir : a=%g\n" % (x0,y0,x1,y1,a))
190         c_code_print(x0,x1,factor_join_bw,False,False)
191
192 print("}\n")  
193
194 # print correction factor for latency for each segment
195 print("static double smpi_latency_factor(double size)\n{")                                
196 for (lb,ub,a,b,factor_bw,factor_lat) in factors:
197         c_code_print(lb,ub,factor_lat,True,True)
198
199 print("\n\t /* ..:: inter-segment corrections ::.. */");
200 while joinseg:
201         (x0,y0) = joinseg.pop()
202         (x1,y1) = joinseg.pop()
203         # line eq. is y = (y0-y1)/(x0-x1) * x +  (y0 x1 - y1 x0)/(x1-x0)
204         #print("(%f,%f) -> (%f,%f)\n" % (x0,y0,x1,y1))
205         b = 1e-6 * (y0*x1-y1*x0) / (x1-x0)
206         factor_join_lat = b / (latency*links)
207         c_code_print(x0,x1,factor_join_lat,False,False)
208
209 print("}\n")  
210
211 print("\n/**\n *------------------ <copy/paste C code snippet in surf/network.c> ----------------------\n **/")