]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/metaparse/tools/benchmark/benchmark.py
2 """Utility to benchmark the generated source files"""
4 # Copyright Abel Sinkovics (abel@sinkovics.hu) 2016.
5 # Distributed under the Boost Software License, Version 1.0.
6 # (See accompanying file LICENSE_1_0.txt or copy at
7 # http://www.boost.org/LICENSE_1_0.txt)
23 import matplotlib
.pyplot
# pylint:disable=I0011,C0411,C0412,C0413
26 def benchmark_command(cmd
, progress
):
27 """Benchmark one command execution"""
28 full_cmd
= '/usr/bin/time --format="%U %M" {0}'.format(cmd
)
29 print '{0:6.2f}% Running {1}'.format(100.0 * progress
, full_cmd
)
30 (_
, err
) = subprocess
.Popen(
31 ['/bin/bash', '-c', full_cmd
],
32 stdin
=subprocess
.PIPE
,
33 stdout
=subprocess
.PIPE
,
34 stderr
=subprocess
.PIPE
37 values
= err
.strip().split(' ')
40 return (float(values
[0]), float(values
[1]))
41 except: # pylint:disable=I0011,W0702
42 pass # Handled by the code after the "if"
45 raise Exception('Error during benchmarking')
49 filename
, compiler
, include_dirs
, (progress_from
, progress_to
),
51 """Benchmark one file"""
54 for nth_run
in xrange(0, iter_count
):
55 (time_spent
, mem_used
) = benchmark_command(
56 '{0} -std=c++11 {1} -c {2}'.format(
58 ' '.join('-I{0}'.format(i
) for i
in include_dirs
),
62 progress_to
* nth_run
+ progress_from
* (iter_count
- nth_run
)
65 os
.remove(os
.path
.splitext(os
.path
.basename(filename
))[0] + '.o')
66 time_sum
= time_sum
+ time_spent
67 mem_sum
= mem_sum
+ mem_used
70 "time": time_sum
/ iter_count
,
71 "memory": mem_sum
/ (iter_count
* 1024)
75 def compiler_info(compiler
):
76 """Determine the name + version of the compiler"""
77 (out
, err
) = subprocess
.Popen(
78 ['/bin/bash', '-c', '{0} -v'.format(compiler
)],
79 stdin
=subprocess
.PIPE
,
80 stdout
=subprocess
.PIPE
,
81 stderr
=subprocess
.PIPE
84 gcc_clang
= re
.compile('(gcc|clang) version ([0-9]+(\\.[0-9]+)*)')
86 for line
in (out
+ err
).split('\n'):
87 mtch
= gcc_clang
.search(line
)
89 return mtch
.group(1) + ' ' + mtch
.group(2)
94 def string_char(char
):
95 """Turn the character into one that can be part of a filename"""
96 return '_' if char
in [' ', '~', '(', ')', '/', '\\'] else char
99 def make_filename(string
):
100 """Turn the string into a filename"""
101 return ''.join(string_char(c
) for c
in string
)
104 def files_in_dir(path
, extension
):
105 """Enumartes the files in path with the given extension"""
106 ends
= '.{0}'.format(extension
)
107 return (f
for f
in os
.listdir(path
) if f
.endswith(ends
))
110 def format_time(seconds
):
111 """Format a duration"""
119 ('week', week
), ('day', day
), ('hour', hour
),
120 ('minute', minute
), ('second', 1)
123 value
= seconds
// dur
125 '{0} {1}{2}'.format(int(value
), name
, 's' if value
> 1 else '')
127 seconds
= seconds
% dur
128 return ' '.join(result
)
131 def benchmark(src_dir
, compiler
, include_dirs
, iter_count
):
132 """Do the benchrmarking"""
134 files
= list(files_in_dir(src_dir
, 'cpp'))
135 random
.shuffle(files
)
137 started_at
= time
.time()
139 for filename
in files
:
140 progress
= len(result
)
141 result
[filename
] = benchmark_file(
142 os
.path
.join(src_dir
, filename
),
145 (float(progress
) / len(files
), float(progress
+ 1) / len(files
)),
148 elapsed
= time
.time() - started_at
149 total
= float(len(files
) * elapsed
) / len(result
)
150 print 'Elapsed time: {0}, Remaining time: {1}'.format(
151 format_time(elapsed
),
152 format_time(total
- elapsed
)
157 def plot(values
, mode_names
, title
, (xlabel
, ylabel
), out_file
):
159 matplotlib
.pyplot
.clf()
160 for mode
, mode_name
in mode_names
.iteritems():
162 matplotlib
.pyplot
.plot(
163 [x
for x
, _
in vals
],
164 [y
for _
, y
in vals
],
167 matplotlib
.pyplot
.title(title
)
168 matplotlib
.pyplot
.xlabel(xlabel
)
169 matplotlib
.pyplot
.ylabel(ylabel
)
170 if len(mode_names
) > 1:
171 matplotlib
.pyplot
.legend()
172 matplotlib
.pyplot
.savefig(out_file
)
183 def configs_in(src_dir
):
184 """Enumerate all configs in src_dir"""
185 for filename
in files_in_dir(src_dir
, 'json'):
186 with
open(os
.path
.join(src_dir
, filename
), 'rb') as in_f
:
187 yield json
.load(in_f
)
190 def byte_to_gb(byte
):
191 """Convert bytes to GB"""
192 return byte
/ (1024.0 * 1024 * 1024)
195 def join_images(img_files
, out_file
):
196 """Join the list of images into the out file"""
197 images
= [PIL
.Image
.open(f
) for f
in img_files
]
198 joined
= PIL
.Image
.new(
200 (sum(i
.size
[0] for i
in images
), max(i
.size
[1] for i
in images
))
204 joined
.paste(im
=img
, box
=(left
, 0))
205 left
= left
+ img
.size
[0]
206 joined
.save(out_file
)
209 def plot_temp_diagrams(config
, results
, temp_dir
):
210 """Plot temporary diagrams"""
212 'time': 'Compilation time (s)',
213 'memory': 'Compiler memory usage (MB)',
216 files
= config
['files']
218 for measured
in ['time', 'memory']:
219 mpts
= sorted(int(k
) for k
in files
.keys())
220 img_files
.append(os
.path
.join(temp_dir
, '_{0}.png'.format(measured
)))
223 m
: [(x
, results
[files
[str(x
)][m
]][measured
]) for x
in mpts
]
224 for m
in config
['modes'].keys()
227 display_name
[measured
],
228 (config
['x_axis_label'], display_name
[measured
]),
234 def plot_diagram(config
, results
, images_dir
, out_filename
):
235 """Plot one diagram"""
236 img_files
= plot_temp_diagrams(config
, results
, images_dir
)
237 join_images(img_files
, out_filename
)
238 for img_file
in img_files
:
242 def plot_diagrams(results
, configs
, compiler
, out_dir
):
243 """Plot all diagrams specified by the configs"""
244 compiler_fn
= make_filename(compiler
)
245 total
= psutil
.virtual_memory().total
# pylint:disable=I0011,E1101
246 memory
= int(math
.ceil(byte_to_gb(total
)))
248 images_dir
= os
.path
.join(out_dir
, 'images')
250 for config
in configs
:
251 out_prefix
= '{0}_{1}'.format(config
['name'], compiler_fn
)
257 os
.path
.join(images_dir
, '{0}.png'.format(out_prefix
))
261 os
.path
.join(out_dir
, '{0}.qbk'.format(out_prefix
)),
265 Measured on a {2} host with {3} GB memory. Compiler used: {4}.
267 [$images/metaparse/{1}.png [width 100%]]
268 """.format(config
['desc'], out_prefix
, platform
.platform(), memory
, compiler
)
269 out_f
.write(qbk_content
)
273 """The main function of the script"""
274 desc
= 'Benchmark the files generated by generate.py'
275 parser
= argparse
.ArgumentParser(description
=desc
)
280 help='The directory containing the sources to benchmark'
286 help='The output directory'
292 help='The directory containing the headeres for the benchmark'
296 dest
='boost_headers',
297 default
='../../../..',
298 help='The directory containing the Boost headers (the boost directory)'
304 help='The compiler to do the benchmark with'
311 help='How many times a measurement should be repeated.'
314 args
= parser
.parse_args()
316 compiler
= compiler_info(args
.compiler
)
320 [args
.include
, args
.boost_headers
],
324 plot_diagrams(results
, configs_in(args
.src_dir
), compiler
, args
.out_dir
)
327 if __name__
== '__main__':