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) |
---|