17 from __future__
import print_function
27 with open(
'src/core/lib/debug/stats_data.yaml')
as f:
28 attrs = yaml.load(f.read())
30 REQUIRED_FIELDS = [
'name',
'doc']
34 return (collections.namedtuple(
35 name,
' '.join(list(
set(REQUIRED_FIELDS + fields)))), [])
39 if isinstance(s, str):
40 s = s.encode(encoding)
43 c = chr(c)
if isinstance(c, int)
else c
44 if not (32 <=
ord(c) < 127)
or c
in (
'\\',
'"'):
45 result +=
'\\%03o' %
ord(c)
48 return '"' + result +
'"'
53 make_type(
'Histogram', [
'max',
'buckets']),
56 inst_map = dict((t[0].__name__, t[1])
for t
in types)
63 t_name = t.__name__.lower()
67 lst.append(t(name=name, **attr))
70 assert found,
"Bad decl: %s" % attr
74 return ctypes.c_ulonglong.from_buffer(ctypes.c_double(d)).value
78 for i, ab
in enumerate(zip(mapped_bounds, mapped_bounds[1:])):
80 if (a >> shift_bits) == (b >> shift_bits):
82 return len(mapped_bounds)
91 table_size = mapped_bounds[n - 1] >> shift_bits
92 if table_size > max_size:
94 if table_size > 65535:
97 best = (shift_bits, n, table_size)
99 best = (shift_bits, n, table_size)
108 mapped_bounds = [x >> shift_data[0]
for x
in mapped_bounds]
110 for i
in range(0, mapped_bounds[shift_data[1] - 1]):
111 while i > mapped_bounds[cur]:
123 for i, vp
in enumerate(static_tables):
126 print(
"ADD TABLE: %s %r" % (type, values))
127 r =
len(static_tables)
128 static_tables.append(v)
147 done_unmapped =
False
148 first_nontrivial =
None
149 first_unmapped =
None
150 while len(bounds) < histogram.buckets + 1:
151 if len(bounds) == histogram.buckets:
152 nextb =
int(histogram.max)
155 float(histogram.max) / bounds[-1],
156 1.0 / (histogram.buckets + 1 -
len(bounds)))
157 nextb =
int(math.ceil(bounds[-1] * mul))
158 if nextb <= bounds[-1] + 1:
159 nextb = bounds[-1] + 1
160 elif not done_trivial:
162 first_nontrivial =
len(bounds)
166 first_nontrivial_code =
dbl2u64(first_nontrivial)
167 code_bounds = [
dbl2u64(x) - first_nontrivial_code
for x
in bounds]
169 256 * histogram.buckets)
172 code =
'value = grpc_core::Clamp(value, 0, %d);\n' % histogram.max
173 map_table =
gen_map_table(code_bounds[first_nontrivial:], shift_data)
174 if first_nontrivial
is None:
175 code += (
'GRPC_STATS_INC_HISTOGRAM(GRPC_STATS_HISTOGRAM_%s, value);\n' %
176 histogram.name.upper())
178 code +=
'if (value < %d) {\n' % first_nontrivial
179 code += (
'GRPC_STATS_INC_HISTOGRAM(GRPC_STATS_HISTOGRAM_%s, value);\n' %
180 histogram.name.upper())
183 first_nontrivial_code =
dbl2u64(first_nontrivial)
184 if shift_data
is not None:
187 code +=
'union { double dbl; uint64_t uint; } _val, _bkt;\n'
188 code +=
'_val.dbl = value;\n'
189 code +=
'if (_val.uint < %dull) {\n' % (
190 (map_table[-1] << shift_data[0]) + first_nontrivial_code)
191 code +=
'int bucket = '
192 code +=
'grpc_stats_table_%d[((_val.uint - %dull) >> %d)] + %d;\n' % (
193 map_table_idx, first_nontrivial_code, shift_data[0],
195 code +=
'_bkt.dbl = grpc_stats_table_%d[bucket];\n' % bounds_idx
196 code +=
'bucket -= (_val.uint < _bkt.uint);\n'
197 code +=
'GRPC_STATS_INC_HISTOGRAM(GRPC_STATS_HISTOGRAM_%s, bucket);\n' % histogram.name.upper(
201 code +=
'GRPC_STATS_INC_HISTOGRAM(GRPC_STATS_HISTOGRAM_%s, ' % histogram.name.upper(
203 code +=
'grpc_stats_histo_find_bucket_slow(value, grpc_stats_table_%d, %d));\n' % (
204 bounds_idx, histogram.buckets)
205 return (code, bounds_idx)
213 print(
' * %s' % line, file=f)
218 with open(
'src/core/lib/debug/stats_data.h',
'w')
as H:
220 with open(sys.argv[0])
as my_source:
222 for line
in my_source:
225 for line
in my_source:
227 copyright.append(line)
229 for line
in my_source:
232 copyright.append(line)
233 put_banner([H], [line[2:].rstrip()
for line
in copyright])
237 [
"Automatically generated by tools/codegen/core/gen_stats_data.py"])
239 print(
"#ifndef GRPC_CORE_LIB_DEBUG_STATS_DATA_H", file=H)
240 print(
"#define GRPC_CORE_LIB_DEBUG_STATS_DATA_H", file=H)
242 print(
"#include <grpc/support/port_platform.h>", file=H)
244 print(
"#include <inttypes.h>", file=H)
245 print(
"#include \"src/core/lib/iomgr/exec_ctx.h\"", file=H)
248 for typename, instances
in sorted(inst_map.items()):
249 print(
"typedef enum {", file=H)
250 for inst
in instances:
251 print(
" GRPC_STATS_%s_%s," % (typename.upper(), inst.name.upper()),
253 print(
" GRPC_STATS_%s_COUNT" % (typename.upper()), file=H)
254 print(
"} grpc_stats_%ss;" % (typename.lower()), file=H)
255 print(
"extern const char *grpc_stats_%s_name[GRPC_STATS_%s_COUNT];" %
256 (typename.lower(), typename.upper()),
258 print(
"extern const char *grpc_stats_%s_doc[GRPC_STATS_%s_COUNT];" %
259 (typename.lower(), typename.upper()),
264 histo_bucket_boundaries = []
266 print(
"typedef enum {", file=H)
268 for histogram
in inst_map[
'Histogram']:
269 histo_start.append(first_slot)
270 histo_buckets.append(histogram.buckets)
271 print(
" GRPC_STATS_HISTOGRAM_%s_FIRST_SLOT = %d," %
272 (histogram.name.upper(), first_slot),
274 print(
" GRPC_STATS_HISTOGRAM_%s_BUCKETS = %d," %
275 (histogram.name.upper(), histogram.buckets),
277 first_slot += histogram.buckets
278 print(
" GRPC_STATS_HISTOGRAM_BUCKETS = %d" % first_slot, file=H)
279 print(
"} grpc_stats_histogram_constants;", file=H)
281 print(
"#if defined(GRPC_COLLECT_STATS) || !defined(NDEBUG)", file=H)
282 for ctr
in inst_map[
'Counter']:
283 print((
"#define GRPC_STATS_INC_%s() " +
284 "GRPC_STATS_INC_COUNTER(GRPC_STATS_COUNTER_%s)") %
285 (ctr.name.upper(), ctr.name.upper()),
287 for histogram
in inst_map[
'Histogram']:
289 "#define GRPC_STATS_INC_%s(value) grpc_stats_inc_%s( (int)(value))"
290 % (histogram.name.upper(), histogram.name.lower()),
292 print(
"void grpc_stats_inc_%s(int x);" % histogram.name.lower(), file=H)
294 print(
"#else", file=H)
295 for ctr
in inst_map[
'Counter']:
296 print((
"#define GRPC_STATS_INC_%s() ") % (ctr.name.upper()), file=H)
297 for histogram
in inst_map[
'Histogram']:
298 print(
"#define GRPC_STATS_INC_%s(value)" % (histogram.name.upper()),
300 print(
"#endif /* defined(GRPC_COLLECT_STATS) || !defined(NDEBUG) */",
303 for i, tbl
in enumerate(static_tables):
304 print(
"extern const %s grpc_stats_table_%d[%d];" %
305 (tbl[0], i,
len(tbl[1])),
308 print(
"extern const int grpc_stats_histo_buckets[%d];" %
309 len(inst_map[
'Histogram']),
311 print(
"extern const int grpc_stats_histo_start[%d];" %
312 len(inst_map[
'Histogram']),
314 print(
"extern const int *const grpc_stats_histo_bucket_boundaries[%d];" %
315 len(inst_map[
'Histogram']),
317 print(
"extern void (*const grpc_stats_inc_histogram[%d])(int x);" %
318 len(inst_map[
'Histogram']),
322 print(
"#endif /* GRPC_CORE_LIB_DEBUG_STATS_DATA_H */", file=H)
324 with open(
'src/core/lib/debug/stats_data.cc',
'w')
as C:
326 with open(sys.argv[0])
as my_source:
328 for line
in my_source:
331 for line
in my_source:
333 copyright.append(line)
335 for line
in my_source:
338 copyright.append(line)
339 put_banner([C], [line[2:].rstrip()
for line
in copyright])
343 [
"Automatically generated by tools/codegen/core/gen_stats_data.py"])
345 print(
"#include <grpc/support/port_platform.h>", file=C)
347 print(
"#include \"src/core/lib/debug/stats.h\"", file=C)
348 print(
"#include \"src/core/lib/debug/stats_data.h\"", file=C)
349 print(
"#include \"src/core/lib/gpr/useful.h\"", file=C)
350 print(
"#include \"src/core/lib/iomgr/exec_ctx.h\"", file=C)
354 for histogram
in inst_map[
'Histogram']:
356 histo_bucket_boundaries.append(bounds_idx)
357 histo_code.append(code)
359 for typename, instances
in sorted(inst_map.items()):
360 print(
"const char *grpc_stats_%s_name[GRPC_STATS_%s_COUNT] = {" %
361 (typename.lower(), typename.upper()),
363 for inst
in instances:
364 print(
" %s," %
c_str(inst.name), file=C)
366 print(
"const char *grpc_stats_%s_doc[GRPC_STATS_%s_COUNT] = {" %
367 (typename.lower(), typename.upper()),
369 for inst
in instances:
370 print(
" %s," %
c_str(inst.doc), file=C)
373 for i, tbl
in enumerate(static_tables):
374 print(
"const %s grpc_stats_table_%d[%d] = {%s};" %
375 (tbl[0], i,
len(tbl[1]),
','.join(
'%s' % x
for x
in tbl[1])),
378 for histogram, code
in zip(inst_map[
'Histogram'], histo_code):
379 print((
"void grpc_stats_inc_%s(int value) {%s}") %
380 (histogram.name.lower(), code),
384 "const int grpc_stats_histo_buckets[%d] = {%s};" %
385 (
len(inst_map[
'Histogram']),
','.join(
'%s' % x
for x
in histo_buckets)),
387 print(
"const int grpc_stats_histo_start[%d] = {%s};" %
388 (
len(inst_map[
'Histogram']),
','.join(
'%s' % x
for x
in histo_start)),
390 print(
"const int *const grpc_stats_histo_bucket_boundaries[%d] = {%s};" %
391 (
len(inst_map[
'Histogram']),
','.join(
392 'grpc_stats_table_%d' % x
for x
in histo_bucket_boundaries)),
394 print(
"void (*const grpc_stats_inc_histogram[%d])(int x) = {%s};" %
395 (
len(inst_map[
'Histogram']),
','.join(
396 'grpc_stats_inc_%s' % histogram.name.lower()
397 for histogram
in inst_map[
'Histogram'])),
401 RECORD_EXPLICIT_PERCENTILES = [50, 95, 99]
403 with open(
'tools/run_tests/performance/scenario_result_schema.json',
'r')
as f:
404 qps_schema = json.loads(f.read())
409 if el[
'name'] == name:
415 for field
in js[
'fields']:
416 if not field[
'name'].startswith(
'core_'):
417 new_fields.append(field)
418 js[
'fields'] = new_fields
426 for counter
in inst_map[
'Counter']:
427 js[
'fields'].append({
428 'name':
'core_%s' % counter.name,
432 for histogram
in inst_map[
'Histogram']:
433 js[
'fields'].append({
434 'name':
'core_%s' % histogram.name,
438 js[
'fields'].append({
439 'name':
'core_%s_bkts' % histogram.name,
443 for pctl
in RECORD_EXPLICIT_PERCENTILES:
444 js[
'fields'].append({
445 'name':
'core_%s_%dp' % (histogram.name, pctl),
454 with open(
'tools/run_tests/performance/scenario_result_schema.json',
'w')
as f:
455 f.write(json.dumps(qps_schema, indent=2, sort_keys=
True))
459 with open(
'tools/run_tests/performance/massage_qps_stats.py',
'w')
as P:
460 with open(sys.argv[0])
as my_source:
461 for line
in my_source:
464 for line
in my_source:
466 print(line.rstrip(), file=P)
468 for line
in my_source:
471 print(line.rstrip(), file=P)
474 print(
'# Autogenerated by tools/codegen/core/gen_stats_data.py', file=P)
477 print(
'import massage_qps_stats_helpers', file=P)
479 print(
'def massage_qps_stats(scenario_result):', file=P)
481 ' for stats in scenario_result["serverStats"] + scenario_result["clientStats"]:',
483 print(
' if "coreStats" in stats:', file=P)
485 ' # Get rid of the "coreStats" element and replace it by statistics',
487 print(
' # that correspond to columns in the bigquery schema.', file=P)
488 print(
' core_stats = stats["coreStats"]', file=P)
489 print(
' del stats["coreStats"]', file=P)
490 for counter
in inst_map[
'Counter']:
492 ' stats["core_%s"] = massage_qps_stats_helpers.counter(core_stats, "%s")'
493 % (counter.name, counter.name),
495 for i, histogram
in enumerate(inst_map[
'Histogram']):
497 ' h = massage_qps_stats_helpers.histogram(core_stats, "%s")' %
501 ' stats["core_%s"] = ",".join("%%f" %% x for x in h.buckets)' %
505 ' stats["core_%s_bkts"] = ",".join("%%f" %% x for x in h.boundaries)'
508 for pctl
in RECORD_EXPLICIT_PERCENTILES:
510 ' stats["core_%s_%dp"] = massage_qps_stats_helpers.percentile(h.buckets, %d, h.boundaries)'
511 % (histogram.name, pctl, pctl),
514 with open(
'src/core/lib/debug/stats_data_bq_schema.sql',
'w')
as S:
516 for counter
in inst_map[
'Counter']:
517 columns.append((
'%s_per_iteration' % counter.name,
'FLOAT'))
518 print(
',\n'.join(
'%s:%s' % x
for x
in columns), file=S)