[3] | 1 | #!/afs/bx.psu.edu/project/pythons/linux-x86_64-ucs4/bin/python2.6 |
---|
| 2 | # This file is part of the twill source distribution. |
---|
| 3 | # |
---|
| 4 | # twill is a extensible scriptlet language for testing Web apps, |
---|
| 5 | # available at http://twill.idyll.org/. |
---|
| 6 | # |
---|
| 7 | # Contact author: C. Titus Brown, titus@idyll.org. |
---|
| 8 | # |
---|
| 9 | # This program and all associated source code files are Copyright (C) |
---|
| 10 | # 2005-2007 by C. Titus Brown. It is released under the MIT license; |
---|
| 11 | # please see the included LICENSE.txt file for more information, or |
---|
| 12 | # go to http://www.opensource.org/licenses/mit-license.php. |
---|
| 13 | |
---|
| 14 | """ |
---|
| 15 | twill multiprocess execution system. |
---|
| 16 | """ |
---|
| 17 | |
---|
| 18 | import sys, os, time |
---|
| 19 | from twill import execute_file |
---|
| 20 | from optparse import OptionParser |
---|
| 21 | from cPickle import load, dump |
---|
| 22 | |
---|
| 23 | ### |
---|
| 24 | # make sure that the current working directory is in the path. does this |
---|
| 25 | # work on Windows?? |
---|
| 26 | |
---|
| 27 | if not '.' in sys.path: |
---|
| 28 | sys.path.append('.') |
---|
| 29 | ### |
---|
| 30 | |
---|
| 31 | #### OPTIONS |
---|
| 32 | |
---|
| 33 | parser = OptionParser() |
---|
| 34 | |
---|
| 35 | parser.add_option('-u', '--url', nargs=1, action="store", dest="url", |
---|
| 36 | help="start at the given URL before each script") |
---|
| 37 | |
---|
| 38 | parser.add_option('-n', '--number', nargs=1, action="store", dest="number", |
---|
| 39 | default=1, type="int", |
---|
| 40 | help="number of times to run the given script(s)") |
---|
| 41 | |
---|
| 42 | parser.add_option('-p', '--processes', nargs=1, action="store", |
---|
| 43 | dest="processes", default=1, type="int", |
---|
| 44 | help="number of processes to execute in parallel") |
---|
| 45 | |
---|
| 46 | #### |
---|
| 47 | |
---|
| 48 | # parse arguments. |
---|
| 49 | (options, args) = parser.parse_args() |
---|
| 50 | |
---|
| 51 | if not len(args): |
---|
| 52 | sys.stderr.write('Error! Must specify one or more scripts to execute...\n') |
---|
| 53 | sys.exit(-1) |
---|
| 54 | |
---|
| 55 | average_number = int(options.number / options.processes) |
---|
| 56 | last_number = average_number + options.number % options.processes |
---|
| 57 | is_parent = True |
---|
| 58 | child_pids = [] |
---|
| 59 | |
---|
| 60 | # |
---|
| 61 | # start a bunch of child processes & record their pids in the parent. |
---|
| 62 | # |
---|
| 63 | |
---|
| 64 | for i in range(0, options.processes): |
---|
| 65 | pid = os.fork() |
---|
| 66 | if pid == 0: |
---|
| 67 | if i == 0: |
---|
| 68 | repeat = last_number # make sure we execute 'em *all* |
---|
| 69 | else: |
---|
| 70 | repeat = average_number |
---|
| 71 | |
---|
| 72 | is_parent = False |
---|
| 73 | break |
---|
| 74 | else: |
---|
| 75 | child_pids.append(pid) # keep track of children |
---|
| 76 | |
---|
| 77 | # |
---|
| 78 | # set the children up to run & record their stats |
---|
| 79 | # |
---|
| 80 | |
---|
| 81 | failed = False |
---|
| 82 | |
---|
| 83 | if not is_parent: |
---|
| 84 | print '[twill-fork: pid %d : executing %d times]' % (os.getpid(), repeat) |
---|
| 85 | |
---|
| 86 | start_time = time.time() |
---|
| 87 | |
---|
| 88 | for i in range(0, repeat): |
---|
| 89 | for filename in args: |
---|
| 90 | execute_file(filename, initial_url=options.url) |
---|
| 91 | |
---|
| 92 | end_time = time.time() |
---|
| 93 | this_time = end_time - start_time |
---|
| 94 | |
---|
| 95 | # write statistics |
---|
| 96 | fp = open('.status.%d' % (os.getpid(),), 'w') |
---|
| 97 | info = (this_time, repeat) |
---|
| 98 | dump(info, fp) |
---|
| 99 | fp.close() |
---|
| 100 | |
---|
| 101 | else: # is_parent |
---|
| 102 | total_time = 0. |
---|
| 103 | total_exec = 0 |
---|
| 104 | |
---|
| 105 | # iterate over all the child pids, wait 'til they finish, and then |
---|
| 106 | # sum statistics. |
---|
| 107 | |
---|
| 108 | left_childs = child_pids[:] |
---|
| 109 | for child_pid in left_childs: |
---|
| 110 | child_pid, status = os.waitpid(child_pid, 0) |
---|
| 111 | |
---|
| 112 | # status != 0 indicates failure: |
---|
| 113 | |
---|
| 114 | if status != 0: |
---|
| 115 | print '[twill-fork parent: process %d FAILED: exit status %d]' % (child_pid, status,) |
---|
| 116 | print '[twill-fork parent: (not counting stats for this process)]' |
---|
| 117 | failed = True |
---|
| 118 | else: |
---|
| 119 | # record statistics, otherwise |
---|
| 120 | |
---|
| 121 | fp = open('.status.%d' % (child_pid,)) |
---|
| 122 | (this_time, n_executed) = load(fp) |
---|
| 123 | fp.close() |
---|
| 124 | os.unlink('.status.%d' % (child_pid,)) |
---|
| 125 | |
---|
| 126 | total_time += this_time |
---|
| 127 | total_exec += n_executed |
---|
| 128 | |
---|
| 129 | # |
---|
| 130 | # summarize |
---|
| 131 | # |
---|
| 132 | |
---|
| 133 | print '\n---' |
---|
| 134 | print 'n processes: %d' % (options.processes,) |
---|
| 135 | print 'total executed: %d' % (total_exec,) |
---|
| 136 | print 'total time to execute: %f' % (total_time,) |
---|
| 137 | if total_exec: |
---|
| 138 | print 'average time: %f' % (total_time / total_exec,) |
---|
| 139 | else: |
---|
| 140 | print '(nothing completed, no average!)' |
---|
| 141 | |
---|
| 142 | if failed: |
---|
| 143 | sys.exit(-1) |
---|
| 144 | |
---|
| 145 | sys.exit(0) |
---|