]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/metaparse/tools/benchmark/generate.py
2 """Utility to generate files to benchmark"""
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)
16 import Cheetah
.Template
20 def regex_to_error_msg(regex
):
21 """Format a human-readable error message from a regex"""
22 return re
.sub('([^\\\\])[()]', '\\1', regex
) \
23 .replace('[ \t]*$', '') \
26 .replace('[ \t]*', ' ') \
27 .replace('[ \t]+', ' ') \
28 .replace('[0-9]+', 'X') \
30 .replace('\\[', '[') \
31 .replace('\\]', ']') \
32 .replace('\\(', '(') \
33 .replace('\\)', ')') \
45 def in_comment(regex
):
46 """Builds a regex matching "regex" in a comment"""
47 return '^[ \t]*//[ \t]*' + regex
+ '[ \t]*$'
50 def random_chars(number
):
51 """Generate random characters"""
53 k
: v
for k
, v
in chars
.CHARS
.iteritems()
54 if not format_character(k
).startswith('\\x')
57 char_num
= sum(char_map
.values())
59 format_character(nth_char(char_map
, random
.randint(0, char_num
- 1)))
60 for _
in xrange(0, number
)
64 def random_string(length
):
65 """Generate a random string or character list depending on the mode"""
67 'BOOST_METAPARSE_STRING("{0}")'.format(''.join(random_chars(length
)))
71 """Represents a generation mode"""
73 def __init__(self
, name
):
75 if name
== 'BOOST_METAPARSE_STRING':
76 self
.identifier
= 'bmp'
77 elif name
== 'manual':
78 self
.identifier
= 'man'
80 raise Exception('Invalid mode: {0}'.format(name
))
82 def description(self
):
83 """The description of the mode"""
84 if self
.identifier
== 'bmp':
85 return 'Using BOOST_METAPARSE_STRING'
86 elif self
.identifier
== 'man':
87 return 'Generating strings manually'
89 def convert_from(self
, base
):
90 """Convert a BOOST_METAPARSE_STRING mode document into one with
92 if self
.identifier
== 'bmp':
94 elif self
.identifier
== 'man':
96 prefix
= 'BOOST_METAPARSE_STRING("'
98 bmp_at
= base
.find(prefix
)
100 return ''.join(result
) + base
103 base
[0:bmp_at
] + '::boost::metaparse::string<'
106 was_backslash
= False
108 for i
in xrange(bmp_at
+ len(prefix
), len(base
)):
111 '{0}\'\\{1}\''.format(comma
, base
[i
])
113 was_backslash
= False
116 new_base
= base
[i
+2:]
118 elif base
[i
] == '\\':
121 result
.append('{0}\'{1}\''.format(comma
, base
[i
]))
127 class Template(object):
128 """Represents a loaded template"""
130 def __init__(self
, name
, content
):
132 self
.content
= content
134 def instantiate(self
, value_of_n
):
135 """Instantiates the template"""
136 template
= Cheetah
.Template
.Template(
138 searchList
={'n': value_of_n
}
140 template
.random_string
= random_string
144 """Returns the range for N"""
145 match
= self
._match
(in_comment(
146 'n[ \t]+in[ \t]*\\[([0-9]+)\\.\\.([0-9]+)\\),[ \t]+'
155 def property(self
, name
):
156 """Parses and returns a property"""
157 return self
._get
_line
(in_comment(name
+ ':[ \t]*(.*)'))
160 """Returns the list of generation modes"""
161 return [Mode(s
.strip()) for s
in self
.property('modes').split(',')]
163 def _match(self
, regex
):
164 """Find the first line matching regex and return the match object"""
165 cregex
= re
.compile(regex
)
166 for line
in self
.content
.splitlines():
167 match
= cregex
.match(line
)
170 raise Exception('No "{0}" line in {1}.cpp'.format(
171 regex_to_error_msg(regex
),
175 def _get_line(self
, regex
):
176 """Get a line based on a regex"""
177 return self
._match
(regex
).group(1)
181 """Returns the content of the file"""
182 with
open(path
, 'rb') as in_file
:
183 return in_file
.read()
186 def templates_in(path
):
187 """Enumerate the templates found in path"""
190 Template(f
[0:-len(ext
)], load_file(os
.path
.join(path
, f
)))
191 for f
in os
.listdir(path
) if f
.endswith(ext
)
195 def nth_char(char_map
, index
):
196 """Returns the nth character of a character->occurrence map"""
197 for char
in char_map
:
198 if index
< char_map
[char
]:
200 index
= index
- char_map
[char
]
204 def format_character(char
):
205 """Returns the C-formatting of the character"""
207 char
in string
.ascii_letters \
208 or char
in string
.digits \
210 '_', '.', ':', ';', ' ', '!', '?', '+', '-', '/', '=', '<',
211 '>', '$', '(', ')', '@', '~', '`', '|', '#', '[', ']', '{',
212 '}', '&', '*', '^', '%']:
214 elif char
in ['"', '\'', '\\']:
215 return '\\{0}'.format(char
)
223 return '\\x{:02x}'.format(ord(char
))
226 def write_file(filename
, content
):
227 """Create the file with the given content"""
228 print 'Generating {0}'.format(filename
)
229 with
open(filename
, 'wb') as out_f
:
233 def out_filename(template
, n_val
, mode
):
234 """Determine the output filename"""
235 return '{0}_{1}_{2}.cpp'.format(template
.name
, n_val
, mode
.identifier
)
239 """The main function of the script"""
240 desc
= 'Generate files to benchmark'
241 parser
= argparse
.ArgumentParser(description
=desc
)
246 help='The directory containing the templates'
252 help='The output directory'
258 help='The random seed (to ensure consistent regeneration)'
261 args
= parser
.parse_args()
263 random
.seed(int(args
.seed
))
265 mkdir_p(args
.out_dir
)
267 for template
in templates_in(args
.src_dir
):
268 modes
= template
.modes()
270 n_range
= template
.range()
271 for n_value
in n_range
:
272 base
= template
.instantiate(n_value
)
277 out_filename(template
, n_value
, mode
)
279 mode
.convert_from(base
)
282 os
.path
.join(args
.out_dir
, '{0}.json'.format(template
.name
)),
286 m
.identifier
: out_filename(template
, n
, m
)
290 'name': template
.name
,
291 'x_axis_label': template
.property('x_axis_label'),
292 'desc': template
.property('desc'),
293 'modes': {m
.identifier
: m
.description() for m
in modes
}
298 if __name__
== '__main__':