#! /usr/bin/env python # ______________________________________________________________________ # # Filename: memstats # # Created: 20-JAN-2001, Harry Melanson # # ______________________________________________________________________ """Summarize D0 framework job memory statistics. USAGE: memstats [-hv] framework.log OPTIONS: -h, --help -- Print help text and exit. -v -- Verbose print (list all increases). Description: memstats analyzes the log file of a framework job, and looks for increases in memory usage. The framework executable must have been run with the -mem option. By default, only the top ten memory increases are listed. Selecting the -v option results in a complete list. Limitations: The current version seems to only work with the output of d0reco. The framework appears to change the format of the output of its monitoring of memory usage, depending on the use of the 'Controller pattern'. memstats was written to support the pattern used by d0reco. """ # ______________________________________________________________________ import sys, os import glob import string # ______________________________________________________________________ __author__ = 'Harry Melanson, melanson@fnal.gov' __version__ = '01.00.00' __filename__ = 'memstats' __doc__ = __doc__ % vars() # ______________________________________________________________________ def process_command(): """Process the command.""" from scriptutil import getOptions optlist, args = getOptions('v', [], __doc__) # Process command line arguments if len(args) == 0: print "\nERROR: No RECO log file specified." print "\nNAME: ", (os.path.basename(sys.argv[0])) print __doc__ sys.exit(-1) outfile = args[0] if len(glob.glob(outfile)) == 0: print "\nERROR: RECO output file", outfile, "does not exist.\n" sys.exit(-1) elif len(glob.glob(outfile)) != 1: print "\nERROR: More than one file found?\n" sys.exit(-1) VERBOSE = 0 for opt in optlist: if opt.flag == '-v': VERBOSE = 1 # ________________________________________ # result = extractMemUsage(outfile) printSummary(result, VERBOSE) # ______________________________________________________________________ # def extractMemUsage(outfile): """Return list of memory usage from a framework log file.""" # Process the file file = open(outfile,'r') results = [] found = 0 for line in file.readlines(): # Look for lines from framework with package/algorithm if string.find(line, '%ERLOG-i mem:') != -1: items = string.split(line) mem = string.atof(items[-2]) found = 1 # If previous line was package/algo, this line has # the cpu mean time elif found == 1: found = 0 if (string.find(line, 'process') == -1 and string.find(line, 'generator') == -1 and string.find(line, 'decide') == -1 and string.find(line, 'analyze') == -1 and string.find(line, 'builder') == -1 and string.find(line, 'rcfgChanged') == -1 and string.find(line, 'output') == -1 and string.find(line, 'jobSummary') == -1 and string.find(line, 'runInit') == -1 and string.find(line, 'fileOpen') == -1 ): pass else: items = string.split(line) package = items[-1] type = items[0] results.append( MemUse(package, type, mem) ) file.close() return results # ______________________________________________________________________ # class MemUse: def __init__(self, package, type, mem): self.package = package self.type = type self.mem = mem self.count = 1 self.leak = 0 def sortMemUse(a, b): if a.leak > b.leak: return 1 elif b.leak > a.leak: return -1 else: return 0 # ______________________________________________________________________ # def printSummary(results, level): """Print summary of results at specified level of detail.""" requests = {} # Go through each memory request, and determine per package. for item in results: if not requests.has_key(item.package): requests[item.package] = item else: requests[item.package].count = requests[item.package].count + 1 # Try to associate memory increases to each package oldmem = results[0].mem for item in results[1:]: requests[item.package].leak = requests[item.package].leak + (item.mem - oldmem) oldmem = item.mem # Make a sorted list based on number of memory requests list = [] for key in requests.keys(): list.append(requests[key]) list.sort(sortMemUse) list.reverse() print "\nFinal memory usage: ", results[-1].mem, "MB\n" format1 = '%-29s %10s %10s' format2 = '%-35s %3i %5.1f' print format1 % ('Package', 'Count', 'Increase (MB)') print format1 % ('-------', '-----', '-------------') if (level == 0): for item in list[:10]: print format2 % (item.package, item.count, item.leak) elif (level == 1): for item in list: print format2 % (item.package, item.count, item.leak) # ______________________________________________________________________ # # Execute command if __name__ == '__main__': process_command() sys.exit(0)