CMS 3D CMS Logo

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