2 # Copyright (C) 2019 - Jonathan Rajotte Julien <jonathan.rajotte-julien@efficios.com>
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 from collections
import defaultdict
24 def wall_clock_parser(value
):
26 Parse /usr/bin/time wall clock value.
27 Wall clock value is expressed in different formats depending on the actual
33 total
+= float(value
[pos
:])
36 v_split
= value
.split(":")
38 total
+= float(v_split
[0]) * 60.0
39 total
+= float(v_split
[1]) * 1.0
40 elif len(v_split
) == 3:
41 total
+= float(v_split
[0]) * 360.0
42 total
+= float(v_split
[1]) * 60.0
43 total
+= float(v_split
[2]) * 1.0
50 def percent_parser(value
):
52 Parse /usr/bin/time percent value.
54 parsed
= value
.replace("%", "").replace("?", "")
61 "User time (seconds)": float,
62 "System time (seconds)": float,
63 "Percent of CPU this job got": percent_parser
,
64 "Elapsed (wall clock) time (h:mm:ss or m:ss)": wall_clock_parser
,
65 "Average shared text size (kbytes)": int,
66 "Average unshared data size (kbytes)": int,
67 "Average stack size (kbytes)": int,
68 "Average total size (kbytes)": int,
69 "Maximum resident set size (kbytes)": int,
70 "Average resident set size (kbytes)": int,
71 "Major (requiring I/O) page faults": int,
72 "Minor (reclaiming a frame) page faults": int,
73 "Voluntary context switches": int,
74 "Involuntary context switches": int,
76 "File system inputs": int,
77 "File system outputs": int,
78 "Socket messages sent": int,
79 "Socket messages received": int,
80 "Signals delivered": int,
81 "Page size (bytes)": int,
86 def parse(path
, results
):
88 Parser and accumulator for /usr/bin/time results.
90 with
open(path
, "r") as data
:
92 if line
.rfind(":") == -1:
94 key
, value
= line
.lstrip().rsplit(": ")
96 results
[key
].append(_METRIC
[key
](value
))
101 def save(path
, results
):
103 Save the result in json format to path.
105 with
open(path
, "w") as out
:
106 json
.dump(results
, out
, sort_keys
=True, indent
=4)
109 def run(command
, iteration
, output
, stdout
, stderr
):
111 Run the command throught /usr/bin/time n iterations and parse each result.
113 results
= defaultdict(list)
114 for i
in range(iteration
):
115 time_stdout
= tempfile
.NamedTemporaryFile(delete
=False)
116 # We must delete this file later on.
118 with
open(stdout
, "a+") as out
, open(stderr
, "a+") as err
:
119 cmd
= "/usr/bin/time -v --output='{}' {}".format(time_stdout
.name
, command
)
120 ret
= subprocess
.run(cmd
, shell
=True, stdout
=out
, stderr
=err
)
121 if ret
.returncode
!= 0:
122 print("Iteration: {}, Command failed: {}".format(str(i
), cmd
))
123 results
= parse(time_stdout
.name
, results
)
124 os
.remove(time_stdout
.name
)
125 save(output
, results
)
130 Run /usr/bin/time N time and collect the result.
131 The resulting json have the following form:
134 "User time (seconds)": [],
135 "System time (seconds)": [],
136 "Percent of CPU this job got": [],
137 "Elapsed (wall clock) time (h:mm:ss or m:ss)": [],
138 "Average shared text size (kbytes)": [],
139 "Average unshared data size (kbytes)": [],
140 "Average stack size (kbytes)": [],
141 "Average total size (kbytes)": [],
142 "Maximum resident set size (kbytes)": [],
143 "Average resident set size (kbytes)": [],
144 "Major (requiring I/O) page faults": [],
145 "Minor (reclaiming a frame) page faults": [],
146 "Voluntary context switches": [],
147 "Involuntary context switches": [],
149 "File system inputs": [],
150 "File system outputs": [],
151 "Socket messages sent": [],
152 "Socket messages received": [],
153 "Signals delivered": [],
154 "Page size (bytes)": [],
158 parser
= argparse
.ArgumentParser(
159 description
="Run command N time using /usr/bin/time and collect the statistics"
161 parser
.add_argument("--output", help="Where to same the result", required
=True)
162 parser
.add_argument("--command", help="The command to benchmark", required
=True)
167 help="The number of iteration to run the command (default: 5)",
173 help="Where to append the stdout of each command (default: /dev/null)",
177 default
=os
.path
.join(os
.getcwd(), "stderr.out"),
178 help="Where to append the stderr of each command (default: $CWD/stderr.out)",
181 args
= parser
.parse_args()
182 run(args
.command
, args
.iteration
, args
.output
, args
.stdout
, args
.stderr
)
185 if __name__
== "__main__":
This page took 0.043201 seconds and 4 git commands to generate.