CMS 3D CMS Logo

cmsPerfServer.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 from __future__ import print_function
3 from builtins import range
4 import cmsPerfPublish as cspp
5 import cmsPerfSuite as cps
6 import cmsPerfHarvest as cph
7 #G.Benelli
8 import cmsRelValCmd #Module that contains get_cmsDriverOptions() function to get a string with the options we are interested in from cmsDriver_highstats_hlt.txt
9 import cmsCpuInfo #Module that contains get_NumOfCores() function to get an integer with the number of cores on the current machine (through parsing /proc/cpuinfo)
10 from cmsPerfCommons import Candles
11 import optparse as opt
12 import socket, os, sys, SimpleXMLRPCServer, threading, exceptions
13 
14 CandlesString=""
15 for candle in Candles:
16  CandlesString=CandlesString+","+candle
17 print(CandlesString[1:])
18 _outputdir = os.getcwd()
19 _reqnumber = 0
20 _logreturn = False
21 _PROG_NAME = os.path.basename(sys.argv[0])
22 _CASTOR_DIR = "/castor/cern.ch/cms/store/relval/performance/"
23 _DEFAULTS = {"castordir" : _CASTOR_DIR,
24  "perfsuitedir" : os.getcwd(),
25  "TimeSizeEvents" : 100 ,
26  "TimeSizeCandles" : "",
27  "TimeSizePUCandles" : "",
28  "IgProfEvents" : 0 ,
29  "IgProfCandles" : "" ,
30  "IgProfPUCandles" : "" ,
31  "CallgrindEvents" : 0 ,
32  "CallgrindCandles" : "" ,
33  "CallgrindPUCandles" : "" ,
34  "MemcheckEvents" : 0 ,
35  "MemcheckCandles" : "" ,
36  "MemcheckPUCandles" : "" ,
37  "cmsScimark" : 10 ,
38  "cmsScimarkLarge" : 10 ,
39  "cmsdriverOptions" : cmsRelValCmd.get_cmsDriverOptions(), #Get these options automatically now!
40  "stepOptions" : "" ,
41  "quicktest" : False ,
42  "profilers" : "" ,
43  "cpus" : "1" ,
44  "cores" : cmsCpuInfo.get_NumOfCores(), #Get this option automatically
45  "prevrel" : "" ,
46  "isAllCandles" : True ,
47  #"candles" : CandlesString[1:] ,
48  "bypasshlt" : False ,
49  "runonspare" : True ,
50  "logfile" : os.path.join(os.getcwd(),"cmsPerfSuite.log")}
51 
53  global _outputdir
54  parser = opt.OptionParser(usage=("""%s [Options]""" % _PROG_NAME))
55 
56  parser.add_option('-p',
57  '--port',
58  type="int",
59  dest='port',
60  default=8000, #Setting the default port to be 8000
61  help='Run server on a particular port',
62  metavar='<PORT>',
63  )
64 
65  parser.add_option('-o',
66  '--output',
67  type="string",
68  dest='outputdir',
69  default="",
70  help='The output directory for all the cmsPerfSuite runs',
71  metavar='<DIR>',
72  )
73 
74  (options, args) = parser.parse_args()
75 
76  if not options.outputdir == "":
77  options.outputdir = os.path.abspath(options.outputdir)
78  if not os.path.exists(options.outputdir):
79  parser.error("the specified output directory %s does not exist" % options.outputdir)
80  sys.exit()
81  #This seems misleading naming _DEFAULTS, while we are re-initializing its keys to different values as we go...
82  _DEFAULTS["perfsuitedir"] = options.outputdir
83 
84  #resetting global variable _outputdir too... do we really need this variable?
85  _outputdir = options.outputdir
86 
87  return (options.port,options.outputdir)
88 
89 #class ClientThread(threading.Thread):
90  # Overloading the constructor to accept cmsPerfSuite parameters
91 
92 
93 def runserv(port):
94  # Remember that localhost is the loopback network: it does not provide
95  # or require any connection to the outside world. As such it is useful
96  # for testing purposes. If you want your server to be seen on other
97  # machines, you must use your real network address in stead of
98  # 'localhost'.
99  server = None
100  try:
101  server = SimpleXMLRPCServer.SimpleXMLRPCServer((socket.gethostname(),port))
102  server.register_function(request_benchmark)
103  except socket.error as detail:
104  print("ERROR: Could not initialise server:", detail)
105  sys.stdout.flush()
106  sys.exit()
107 
108  print("Running server on port %s... " % port)
109  sys.stdout.flush()
110  while True:
111  try:
112  server.handle_request()
113  sys.stdout.flush()
114  except (KeyboardInterrupt, SystemExit):
115  #cleanup
116  server.server_close()
117  raise
118  except:
119  #cleanup
120  server.server_close()
121  raise
122  server.server_close()
123 
124 #Not sure about this unused function:
125 #Probably left over from first server implementation tests
126 #def runcmd(cmd):
127 # process = os.popen(cmd)
128 # cmdout = process.read()
129 # exitstat = process.close()
130 #
131 # if True:
132 # print cmd
133 # print cmdout
134 #
135 # if not exitstat == None:
136 # sig = exitstat >> 16 # Get the top 16 bits
137 # xstatus = exitstat & 0xffff # Mask out all bits except the bottom 16
138 # raise
139 # return cmdout
140 
141 def readlog(logfile):
142  astr = ""
143  try:
144  for line in open(logfile,"r"):
145  astr += line
146  except (OSError, IOError) as detail:
147  print(detail)
148  return astr
149 
150 def getCPSkeyword(key,dict):
151  if key in dict:
152  return dict[key]
153  else:
154  return _DEFAULTS[key]
155 
156 
158  #This is the function with which the server listens on the given port
159  #cmds is a list of dictionaries: each dictionary is a set of cmsPerfSuite commands to run.
160  #Most common use will be only 1 dictionary, but for testing with reproducibility and statistical errors
161  #one can easily think of sending the same command 10 times for example and then compare the outputs
162  global _outputdir, _reqnumber
163  print("Commands received running perfsuite for these jobs:")
164  print(cmds)
165  sys.stdout.flush()
166  try:
167  # input is a list of dictionaries each defining the
168  # keywords to cmsperfsuite
169  outs = []
170  cmd_num = 0
171  exists = True
172  #Funky way to make sure we create a directory request_n with n = serial request number (if the server is running for a while
173  #and the client submits more than one request
174  #This should never happen since _reqnumber is a global variable on the server side...
175  while exists:
176  topdir = os.path.join(_outputdir,"request_" + str(_reqnumber))
177  exists = os.path.exists(topdir)
178  _reqnumber += 1
179  os.mkdir(topdir)
180  #Going through each command dictionary in the cmds list (usually only 1 such dictionary):
181  for cmd in cmds:
182  curperfdir = os.path.abspath(os.path.join(topdir,str(cmd_num)))
183  if not os.path.exists(curperfdir):
184  os.mkdir(curperfdir)
185  logfile = os.path.join(curperfdir, "cmsPerfSuite.log")
186  if os.path.exists(logfile):
187  logfile = logfile + str(cmd_num)
188  print(cmd)
189  if 'cpus' in cmd:
190  if cmd['cpus'] == "All":
191  print("Running performance suite on all CPUS!\n")
192  cmd['cpus']=""
193  for cpu in range(cmsCpuInfo.get_NumOfCores()):
194  cmd["cpus"]=cmd["cpus"]+str(cpu)+","
195  cmd["cpus"]=cmd["cpus"][:-1] #eliminate the last comma for cleanliness
196  print("I.e. on cpus %s\n"%cmd["cpus"])
197 
198  #Not sure this is the most elegant solution... we keep cloning dictionaries...
199  cmdwdefs = {}
200  cmdwdefs["castordir" ] = getCPSkeyword("castordir" , cmd)
201  cmdwdefs["perfsuitedir" ] = curperfdir
202  cmdwdefs["TimeSizeEvents" ] = getCPSkeyword("TimeSizeEvents" , cmd)
203  cmdwdefs["TimeSizeCandles" ] = getCPSkeyword("TimeSizeCandles" , cmd)
204  cmdwdefs["TimeSizePUCandles" ] = getCPSkeyword("TimeSizePUCandles" , cmd)
205  cmdwdefs["IgProfEvents" ] = getCPSkeyword("IgProfEvents" , cmd)
206  cmdwdefs["IgProfCandles" ] = getCPSkeyword("IgProfCandles" , cmd)
207  cmdwdefs["IgProfPUCandles" ] = getCPSkeyword("IgProfPUCandles" , cmd)
208  cmdwdefs["CallgrindEvents" ] = getCPSkeyword("CallgrindEvents" , cmd)
209  cmdwdefs["CallgrindCandles"] = getCPSkeyword("CallgrindCandles" , cmd)
210  cmdwdefs["CallgrindPUCandles"] = getCPSkeyword("CallgrindPUCandles" , cmd)
211  cmdwdefs["MemcheckEvents" ] = getCPSkeyword("MemcheckEvents" , cmd)
212  cmdwdefs["MemcheckCandles" ] = getCPSkeyword("MemcheckCandles" , cmd)
213  cmdwdefs["MemcheckPUCandles" ] = getCPSkeyword("MemcheckPUCandles" , cmd)
214  cmdwdefs["cmsScimark" ] = getCPSkeyword("cmsScimark" , cmd)
215  cmdwdefs["cmsScimarkLarge" ] = getCPSkeyword("cmsScimarkLarge" , cmd)
216  cmdwdefs["cmsdriverOptions"] = getCPSkeyword("cmsdriverOptions", cmd)
217  cmdwdefs["stepOptions" ] = getCPSkeyword("stepOptions" , cmd)
218  cmdwdefs["quicktest" ] = getCPSkeyword("quicktest" , cmd)
219  cmdwdefs["profilers" ] = getCPSkeyword("profilers" , cmd)
220  cmdwdefs["cpus" ] = getCPSkeyword("cpus" , cmd)
221  cmdwdefs["cores" ] = getCPSkeyword("cores" , cmd)
222  cmdwdefs["prevrel" ] = getCPSkeyword("prevrel" , cmd)
223 # cmdwdefs["candles" ] = getCPSkeyword("candles" , cmd)
224 # cmdwdefs["isAllCandles" ] = len(Candles) == len(cmdwdefs["candles"]) #Dangerous: in the _DEFAULTS version this is a boolean!
225  cmdwdefs["bypasshlt" ] = getCPSkeyword("bypasshlt" , cmd)
226  cmdwdefs["runonspare" ] = getCPSkeyword("runonspare" , cmd)
227  cmdwdefs["logfile" ] = logfile
228  logh = open(logfile,"w")
229  logh.write("This perfsuite run was configured with the following options:\n")
230  #logh.write(str(cmdwdefs) + "\n")
231  for key in cmdwdefs.keys():
232  logh.write(key + "\t" +str(cmdwdefs[key])+"\n")
233  logh.close()
234  print("Calling cmsPerfSuite.main() function\n")
235  cpsInputArgs=[
236  #"-a",cmdwdefs["castordir"],
237  "-t",cmdwdefs["TimeSizeEvents" ],
238  "--RunTimeSize",cmdwdefs["TimeSizeCandles"],
239  "-o",cmdwdefs["perfsuitedir" ],
240  #"-i",cmdwdefs["IgProfEvents" ],
241  #"--RunIgProf",cmdwdefs["RunIgProf" ],
242  #"-c",cmdwdefs["CallgrindEvents" ],
243  #"--RunCallgrind",cmdwdefs["RunCallgrind" ],
244  #"-m",cmdwdefs["MemcheckEvents"],
245  #"--RunMemcheck",cmdwdefs["RunMemcheck"],
246  "--cmsScimark",cmdwdefs["cmsScimark" ],
247  "--cmsScimarkLarge",cmdwdefs["cmsScimarkLarge" ],
248  "--cmsdriver",cmdwdefs["cmsdriverOptions"],
249  "--step",cmdwdefs["stepOptions" ],
250  #"--quicktest",cmdwdefs["quicktest" ],
251  #"--profile",cmdwdefs["profilers" ],
252  "--cpu",cmdwdefs["cpus" ],
253  "--cores",cmdwdefs["cores" ],
254  #"--prevrel",cmdwdefs["prevrel" ],
255  # "--candle",cmdwdefs["candles" ],
256  #"--bypass-hlt",cmdwdefs["bypasshlt" ],
257  "--notrunspare"#,cmdwdefs["runonspare" ]#,
258  #"--logfile",cmdwdefs["logfile" ]
259  ]
260  print(cpsInputArgs)
261  cps.main(cpsInputArgs)
262  print("Running of the Performance Suite is done!")
263  #logreturn is false... so this does not get executed
264  #Maybe we can replace this so that we can have more verbose logging of the server activity
265  if _logreturn:
266  outs.append(readlog(logfile))
267  else:
268  outs.append((cmdwdefs,cph.harvest(curperfdir)))
269  #incrementing the variable for the command number:
270  cmd_num += 1
271 
272 
273  return outs #Not sure what James intended to return here... the contents of all logfiles in a list of logfiles?
274  except exceptions.Exception as detail:
275  # wrap the entire function in try except so we can log the error at client and server
276  logh = open(os.path.join(os.getcwd(),"error.log"),"a")
277  logh.write(str(detail) + "\n")
278  logh.flush()
279  logh.close()
280  print(detail)
281  sys.stdout.flush()
282  raise
283 
284 def _main():
285  print(_DEFAULTS)
286  (port, outputdir) = optionparse()
287  server_thread = threading.Thread(target = runserv(port))
288  server_thread.setDaemon(True) # Allow process to finish if this is the only remaining thread
289  server_thread.start()
290 
291 if __name__ == "__main__":
292  _main()
293 
def readlog(logfile)
def get_NumOfCores()
Definition: cmsCpuInfo.py:7
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def request_benchmark(cmds)
def runserv(port)
def get_cmsDriverOptions()
Definition: cmsRelValCmd.py:13
def getCPSkeyword(key, dict)
#define str(s)