CMS 3D CMS Logo

cmsPerfServer.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 import cmsPerfPublish as cspp
00003 import cmsPerfSuite      as cps
00004 import cmsPerfHarvest    as cph
00005 #G.Benelli
00006 import cmsRelValCmd #Module that contains get_cmsDriverOptions() function to get a string with the options we are interested in from cmsDriver_highstats_hlt.txt
00007 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)
00008 from cmsPerfCommons import Candles
00009 import optparse as opt
00010 import socket, os, sys, SimpleXMLRPCServer, threading, exceptions
00011 
00012 CandlesString=""
00013 for candle in Candles:
00014     CandlesString=CandlesString+","+candle
00015 print CandlesString[1:]
00016 _outputdir  = os.getcwd()
00017 _reqnumber  = 0
00018 _logreturn  = False
00019 _PROG_NAME  = os.path.basename(sys.argv[0])
00020 _CASTOR_DIR = "/castor/cern.ch/cms/store/relval/performance/"
00021 _DEFAULTS   = {"castordir"        : _CASTOR_DIR,
00022                "perfsuitedir"     : os.getcwd(),
00023                "TimeSizeEvents"   : 100        ,
00024                "TimeSizeCandles"      : "",
00025                "TimeSizePUCandles"      : "",
00026                "IgProfEvents"     : 0          ,
00027                "IgProfCandles"        : ""       ,
00028                "IgProfPUCandles"        : ""       ,
00029                "CallgrindEvents"  : 0          ,
00030                "CallgrindCandles"     : ""       ,
00031                "CallgrindPUCandles"     : ""       ,
00032                "MemcheckEvents"   : 0          ,
00033                "MemcheckCandles"      : ""          ,
00034                "MemcheckPUCandles"      : ""          ,
00035                "cmsScimark"       : 10         ,
00036                "cmsScimarkLarge"  : 10         ,
00037                "cmsdriverOptions" : cmsRelValCmd.get_cmsDriverOptions(), #Get these options automatically now!
00038                "stepOptions"      : ""         ,
00039                "quicktest"        : False      ,
00040                "profilers"        : ""         ,
00041                "cpus"             : "1"        ,
00042                "cores"            : cmsCpuInfo.get_NumOfCores(), #Get this option automatically
00043                "prevrel"          : ""         ,
00044                "isAllCandles"     : True       ,
00045                #"candles"          : CandlesString[1:]    ,
00046                "bypasshlt"        : False      ,
00047                "runonspare"       : True       ,
00048                "logfile"          : os.path.join(os.getcwd(),"cmsPerfSuite.log")}
00049 
00050 def optionparse():
00051     global _outputdir
00052     parser = opt.OptionParser(usage=("""%s [Options]""" % _PROG_NAME))
00053 
00054     parser.add_option('-p',
00055                       '--port',
00056                       type="int",
00057                       dest='port',
00058                       default=8000, #Setting the default port to be 8000
00059                       help='Run server on a particular port',
00060                       metavar='<PORT>',
00061                       )
00062     
00063     parser.add_option('-o',
00064                       '--output',
00065                       type="string",
00066                       dest='outputdir',
00067                       default="",
00068                       help='The output directory for all the cmsPerfSuite runs',
00069                       metavar='<DIR>',
00070                       )
00071 
00072     (options, args) = parser.parse_args()
00073 
00074     if not options.outputdir == "":
00075         options.outputdir = os.path.abspath(options.outputdir)
00076         if not os.path.exists(options.outputdir):
00077             parser.error("the specified output directory %s does not exist" % options.outputdir)
00078             sys.exit()
00079         #This seems misleading naming _DEFAULTS, while we are re-initializing its keys to different values as we go...
00080         _DEFAULTS["perfsuitedir"] = options.outputdir
00081 
00082     #resetting global variable _outputdir too... do we really need this variable?
00083     _outputdir = options.outputdir
00084 
00085     return (options.port,options.outputdir)
00086 
00087 #class ClientThread(threading.Thread):
00088     # Overloading the constructor to accept cmsPerfSuite parameters
00089     
00090 
00091 def runserv(port):
00092     # Remember that localhost is the loopback network: it does not provide
00093     # or require any connection to the outside world. As such it is useful
00094     # for testing purposes. If you want your server to be seen on other
00095     # machines, you must use your real network address in stead of
00096     # 'localhost'.
00097     server = None
00098     try:
00099         server = SimpleXMLRPCServer.SimpleXMLRPCServer((socket.gethostname(),port))
00100         server.register_function(request_benchmark)
00101     except socket.error, detail:
00102         print "ERROR: Could not initialise server:", detail
00103         sys.stdout.flush()        
00104         sys.exit()
00105 
00106     print "Running server on port %s... " % port
00107     sys.stdout.flush()    
00108     while True:
00109         try:
00110             server.handle_request()
00111             sys.stdout.flush()
00112         except (KeyboardInterrupt, SystemExit):
00113             #cleanup
00114             server.server_close()            
00115             raise
00116         except:
00117             #cleanup
00118             server.server_close()
00119             raise
00120     server.server_close()        
00121 
00122 #Not sure about this unused function:
00123 #Probably left over from first server implementation tests
00124 #def runcmd(cmd):
00125 #    process  = os.popen(cmd)
00126 #    cmdout   = process.read()
00127 #    exitstat = process.close()
00128 #
00129 #    if True:
00130 #        print cmd
00131 #        print cmdout
00132 #
00133 #    if not exitstat == None:
00134 #        sig     = exitstat >> 16    # Get the top 16 bits
00135 #        xstatus = exitstat & 0xffff # Mask out all bits except the bottom 16
00136 #        raise
00137 #    return cmdout
00138 
00139 def readlog(logfile):
00140     astr = ""    
00141     try:
00142         for line in open(logfile,"r"):
00143             astr += line
00144     except (OSError, IOError) , detail:
00145         print detail
00146     return astr
00147 
00148 def getCPSkeyword(key,dict):
00149     if dict.has_key(key):
00150         return dict[key]
00151     else:
00152         return _DEFAULTS[key]
00153 
00154 
00155 def request_benchmark(cmds):
00156     #This is the function with which the server listens on the given port
00157     #cmds is a list of dictionaries: each dictionary is a set of cmsPerfSuite commands to run.
00158     #Most common use will be only 1 dictionary, but for testing with reproducibility and statistical errors
00159     #one can easily think of sending the same command 10 times for example and then compare the outputs
00160     global _outputdir, _reqnumber
00161     print "Commands received running perfsuite for these jobs:"
00162     print cmds
00163     sys.stdout.flush()
00164     try:
00165         # input is a list of dictionaries each defining the
00166         #   keywords to cmsperfsuite
00167         outs = []
00168         cmd_num = 0
00169         exists = True
00170         #Funky way to make sure we create a directory request_n with n = serial request number (if the server is running for a while
00171         #and the client submits more than one request
00172         #This should never happen since _reqnumber is a global variable on the server side...
00173         while exists:
00174             topdir = os.path.join(_outputdir,"request_" + str(_reqnumber))
00175             exists = os.path.exists(topdir)
00176             _reqnumber += 1
00177         os.mkdir(topdir)
00178         #Going through each command dictionary in the cmds list (usually only 1 such dictionary):
00179         for cmd in cmds:
00180             curperfdir = os.path.abspath(os.path.join(topdir,str(cmd_num)))
00181             if not os.path.exists(curperfdir):
00182                 os.mkdir(curperfdir)
00183             logfile = os.path.join(curperfdir, "cmsPerfSuite.log")
00184             if os.path.exists(logfile):
00185                 logfile = logfile + str(cmd_num)
00186             print cmd
00187             if cmd.has_key('cpus'):
00188                 if cmd['cpus'] == "All":
00189                     print "Running performance suite on all CPUS!\n"
00190                     cmd['cpus']=""
00191                     for cpu in range(cmsCpuInfo.get_NumOfCores()):
00192                         cmd["cpus"]=cmd["cpus"]+str(cpu)+","
00193                     cmd["cpus"]=cmd["cpus"][:-1] #eliminate the last comma for cleanliness 
00194                     print "I.e. on cpus %s\n"%cmd["cpus"]
00195                 
00196             #Not sure this is the most elegant solution... we keep cloning dictionaries...
00197             cmdwdefs = {}
00198             cmdwdefs["castordir"       ] = getCPSkeyword("castordir"       , cmd)
00199             cmdwdefs["perfsuitedir"    ] = curperfdir                      
00200             cmdwdefs["TimeSizeEvents"  ] = getCPSkeyword("TimeSizeEvents"  , cmd)
00201             cmdwdefs["TimeSizeCandles" ] = getCPSkeyword("TimeSizeCandles"  , cmd)
00202             cmdwdefs["TimeSizePUCandles" ] = getCPSkeyword("TimeSizePUCandles"  , cmd)
00203             cmdwdefs["IgProfEvents"    ] = getCPSkeyword("IgProfEvents"    , cmd)
00204             cmdwdefs["IgProfCandles"   ] = getCPSkeyword("IgProfCandles"    , cmd)
00205             cmdwdefs["IgProfPUCandles"   ] = getCPSkeyword("IgProfPUCandles"    , cmd)
00206             cmdwdefs["CallgrindEvents" ] = getCPSkeyword("CallgrindEvents"  , cmd)
00207             cmdwdefs["CallgrindCandles"] = getCPSkeyword("CallgrindCandles"  , cmd)
00208             cmdwdefs["CallgrindPUCandles"] = getCPSkeyword("CallgrindPUCandles"  , cmd)
00209             cmdwdefs["MemcheckEvents"  ] = getCPSkeyword("MemcheckEvents"  , cmd)
00210             cmdwdefs["MemcheckCandles" ] = getCPSkeyword("MemcheckCandles"  , cmd)
00211             cmdwdefs["MemcheckPUCandles" ] = getCPSkeyword("MemcheckPUCandles"  , cmd)
00212             cmdwdefs["cmsScimark"      ] = getCPSkeyword("cmsScimark"      , cmd)
00213             cmdwdefs["cmsScimarkLarge" ] = getCPSkeyword("cmsScimarkLarge" , cmd)
00214             cmdwdefs["cmsdriverOptions"] = getCPSkeyword("cmsdriverOptions", cmd)
00215             cmdwdefs["stepOptions"     ] = getCPSkeyword("stepOptions"     , cmd)
00216             cmdwdefs["quicktest"       ] = getCPSkeyword("quicktest"       , cmd)
00217             cmdwdefs["profilers"       ] = getCPSkeyword("profilers"       , cmd)
00218             cmdwdefs["cpus"            ] = getCPSkeyword("cpus"            , cmd)
00219             cmdwdefs["cores"           ] = getCPSkeyword("cores"           , cmd)
00220             cmdwdefs["prevrel"         ] = getCPSkeyword("prevrel"         , cmd)
00221 #            cmdwdefs["candles"         ] = getCPSkeyword("candles"         , cmd)                                    
00222 #            cmdwdefs["isAllCandles"    ] = len(Candles) == len(cmdwdefs["candles"]) #Dangerous: in the _DEFAULTS version this is a boolean!
00223             cmdwdefs["bypasshlt"       ] = getCPSkeyword("bypasshlt"       , cmd)
00224             cmdwdefs["runonspare"      ] = getCPSkeyword("runonspare"      , cmd)
00225             cmdwdefs["logfile"         ] = logfile
00226             logh = open(logfile,"w")
00227             logh.write("This perfsuite run was configured with the following options:\n")
00228             #logh.write(str(cmdwdefs) + "\n")
00229             for key in cmdwdefs.keys():
00230                 logh.write(key + "\t" +str(cmdwdefs[key])+"\n")
00231             logh.close()
00232             print "Calling cmsPerfSuite.main() function\n"
00233             cpsInputArgs=[
00234                       #"-a",cmdwdefs["castordir"],
00235                       "-t",cmdwdefs["TimeSizeEvents"  ],
00236                       "--RunTimeSize",cmdwdefs["TimeSizeCandles"],
00237                       "-o",cmdwdefs["perfsuitedir"    ],
00238                       #"-i",cmdwdefs["IgProfEvents"    ],
00239                       #"--RunIgProf",cmdwdefs["RunIgProf"    ],
00240                       #"-c",cmdwdefs["CallgrindEvents"  ],
00241                       #"--RunCallgrind",cmdwdefs["RunCallgrind"  ],
00242                       #"-m",cmdwdefs["MemcheckEvents"],
00243                       #"--RunMemcheck",cmdwdefs["RunMemcheck"],
00244                       "--cmsScimark",cmdwdefs["cmsScimark"      ],
00245                       "--cmsScimarkLarge",cmdwdefs["cmsScimarkLarge" ],
00246                       "--cmsdriver",cmdwdefs["cmsdriverOptions"],
00247                       "--step",cmdwdefs["stepOptions"     ],
00248                       #"--quicktest",cmdwdefs["quicktest"       ],
00249                       #"--profile",cmdwdefs["profilers"       ],
00250                       "--cpu",cmdwdefs["cpus"            ],
00251                       "--cores",cmdwdefs["cores"           ],
00252                       #"--prevrel",cmdwdefs["prevrel"         ],
00253  #                     "--candle",cmdwdefs["candles"         ],
00254                       #"--bypass-hlt",cmdwdefs["bypasshlt"       ],
00255                       "--notrunspare"#,cmdwdefs["runonspare"      ]#,
00256                       #"--logfile",cmdwdefs["logfile"         ]
00257                       ]
00258             print cpsInputArgs
00259             cps.main(cpsInputArgs)
00260             print "Running of the Performance Suite is done!"          
00261             #logreturn is false... so this does not get executed
00262             #Maybe we can replace this so that we can have more verbose logging of the server activity
00263             if _logreturn:
00264                 outs.append(readlog(logfile))
00265             else:
00266                 outs.append((cmdwdefs,cph.harvest(curperfdir)))
00267             #incrementing the variable for the command number:
00268             cmd_num += 1
00269 
00270             
00271         return outs #Not sure what James intended to return here... the contents of all logfiles in a list of logfiles?
00272     except exceptions.Exception, detail:
00273         # wrap the entire function in try except so we can log the error at client and server
00274         logh = open(os.path.join(os.getcwd(),"error.log"),"a")
00275         logh.write(str(detail) + "\n")
00276         logh.flush()
00277         logh.close()
00278         print detail
00279         sys.stdout.flush()
00280         raise
00281 
00282 def _main():
00283     print _DEFAULTS
00284     (port, outputdir) = optionparse()
00285     server_thread = threading.Thread(target = runserv(port))
00286     server_thread.setDaemon(True) # Allow process to finish if this is the only remaining thread
00287     server_thread.start()
00288 
00289 if __name__ == "__main__":
00290     _main()
00291 

Generated on Tue Jun 9 17:49:26 2009 for CMSSW by  doxygen 1.5.4