#!/usr/bin/env python # #Copyright (c) 2009, Perforce Software, Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #******************************************************************************* # #Author: Stephen Moon #Date: April 27, 2012 # #Summary: A program to test the performance of a Perforce Server on Linux # # The program runs "changes -i, files, sync, flush, integrate, obliterate, etc." # against a server which does not have archived files. # # The program is not meant to replace the existing performance test run by # our performance lab, it is written to detect obvious memory leaks by # the lately released Perforce Server on Widnows. # # 1. The program first creates a client # # 2. Runs "p4 configure" to set the security level to 1 and disable # memory retention of the SmartHeap. # 3. After that, it does an initial stress test which verifies whether # there is any memory leak due to job042858 # 4. Once the stress is done, each command listed in the "cmds" list is # run against the server sequentially (i.e. in serial manner). # 5. When the program is finished, it will have generated a log file # which shows the initial system information, each command ran and # memory usage information after each run command run. # #Instruction to run the program: # # This program utilizes two libraries you may have not installed on your system: # # Required package: P4Python # # P4Python can be downloaded from ftp.perforce.com # # 1. Copy the program to an empty directory with the checkpoint (perftestchkpt.gz) # synced from //depot/dev/smoon/performance @ server.perforce.com:1666 # # 2. Start the Perforce Server with the checkpoint. # # 3. Type "perf_test.py" at the command prompt for the required arguments for # the program to run the program against the server. # # 4. When the program is finished, you will find a log file which corresponds to # the port number of the Perforce server. # # To do: Write a postprocessing script to compare the data (The test should be run # against two different servers. i.e. A Known tested server and the latest # release. # # #******************************************************************************* import P4 from datetime import date from subprocess import Popen,PIPE import time, re, os, sys, optparse,logging #Please note that this needs to be run against a perforce test server and you need #to add appropriate perforce commands to cmds array. cmds = [ ['streams','//streams/...']] def createClient(p4,p4port,p4user,p4debug,p4error): p4.client = p4user + "_ws" p4.port = p4port p4.user = p4user try: p4.connect() p4.password = "perforce1" p4.run_login() client = p4.run('client','-o') clientWS = p4user + "_ws" clientRoot = p4.cwd + os.sep + clientWS if not (os.path.exists(clientRoot)): os.mkdir(clientWS) #for i in client[0]: # print i client[0]['Client'] = clientWS client[0]['Root'] = clientRoot client[0]['View'] = ["//DKGQ/... //" + clientWS + "/..."] client[0]['Options'].replace("normdir","rmdir") p4.save_client(client) except P4.P4Exception: for e in p4.errors: print e p4error.exception("{0}".format(e)) def stressTest(p4,p4port,p4user,p4debug,p4error): p4.client = p4user + "_ws" p4.port = p4port p4.user = p4user count = 3000 #This test is to reproduce job42858 try: for i in range(count): p4.connect() info = p4.run('info') p4.disconnect() if(not(i % count)): print "\np4 info ran " + str(count) + " times\n" print "Typical output of each run\n" for k,v in info[0].iteritems(): print "{0:>30}: {1:<20}".format(k,v) p4debug.debug("{0:>30}: {1:<20}".format(k,v)) except Exception, e: p4error.exception("{0}".format(e)) def runCommands(p4,p4port,p4user,p4debug,p4error): p4.client = p4user + "_ws" p4.port = p4port p4.user = p4user mem = re.compile('^Mem:\s+(\d+)\s+(\d+)\s+(\d+)\s+.*$') try: p4.connect() print "\nBaseline:" p4debug.debug("\nBaseline:") #memory usage runFreeMem(mem,p4debug) for eachList in cmds: cmd_str = "" for item in eachList: cmd_str = cmd_str + " " + item print "\n\nCmd: " + cmd_str p4debug.debug("\n\nCmd: {0}".format(cmd_str)) t0 = time.clock() p4.run(eachList) print "{0:>30} {1:<20.3f}\n".format('Process Time (sec)',time.clock() - t0) p4debug.debug("{0:>30} {1:<20.3f}\n".format('Process Time (sec)',time.clock() - t0)) runFreeMem(mem,p4debug) print "\n\nDone!\n" p4debug.debug("\n\nDone!\n") except Exception, e: p4error.exception("{0}".format(e)) p4.disconnect() def runFreeMem(mem,p4debug): (mem_out,mem_err) = Popen(['free','-m'],stdout=PIPE,stderr=PIPE,close_fds=True).communicate() for each_line in mem_out.split(os.linesep): m = mem.match(each_line) if mem.match(each_line): print "{0:>30} {1:<20} MB".format('Total Memory:', m.group(1)) p4debug.debug("{0:>30} {1:<20} MB".format('Total Memory:', m.group(1))) print "{0:>30} {1:<20} MB".format('Used Memory:', m.group(2)) p4debug.debug("{0:>30} {1:<20} MB".format('Used Memory:', m.group(2))) print "{0:>30} {1:<20} MB".format('Free Memory:', m.group(3)) p4debug.debug("{0:>30} {1:<20} MB".format('Free Memory:', m.group(3))) def summaryLog(logName): #Enable logging of the backup script logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', datefmt='%m-%d %H:%M', filename=logName + ".log", filemode='w') # define a Handler which writes INFO messages or higher to the sys.stderr console = logging.StreamHandler() console.setLevel(logging.INFO) # set a format which is simpler for console use formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') # tell the handler to use this format console.setFormatter(formatter) # add the handler to the root logger logging.getLogger('').addHandler(console) #define all the environmental variables p4debug = logging.getLogger('p4debug') p4error = logging.getLogger('p4error') return (p4debug,p4error) def configureServer(p4,p4debug,p4error): try: memPool = ['configure','set','sys.memory.poolfree=1'] memProc = ['configure','set','sys.memory.procfree=1'] security = ['configure','set','security=1'] info = p4.run('info') mPool = p4.run(memPool) mProc = p4.run(memProc) sec = p4.run(security) for k,v in info[0].items(): print "{0:>30} {1:<10}".format(k + ":",v) p4debug.debug("{0:>30} {1:<10}".format(k + ":",v)) for k,v in mPool[0].items(): print "{0:>30} {1:<10}".format(k + ":",v) p4debug.debug("{0:>30} {1:<10}".format(k + ":",v)) for k,v in mProc[0].items(): print "{0:>30} {1:<10}".format(k + ":",v) p4debug.debug("{0:>30} {1:<10}".format(k + ":",v)) for k,v in sec[0].items(): print "{0:>30} {1:<10}".format(k + ":",v) p4debug.debug("{0:>30} {1:<10}".format(k + ":",v)) except Exception, e: p4error.exception("{0}".format(e)) p4.disconnect() def cleanUp(p4,p4port,p4user,p4debug,p4error): delClient=[] try: p4.connect() delClient = p4.run(['client','-d',p4user + '_ws']) except Exception, e: p4error.exception("{0}".format(e)) p4.disconnect() print "{0:>30}".format(delClient) p4debug.debug("{0:>30}".format(delClient)) def run_trust(p4port): trust_cmd = ['p4','-p',p4port,'trust','-f'] trust_ans = Popen(trust_cmd, shell=False, stdin=PIPE, stdout=PIPE) trust_ans.stdin.write("yes\n") trust_ans.stdin.flush() while True: output = trust_ans.stdout.readline() print("%s" %output) if output == "": break def main(): parser = optparse.OptionParser(usage="%prog p4port user", version="%prog v0.1") #parser.add_option("-v","--verbose",action="store_true",dest="verbose",help="Print debug messages to stdout") (options,args) = parser.parse_args() #by default sys.argv[1:] if len(args) != 2: parser.error("Incorrect number of arguments"); p4 = P4.P4() p4port = args[0] p4user = args[1] portArry = p4port.split(':') logName = '' if(len(portArry) == 3): logName = portArry[2] print("SSL Port") run_trust(p4port) elif(len(portArry) == 2): logName = portArry[1] print("HOST Port") else: logName = portArry[0] print("Port") logName = '' if(len(portArry) == 2): logName = portArry[1] else: logName = portArry[0] (p4debug,p4error) = summaryLog(logName) #print "OS: " + os.name createClient(p4,p4port,p4user,p4debug,p4error) configureServer(p4,p4debug,p4error) #exit(1) stressTest(p4,p4port,p4user,p4debug,p4error) runCommands(p4,p4port,p4user,p4debug,p4error) cleanUp(p4,p4port,p4user,p4debug,p4error) if __name__ == '__main__': main()