#!/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: March 10, 2011 # #Summary: A program to test the performance of a Perforce Server on Windows # # 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: # # They are: P4Python, pywin32 and wmi modules. # # P4Python can be downloaded from ftp.perforce.com # # *For SSL server, you will need to install P4Python >= 2012.1 # # pywin32 module can be downloaded from: # # http://sourceforge.net/projects/pywin32/files/pywin32 # # wmi module can be downloaded from: # # http://timgolden.me.uk/python/wmi/index.html # # They need to installed on Windows before the script can be run. # # 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 import wmi, time from datetime import date from subprocess import Popen,PIPE import os, sys, optparse,logging #Please note that you need to run this against a perforce depot and appropriate commands #need to be added to the cmds array. cmds = [ ['changes','-i','//dkgq/...'], ['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,c): p4.client = p4user + "_ws" p4.port = p4port p4.user = p4user try: p4.connect() print "\nBaseline:" p4debug.debug("\nBaseline:") returnMemorySummary(c,p4debug,p4error) 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)) returnMemorySummary(c,p4debug,p4error) print "\n\nDone!\n" p4debug.debug("\n\nDone!\n") #except Warning, w: # p4debug.debug("{0}".format(e)) # pass except Exception, e: p4error.exception("{0}".format(e)) p4.disconnect() def returnSystemSummary(c,p4debug,p4error): for os in c.Win32_OperatingSystem(): print "\n{0:>30} {1:<10}".format('Caption:',os.Caption) p4debug.debug("\n{0:>30} {1:<10}".format('Caption:',os.Caption)) print "{0:>30} {1:<10}".format('CSDVersion:',os.CSDVersion) p4debug.debug("{0:>30} {1:<10}".format('CSDVersion:',os.CSDVersion)) print "{0:>30} {1:<10}".format('Version:',os.Version) p4debug.debug("{0:>30} {1:<10}".format('Version:',os.Version)) print "{0:>30} {1:<10}".format('OSArchitecture:',os.OSArchitecture) p4debug.debug("{0:>30} {1:<10}".format('OSArchitecture:',os.OSArchitecture)) print "{0:>30} {1:<10}".format('CSName:',os.CSName) p4debug.debug("{0:>30} {1:<10}".format('CSName:',os.CSName)) print "{0:>30} {1:<10} MB".format('Free Physical Memory MB:',int(os.FreePhysicalMemory)/1000) p4debug.debug("{0:>30} {1:<10} MB".format('Free Physical Memory MB:',int(os.FreePhysicalMemory)/1000)) print "{0:>30} {1:<10} MB".format('Total Visible Memory MB:',int(os.TotalVisibleMemorySize)/1000) p4debug.debug("{0:>30} {1:<10} MB".format('Total Visible Memory MB:',int(os.TotalVisibleMemorySize)/1000)) print "{0:>30} {1:<10} MB\n".format('Total Virtual Memory MB:',int(os.TotalVirtualMemorySize)/1000) p4debug.debug("{0:>30} {1:<10} MB\n".format('Total Virtual Memory MB:',int(os.TotalVirtualMemorySize)/1000)) def returnMemorySummary(c,p4debug,p4error): for mem in c.Win32_PerfFormattedData_PerfOS_Memory(): print "{0:>30} {1:<10} MB".format('Available Memory:',mem.AvailableMBytes) p4debug.debug("{0:>30} {1:<10} MB".format('Available Memory:',mem.AvailableMBytes)) print "{0:>30} {1:<10} MB".format('CommittedBytes:',int(mem.CommittedBytes)/1000000) p4debug.debug("{0:>30} {1:<10} MB".format('CommittedBytes:',int(mem.CommittedBytes)/1000000)) print "{0:>30} {1:<10}".format('PageFaultsPerSec:',mem.PageFaultsPerSec) p4debug.debug("{0:>30} {1:<10}".format('PageFaultsPerSec:',mem.PageFaultsPerSec)) print "{0:>30} {1:<10}".format('PercentCommittedBytesInUse:',mem.PercentCommittedBytesInUse) p4debug.debug("{0:>30} {1:<10}".format('PercentCommittedBytesInUse:',mem.PercentCommittedBytesInUse)) print "{0:>30} {1:<10}".format('PoolNonpagedAllocs:',mem.PoolNonpagedAllocs) p4debug.debug("{0:>30} {1:<10}".format('PoolNonpagedAllocs:',mem.PoolNonpagedAllocs)) print "{0:>30} {1:<10} MB".format('PoolNonpagedBytes:',int(mem.PoolNonpagedBytes)/1000000) p4debug.debug("{0:>30} {1:<10} MB".format('PoolNonpagedBytes:',int(mem.PoolNonpagedBytes)/1000000)) print "{0:>30} {1:<10}".format('PoolPagedAllocs:',mem.PoolPagedAllocs) p4debug.debug("{0:>30} {1:<10}".format('PoolPagedAllocs:',mem.PoolPagedAllocs)) print "{0:>30} {1:<10} MB".format('PoolPagedBytes:',int(mem.PoolPagedBytes)/1000000) p4debug.debug("{0:>30} {1:<10} MB".format('PoolPagedBytes:',int(mem.PoolPagedBytes)/1000000)) print "{0:>30} {1:<10} MB".format('PoolPagedResidentBytes:',int(mem.PoolPagedResidentBytes)/1000000) p4debug.debug("{0:>30} {1:<10} MB".format('PoolPagedResidentBytes:',int(mem.PoolPagedResidentBytes)/1000000)) 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)) #str1 = '' #for i in mPool: # str1 = str1 + i + ' ' for k,v in mPool[0].items(): print "{0:>30} {1:<10}".format(k + ":",v) p4debug.debug("{0:>30} {1:<10}".format(k + ":",v)) #str2 = '' #for i in mProc: # str2 = str2 + i + ' ' for k,v in mProc[0].items(): print "{0:>30} {1:<10}".format(k + ":",v) p4debug.debug("{0:>30} {1:<10}".format(k + ":",v)) #str3 = '' #for i in sec: # str3 = str3 + i + ' ' for k,v in sec[0].items(): print "{0:>30} {1:<10}".format(k + ":",v) p4debug.debug("{0:>30} {1:<10}".format(k + ":",v)) #print "\n{0:>30}".format(str1) #p4debug.debug("{0:>30}".format(str1)) #print "{0:>30}".format(str2) #p4debug.debug("{0:>30}".format(str2)) #print "{0:>30}".format(str3) #p4debug.debug("{0:>30}".format(str3)) 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() c = wmi.WMI() 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") (p4debug,p4error) = summaryLog(logName) #print "OS: " + os.name returnSystemSummary(c,p4debug,p4error) createClient(p4,p4port,p4user,p4debug,p4error) configureServer(p4,p4debug,p4error) #sys.exit(1) stressTest(p4,p4port,p4user,p4debug,p4error) runCommands(p4,p4port,p4user,p4debug,p4error,c) cleanUp(p4,p4port,p4user,p4debug,p4error) if __name__ == '__main__': main()