1# Copyright (c) 2015-2017 Intel Corporation 2# 3# Permission is hereby granted, free of charge, to any person obtaining a 4# copy of this software and associated documentation files (the "Software"), 5# to deal in the Software without restriction, including without limitation 6# the rights to use, copy, modify, merge, publish, distribute, sublicense, 7# and/or sell copies of the Software, and to permit persons to whom the 8# Software is furnished to do so, subject to the following conditions: 9# 10# The above copyright notice and this permission notice (including the next 11# paragraph) shall be included in all copies or substantial portions of the 12# Software. 13# 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20# IN THE SOFTWARE. 21 22import argparse 23import builtins 24import collections 25import os 26import re 27import sys 28import textwrap 29 30import xml.etree.ElementTree as et 31 32hashed_funcs = {} 33 34c_file = None 35_c_indent = 0 36 37def c(*args): 38 code = ' '.join(map(str,args)) 39 for line in code.splitlines(): 40 text = ''.rjust(_c_indent) + line 41 c_file.write(text.rstrip() + "\n") 42 43# indented, but no trailing newline... 44def c_line_start(code): 45 c_file.write(''.rjust(_c_indent) + code) 46def c_raw(code): 47 c_file.write(code) 48 49def c_indent(n): 50 global _c_indent 51 _c_indent = _c_indent + n 52def c_outdent(n): 53 global _c_indent 54 _c_indent = _c_indent - n 55 56header_file = None 57_h_indent = 0 58 59def h(*args): 60 code = ' '.join(map(str,args)) 61 for line in code.splitlines(): 62 text = ''.rjust(_h_indent) + line 63 header_file.write(text.rstrip() + "\n") 64 65def h_indent(n): 66 global _c_indent 67 _h_indent = _h_indent + n 68def h_outdent(n): 69 global _c_indent 70 _h_indent = _h_indent - n 71 72 73def emit_fadd(tmp_id, args): 74 c("double tmp{0} = {1} + {2};".format(tmp_id, args[1], args[0])) 75 return tmp_id + 1 76 77# Be careful to check for divide by zero... 78def emit_fdiv(tmp_id, args): 79 c("double tmp{0} = {1};".format(tmp_id, args[1])) 80 c("double tmp{0} = {1};".format(tmp_id + 1, args[0])) 81 c("double tmp{0} = tmp{1} ? tmp{2} / tmp{1} : 0;".format(tmp_id + 2, tmp_id + 1, tmp_id)) 82 return tmp_id + 3 83 84def emit_fmax(tmp_id, args): 85 c("double tmp{0} = {1};".format(tmp_id, args[1])) 86 c("double tmp{0} = {1};".format(tmp_id + 1, args[0])) 87 c("double tmp{0} = MAX(tmp{1}, tmp{2});".format(tmp_id + 2, tmp_id, tmp_id + 1)) 88 return tmp_id + 3 89 90def emit_fmul(tmp_id, args): 91 c("double tmp{0} = {1} * {2};".format(tmp_id, args[1], args[0])) 92 return tmp_id + 1 93 94def emit_fsub(tmp_id, args): 95 c("double tmp{0} = {1} - {2};".format(tmp_id, args[1], args[0])) 96 return tmp_id + 1 97 98def emit_read(tmp_id, args): 99 type = args[1].lower() 100 c("uint64_t tmp{0} = results->accumulator[query->{1}_offset + {2}];".format(tmp_id, type, args[0])) 101 return tmp_id + 1 102 103def emit_uadd(tmp_id, args): 104 c("uint64_t tmp{0} = {1} + {2};".format(tmp_id, args[1], args[0])) 105 return tmp_id + 1 106 107# Be careful to check for divide by zero... 108def emit_udiv(tmp_id, args): 109 c("uint64_t tmp{0} = {1};".format(tmp_id, args[1])) 110 c("uint64_t tmp{0} = {1};".format(tmp_id + 1, args[0])) 111 if args[0].isdigit(): 112 assert int(args[0]) > 0 113 c("uint64_t tmp{0} = tmp{2} / tmp{1};".format(tmp_id + 2, tmp_id + 1, tmp_id)) 114 else: 115 c("uint64_t tmp{0} = tmp{1} ? tmp{2} / tmp{1} : 0;".format(tmp_id + 2, tmp_id + 1, tmp_id)) 116 return tmp_id + 3 117 118def emit_umul(tmp_id, args): 119 c("uint64_t tmp{0} = {1} * {2};".format(tmp_id, args[1], args[0])) 120 return tmp_id + 1 121 122def emit_usub(tmp_id, args): 123 c("uint64_t tmp{0} = {1} - {2};".format(tmp_id, args[1], args[0])) 124 return tmp_id + 1 125 126def emit_umin(tmp_id, args): 127 c("uint64_t tmp{0} = MIN({1}, {2});".format(tmp_id, args[1], args[0])) 128 return tmp_id + 1 129 130def emit_lshft(tmp_id, args): 131 c("uint64_t tmp{0} = {1} << {2};".format(tmp_id, args[1], args[0])) 132 return tmp_id + 1 133 134def emit_rshft(tmp_id, args): 135 c("uint64_t tmp{0} = {1} >> {2};".format(tmp_id, args[1], args[0])) 136 return tmp_id + 1 137 138def emit_and(tmp_id, args): 139 c("uint64_t tmp{0} = {1} & {2};".format(tmp_id, args[1], args[0])) 140 return tmp_id + 1 141 142def emit_ulte(tmp_id, args): 143 c("uint64_t tmp{0} = {1} <= {2};".format(tmp_id, args[1], args[0])) 144 return tmp_id + 1 145 146def emit_ult(tmp_id, args): 147 c("uint64_t tmp{0} = {1} < {2};".format(tmp_id, args[1], args[0])) 148 return tmp_id + 1 149 150def emit_ugte(tmp_id, args): 151 c("uint64_t tmp{0} = {1} >= {2};".format(tmp_id, args[1], args[0])) 152 return tmp_id + 1 153 154def emit_ugt(tmp_id, args): 155 c("uint64_t tmp{0} = {1} > {2};".format(tmp_id, args[1], args[0])) 156 return tmp_id + 1 157 158ops = {} 159# (n operands, emitter) 160ops["FADD"] = (2, emit_fadd) 161ops["FDIV"] = (2, emit_fdiv) 162ops["FMAX"] = (2, emit_fmax) 163ops["FMUL"] = (2, emit_fmul) 164ops["FSUB"] = (2, emit_fsub) 165ops["READ"] = (2, emit_read) 166ops["UADD"] = (2, emit_uadd) 167ops["UDIV"] = (2, emit_udiv) 168ops["UMUL"] = (2, emit_umul) 169ops["USUB"] = (2, emit_usub) 170ops["UMIN"] = (2, emit_umin) 171ops["<<"] = (2, emit_lshft) 172ops[">>"] = (2, emit_rshft) 173ops["AND"] = (2, emit_and) 174ops["UGTE"] = (2, emit_ugte) 175ops["UGT"] = (2, emit_ugt) 176ops["ULTE"] = (2, emit_ulte) 177ops["ULT"] = (2, emit_ult) 178 179 180def brkt(subexp): 181 if " " in subexp: 182 return "(" + subexp + ")" 183 else: 184 return subexp 185 186def splice_bitwise_and(args): 187 return brkt(args[1]) + " & " + brkt(args[0]) 188 189def splice_logical_and(args): 190 return brkt(args[1]) + " && " + brkt(args[0]) 191 192def splice_ult(args): 193 return brkt(args[1]) + " < " + brkt(args[0]) 194 195def splice_ugte(args): 196 return brkt(args[1]) + " >= " + brkt(args[0]) 197 198def splice_ulte(args): 199 return brkt(args[1]) + " <= " + brkt(args[0]) 200 201def splice_ugt(args): 202 return brkt(args[1]) + " > " + brkt(args[0]) 203 204exp_ops = {} 205# (n operands, splicer) 206exp_ops["AND"] = (2, splice_bitwise_and) 207exp_ops["UGTE"] = (2, splice_ugte) 208exp_ops["ULT"] = (2, splice_ult) 209exp_ops["&&"] = (2, splice_logical_and) 210 211 212hw_vars = {} 213hw_vars["$EuCoresTotalCount"] = "perf->sys_vars.n_eus" 214hw_vars["$EuSlicesTotalCount"] = "perf->sys_vars.n_eu_slices" 215hw_vars["$EuSubslicesTotalCount"] = "perf->sys_vars.n_eu_sub_slices" 216hw_vars["$EuDualSubslicesTotalCount"] = "perf->sys_vars.n_eu_sub_slices" 217hw_vars["$EuDualSubslicesSlice0123Count"] = "perf->sys_vars.n_eu_slice0123" 218hw_vars["$EuThreadsCount"] = "perf->devinfo.num_thread_per_eu" 219hw_vars["$SliceMask"] = "perf->sys_vars.slice_mask" 220# subslice_mask is interchangeable with subslice/dual-subslice since Gfx12+ 221# only has dual subslices which can be assimilated with 16EUs subslices. 222hw_vars["$SubsliceMask"] = "perf->sys_vars.subslice_mask" 223hw_vars["$DualSubsliceMask"] = "perf->sys_vars.subslice_mask" 224hw_vars["$GpuTimestampFrequency"] = "perf->devinfo.timestamp_frequency" 225hw_vars["$GpuMinFrequency"] = "perf->sys_vars.gt_min_freq" 226hw_vars["$GpuMaxFrequency"] = "perf->sys_vars.gt_max_freq" 227hw_vars["$SkuRevisionId"] = "perf->devinfo.revision" 228hw_vars["$QueryMode"] = "perf->sys_vars.query_mode" 229 230def resolve_variable(name, set, allow_counters): 231 if name in hw_vars: 232 return hw_vars[name] 233 m = re.search('\$GtSlice([0-9]+)$', name) 234 if m: 235 return 'intel_device_info_slice_available(&perf->devinfo, {0})'.format(m.group(1)) 236 m = re.search('\$GtSlice([0-9]+)DualSubslice([0-9]+)$', name) 237 if m: 238 return 'intel_device_info_subslice_available(&perf->devinfo, {0}, {1})'.format(m.group(1), m.group(2)) 239 if allow_counters and name in set.counter_vars: 240 return set.read_funcs[name[1:]] + "(perf, query, results)" 241 return None 242 243def output_rpn_equation_code(set, counter, equation): 244 c("/* RPN equation: " + equation + " */") 245 tokens = equation.split() 246 stack = [] 247 tmp_id = 0 248 tmp = None 249 250 for token in tokens: 251 stack.append(token) 252 while stack and stack[-1] in ops: 253 op = stack.pop() 254 argc, callback = ops[op] 255 args = [] 256 for i in range(0, argc): 257 operand = stack.pop() 258 if operand[0] == "$": 259 resolved_variable = resolve_variable(operand, set, True) 260 if resolved_variable == None: 261 raise Exception("Failed to resolve variable " + operand + " in equation " + equation + " for " + set.name + " :: " + counter.get('name')); 262 operand = resolved_variable 263 args.append(operand) 264 265 tmp_id = callback(tmp_id, args) 266 267 tmp = "tmp{0}".format(tmp_id - 1) 268 stack.append(tmp) 269 270 if len(stack) != 1: 271 raise Exception("Spurious empty rpn code for " + set.name + " :: " + 272 counter.get('name') + ".\nThis is probably due to some unhandled RPN function, in the equation \"" + 273 equation + "\"") 274 275 value = stack[-1] 276 277 if value[0] == "$": 278 resolved_variable = resolve_variable(value, set, True) 279 if resolved_variable == None: 280 raise Exception("Failed to resolve variable " + operand + " in equation " + equation + " for " + set.name + " :: " + counter.get('name')); 281 value = resolved_variable 282 283 c("\nreturn " + value + ";") 284 285def splice_rpn_expression(set, counter, expression): 286 tokens = expression.split() 287 stack = [] 288 289 for token in tokens: 290 stack.append(token) 291 while stack and stack[-1] in exp_ops: 292 op = stack.pop() 293 argc, callback = exp_ops[op] 294 args = [] 295 for i in range(0, argc): 296 operand = stack.pop() 297 if operand[0] == "$": 298 resolved_variable = resolve_variable(operand, set, False) 299 if resolved_variable == None: 300 raise Exception("Failed to resolve variable " + operand + " in expression " + expression + " for " + set.name + " :: " + counter.get('name')) 301 operand = resolved_variable 302 args.append(operand) 303 304 subexp = callback(args) 305 306 stack.append(subexp) 307 308 if len(stack) != 1: 309 raise Exception("Spurious empty rpn expression for " + set.name + " :: " + 310 counter.get('name') + ".\nThis is probably due to some unhandled RPN operation, in the expression \"" + 311 expression + "\"") 312 313 value = stack[-1] 314 315 if value[0] == "$": 316 resolved_variable = resolve_variable(value, set, False) 317 if resolved_variable == None: 318 raise Exception("Failed to resolve variable " + operand + " in expression " + expression + " for " + set.name + " :: " + counter.get('name')) 319 value = resolved_variable 320 321 return value 322 323def output_counter_read(gen, set, counter): 324 c("\n") 325 c("/* {0} :: {1} */".format(set.name, counter.get('name'))) 326 327 if counter.read_hash in hashed_funcs: 328 c("#define %s \\" % counter.read_sym) 329 c_indent(3) 330 c("%s" % hashed_funcs[counter.read_hash]) 331 c_outdent(3) 332 else: 333 ret_type = counter.get('data_type') 334 if ret_type == "uint64": 335 ret_type = "uint64_t" 336 337 read_eq = counter.get('equation') 338 339 c("static " + ret_type) 340 c(counter.read_sym + "(UNUSED struct intel_perf_config *perf,\n") 341 c_indent(len(counter.read_sym) + 1) 342 c("const struct intel_perf_query_info *query,\n") 343 c("const struct intel_perf_query_result *results)\n") 344 c_outdent(len(counter.read_sym) + 1) 345 346 c("{") 347 c_indent(3) 348 output_rpn_equation_code(set, counter, read_eq) 349 c_outdent(3) 350 c("}") 351 352 hashed_funcs[counter.read_hash] = counter.read_sym 353 354 355def output_counter_max(gen, set, counter): 356 max_eq = counter.get('max_equation') 357 358 if not counter.has_custom_max_func(): 359 return 360 361 c("\n") 362 c("/* {0} :: {1} */".format(set.name, counter.get('name'))) 363 364 if counter.max_hash in hashed_funcs: 365 c("#define %s \\" % counter.max_sym) 366 c_indent(3) 367 c("%s" % hashed_funcs[counter.max_hash]) 368 c_outdent(3) 369 else: 370 ret_type = counter.get('data_type') 371 if ret_type == "uint64": 372 ret_type = "uint64_t" 373 374 c("static " + ret_type) 375 c(counter.max_sym + "(struct intel_perf_config *perf,\n") 376 c_indent(len(counter.read_sym) + 1) 377 c("const struct intel_perf_query_info *query,\n") 378 c("const struct intel_perf_query_result *results)\n") 379 c_outdent(len(counter.read_sym) + 1) 380 c("{") 381 c_indent(3) 382 output_rpn_equation_code(set, counter, max_eq) 383 c_outdent(3) 384 c("}") 385 386 hashed_funcs[counter.max_hash] = counter.max_sym 387 388 389c_type_sizes = { "uint32_t": 4, "uint64_t": 8, "float": 4, "double": 8, "bool": 4 } 390def sizeof(c_type): 391 return c_type_sizes[c_type] 392 393def pot_align(base, pot_alignment): 394 return (base + pot_alignment - 1) & ~(pot_alignment - 1); 395 396semantic_type_map = { 397 "duration": "raw", 398 "ratio": "event" 399 } 400 401def output_availability(set, availability, counter_name): 402 expression = splice_rpn_expression(set, counter_name, availability) 403 lines = expression.split(' && ') 404 n_lines = len(lines) 405 if n_lines == 1: 406 c("if (" + lines[0] + ") {") 407 else: 408 c("if (" + lines[0] + " &&") 409 c_indent(4) 410 for i in range(1, (n_lines - 1)): 411 c(lines[i] + " &&") 412 c(lines[(n_lines - 1)] + ") {") 413 c_outdent(4) 414 415 416def output_units(unit): 417 return unit.replace(' ', '_').upper() 418 419 420# should a unit be visible in description? 421units_map = { 422 "bytes" : True, 423 "cycles" : True, 424 "eu atomic requests to l3 cache lines" : False, 425 "eu bytes per l3 cache line" : False, 426 "eu requests to l3 cache lines" : False, 427 "eu sends to l3 cache lines" : False, 428 "events" : True, 429 "hz" : True, 430 "messages" : True, 431 "ns" : True, 432 "number" : False, 433 "percent" : True, 434 "pixels" : True, 435 "texels" : True, 436 "threads" : True, 437 "us" : True, 438 "utilization" : False, 439 } 440 441 442def desc_units(unit): 443 val = units_map.get(unit) 444 if val is None: 445 raise Exception("Unknown unit: " + unit) 446 if val == False: 447 return "" 448 if unit == 'hz': 449 unit = 'Hz' 450 return "Unit: " + unit + "." 451 452 453counter_key_tuple = collections.namedtuple( 454 'counter_key', 455 [ 456 'name', 457 'description', 458 'symbol_name', 459 'mdapi_group', 460 'semantic_type', 461 'data_type', 462 'units', 463 ] 464) 465 466 467def counter_key(counter): 468 return counter_key_tuple._make([counter.get(field) for field in counter_key_tuple._fields]) 469 470 471def output_counter_struct(set, counter, idx, 472 name_to_idx, desc_to_idx, 473 symbol_name_to_idx, category_to_idx): 474 data_type = counter.data_type 475 data_type_uc = data_type.upper() 476 477 semantic_type = counter.semantic_type 478 if semantic_type in semantic_type_map: 479 semantic_type = semantic_type_map[semantic_type] 480 481 semantic_type_uc = semantic_type.upper() 482 483 c("[" + str(idx) + "] = {\n") 484 c_indent(3) 485 c(".name_idx = " + str(name_to_idx[counter.name]) + ",\n") 486 c(".desc_idx = " + str(desc_to_idx[counter.description + " " + desc_units(counter.units)]) + ",\n") 487 c(".symbol_name_idx = " + str(symbol_name_to_idx[counter.symbol_name]) + ",\n") 488 c(".category_idx = " + str(category_to_idx[counter.mdapi_group]) + ",\n") 489 c(".type = INTEL_PERF_COUNTER_TYPE_" + semantic_type_uc + ",\n") 490 c(".data_type = INTEL_PERF_COUNTER_DATA_TYPE_" + data_type_uc + ",\n") 491 c(".units = INTEL_PERF_COUNTER_UNITS_" + output_units(counter.units) + ",\n") 492 c_outdent(3) 493 c("},\n") 494 495 496def output_counter_report(set, counter, counter_to_idx, current_offset): 497 data_type = counter.get('data_type') 498 data_type_uc = data_type.upper() 499 c_type = data_type 500 501 if "uint" in c_type: 502 c_type = c_type + "_t" 503 504 semantic_type = counter.get('semantic_type') 505 if semantic_type in semantic_type_map: 506 semantic_type = semantic_type_map[semantic_type] 507 508 semantic_type_uc = semantic_type.upper() 509 510 c("\n") 511 512 availability = counter.get('availability') 513 if availability: 514 output_availability(set, availability, counter.get('name')) 515 c_indent(3) 516 517 key = counter_key(counter) 518 idx = str(counter_to_idx[key]) 519 520 current_offset = pot_align(current_offset, sizeof(c_type)) 521 522 if data_type == 'uint64': 523 c("intel_perf_query_add_counter_uint64(query, " + idx + ", " + 524 str(current_offset) + ", " + 525 set.max_funcs[counter.get('symbol_name')] + "," + 526 set.read_funcs[counter.get('symbol_name')] + ");\n") 527 else: 528 c("intel_perf_query_add_counter_float(query, " + idx + ", " + 529 str(current_offset) + ", " + 530 set.max_funcs[counter.get('symbol_name')] + "," + 531 set.read_funcs[counter.get('symbol_name')] + ");\n") 532 533 534 if availability: 535 c_outdent(3); 536 c("}") 537 538 return current_offset + sizeof(c_type) 539 540 541def str_to_idx_table(strs): 542 sorted_strs = sorted(strs) 543 544 str_to_idx = collections.OrderedDict() 545 str_to_idx[sorted_strs[0]] = 0 546 previous = sorted_strs[0] 547 548 for i in range(1, len(sorted_strs)): 549 str_to_idx[sorted_strs[i]] = str_to_idx[previous] + len(previous) + 1 550 previous = sorted_strs[i] 551 552 return str_to_idx 553 554 555def output_str_table(name: str, str_to_idx): 556 c("\n") 557 c("static const char " + name + "[] = {\n") 558 c_indent(3) 559 c("\n".join(f"/* {idx} */ \"{val}\\0\"" for val, idx in str_to_idx.items())) 560 c_outdent(3) 561 c("};\n") 562 563 564register_types = { 565 'FLEX': 'flex_regs', 566 'NOA': 'mux_regs', 567 'OA': 'b_counter_regs', 568} 569 570def compute_register_lengths(set): 571 register_lengths = {} 572 register_configs = set.findall('register_config') 573 for register_config in register_configs: 574 t = register_types[register_config.get('type')] 575 if t not in register_lengths: 576 register_lengths[t] = len(register_config.findall('register')) 577 else: 578 register_lengths[t] += len(register_config.findall('register')) 579 580 return register_lengths 581 582 583def generate_register_configs(set): 584 register_configs = set.findall('register_config') 585 586 for register_config in register_configs: 587 t = register_types[register_config.get('type')] 588 589 availability = register_config.get('availability') 590 if availability: 591 output_availability(set, availability, register_config.get('type') + ' register config') 592 c_indent(3) 593 594 registers = register_config.findall('register') 595 c("static const struct intel_perf_query_register_prog %s[] = {" % t) 596 c_indent(3) 597 for register in registers: 598 c("{ .reg = %s, .val = %s }," % (register.get('address'), register.get('value'))) 599 c_outdent(3) 600 c("};") 601 c("query->config.%s = %s;" % (t, t)) 602 c("query->config.n_%s = ARRAY_SIZE(%s);" % (t, t)) 603 604 if availability: 605 c_outdent(3) 606 c("}") 607 c("\n") 608 609 610# Wraps a <counter> element from the oa-*.xml files. 611class Counter: 612 def __init__(self, set, xml): 613 self.xml = xml 614 self.set = set 615 self.read_hash = None 616 self.max_hash = None 617 618 self.read_sym = "{0}__{1}__{2}__read".format(self.set.gen.chipset, 619 self.set.underscore_name, 620 self.xml.get('underscore_name')) 621 self.max_sym = self.build_max_sym() 622 623 def get(self, prop): 624 return self.xml.get(prop) 625 626 # Compute the hash of a counter's equation by expanding (including all the 627 # sub-equations it depends on) 628 def compute_hashes(self): 629 if self.read_hash is not None: 630 return 631 632 def replace_token(token): 633 if token[0] != "$": 634 return token 635 if token not in self.set.counter_vars: 636 return token 637 self.set.counter_vars[token].compute_hashes() 638 return self.set.counter_vars[token].read_hash 639 640 read_eq = self.xml.get('equation') 641 self.read_hash = ' '.join(map(replace_token, read_eq.split())) 642 643 max_eq = self.xml.get('max_equation') 644 if max_eq: 645 self.max_hash = ' '.join(map(replace_token, max_eq.split())) 646 647 def has_custom_max_func(self): 648 max_eq = self.xml.get('max_equation') 649 if not max_eq: 650 return False 651 652 try: 653 val = float(max_eq) 654 if val == 100: 655 return False 656 except ValueError: 657 pass 658 659 for token in max_eq.split(): 660 if token[0] == '$' and resolve_variable(token, self.set, True) == None: 661 print("unresolved token " + token) 662 return False 663 return True 664 665 def build_max_sym(self): 666 max_eq = self.xml.get('max_equation') 667 if not max_eq: 668 return "NULL" 669 670 try: 671 val = float(max_eq) 672 if val == 100: 673 if self.xml.get('data_type') == 'uint64': 674 return "percentage_max_uint64" 675 else: 676 return "percentage_max_float" 677 except ValueError: 678 pass 679 680 assert self.has_custom_max_func() 681 return "{0}__{1}__{2}__max".format(self.set.gen.chipset, 682 self.set.underscore_name, 683 self.xml.get('underscore_name')) 684 685 686# Wraps a <set> element from the oa-*.xml files. 687class Set: 688 def __init__(self, gen, xml): 689 self.gen = gen 690 self.xml = xml 691 692 self.counter_vars = {} 693 self.max_funcs = {} 694 self.read_funcs = {} 695 696 xml_counters = self.xml.findall("counter") 697 self.counters = [] 698 for xml_counter in xml_counters: 699 counter = Counter(self, xml_counter) 700 self.counters.append(counter) 701 self.counter_vars['$' + counter.get('symbol_name')] = counter 702 self.read_funcs[counter.get('symbol_name')] = counter.read_sym 703 self.max_funcs[counter.get('symbol_name')] = counter.max_sym 704 705 for counter in self.counters: 706 counter.compute_hashes() 707 708 @property 709 def hw_config_guid(self): 710 return self.xml.get('hw_config_guid') 711 712 @property 713 def name(self): 714 return self.xml.get('name') 715 716 @property 717 def symbol_name(self): 718 return self.xml.get('symbol_name') 719 720 @property 721 def underscore_name(self): 722 return self.xml.get('underscore_name') 723 724 def findall(self, path): 725 return self.xml.findall(path) 726 727 def find(self, path): 728 return self.xml.find(path) 729 730 731# Wraps an entire oa-*.xml file. 732class Gen: 733 def __init__(self, filename): 734 self.filename = filename 735 self.xml = et.parse(self.filename) 736 self.chipset = self.xml.find('.//set').get('chipset').lower() 737 self.sets = [] 738 739 for xml_set in self.xml.findall(".//set"): 740 self.sets.append(Set(self, xml_set)) 741 742 743def main(): 744 global c_file 745 global header_file 746 747 parser = argparse.ArgumentParser() 748 parser.add_argument("--header", help="Header file to write", required=True) 749 parser.add_argument("--code", help="C file to write", required=True) 750 parser.add_argument("xml_files", nargs='+', help="List of xml metrics files to process") 751 752 args = parser.parse_args() 753 754 c_file = open(args.code, 'w') 755 header_file = open(args.header, 'w') 756 757 gens = [] 758 for xml_file in args.xml_files: 759 gens.append(Gen(xml_file)) 760 761 762 copyright = textwrap.dedent("""\ 763 /* Autogenerated file, DO NOT EDIT manually! generated by {} 764 * 765 * Copyright (c) 2015 Intel Corporation 766 * 767 * Permission is hereby granted, free of charge, to any person obtaining a 768 * copy of this software and associated documentation files (the "Software"), 769 * to deal in the Software without restriction, including without limitation 770 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 771 * and/or sell copies of the Software, and to permit persons to whom the 772 * Software is furnished to do so, subject to the following conditions: 773 * 774 * The above copyright notice and this permission notice (including the next 775 * paragraph) shall be included in all copies or substantial portions of the 776 * Software. 777 * 778 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 779 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 780 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 781 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 782 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 783 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 784 * DEALINGS IN THE SOFTWARE. 785 */ 786 787 """).format(os.path.basename(__file__)) 788 789 h(copyright) 790 h(textwrap.dedent("""\ 791 #pragma once 792 793 struct intel_perf_config; 794 795 """)) 796 797 c(copyright) 798 c(textwrap.dedent("""\ 799 #include <stdint.h> 800 #include <stdbool.h> 801 802 #include <drm-uapi/i915_drm.h> 803 804 #include "util/hash_table.h" 805 #include "util/ralloc.h" 806 807 """)) 808 809 c("#include \"" + os.path.basename(args.header) + "\"") 810 811 c(textwrap.dedent("""\ 812 #include "perf/intel_perf.h" 813 #include "perf/intel_perf_setup.h" 814 """)) 815 816 names = builtins.set() 817 descs = builtins.set() 818 symbol_names = builtins.set() 819 categories = builtins.set() 820 for gen in gens: 821 for set in gen.sets: 822 for counter in set.counters: 823 names.add(counter.get('name')) 824 symbol_names.add(counter.get('symbol_name')) 825 descs.add(counter.get('description') + " " + desc_units(counter.get('units'))) 826 categories.add(counter.get('mdapi_group')) 827 828 name_to_idx = str_to_idx_table(names) 829 output_str_table("name", name_to_idx) 830 831 desc_to_idx = str_to_idx_table(descs) 832 output_str_table("desc", desc_to_idx) 833 834 symbol_name_to_idx = str_to_idx_table(symbol_names) 835 output_str_table("symbol_name", symbol_name_to_idx) 836 837 category_to_idx = str_to_idx_table(categories) 838 output_str_table("category", category_to_idx) 839 840 # Print out all equation functions. 841 for gen in gens: 842 for set in gen.sets: 843 for counter in set.counters: 844 output_counter_read(gen, set, counter) 845 output_counter_max(gen, set, counter) 846 847 c("\n") 848 c("static const struct intel_perf_query_counter_data counters[] = {\n") 849 c_indent(3) 850 851 counter_to_idx = collections.OrderedDict() 852 idx = 0 853 for gen in gens: 854 for set in gen.sets: 855 for counter in set.counters: 856 key = counter_key(counter) 857 if key not in counter_to_idx: 858 counter_to_idx[key] = idx 859 output_counter_struct(set, key, idx, 860 name_to_idx, 861 desc_to_idx, 862 symbol_name_to_idx, 863 category_to_idx) 864 idx += 1 865 866 c_outdent(3) 867 c("};\n\n") 868 869 c(textwrap.dedent("""\ 870 static void ATTRIBUTE_NOINLINE 871 intel_perf_query_add_counter_uint64(struct intel_perf_query_info *query, 872 int counter_idx, size_t offset, 873 intel_counter_read_uint64_t oa_counter_max, 874 intel_counter_read_uint64_t oa_counter_read) 875 { 876 struct intel_perf_query_counter *dest = &query->counters[query->n_counters++]; 877 const struct intel_perf_query_counter_data *counter = &counters[counter_idx]; 878 879 dest->name = &name[counter->name_idx]; 880 dest->desc = &desc[counter->desc_idx]; 881 dest->symbol_name = &symbol_name[counter->symbol_name_idx]; 882 dest->category = &category[counter->category_idx]; 883 884 dest->offset = offset; 885 dest->type = counter->type; 886 dest->data_type = counter->data_type; 887 dest->units = counter->units; 888 dest->oa_counter_max_uint64 = oa_counter_max; 889 dest->oa_counter_read_uint64 = oa_counter_read; 890 } 891 892 static void ATTRIBUTE_NOINLINE 893 intel_perf_query_add_counter_float(struct intel_perf_query_info *query, 894 int counter_idx, size_t offset, 895 intel_counter_read_float_t oa_counter_max, 896 intel_counter_read_float_t oa_counter_read) 897 { 898 struct intel_perf_query_counter *dest = &query->counters[query->n_counters++]; 899 const struct intel_perf_query_counter_data *counter = &counters[counter_idx]; 900 901 dest->name = &name[counter->name_idx]; 902 dest->desc = &desc[counter->desc_idx]; 903 dest->symbol_name = &symbol_name[counter->symbol_name_idx]; 904 dest->category = &category[counter->category_idx]; 905 906 dest->offset = offset; 907 dest->type = counter->type; 908 dest->data_type = counter->data_type; 909 dest->units = counter->units; 910 dest->oa_counter_max_float = oa_counter_max; 911 dest->oa_counter_read_float = oa_counter_read; 912 } 913 914 static float ATTRIBUTE_NOINLINE 915 percentage_max_float(struct intel_perf_config *perf, 916 const struct intel_perf_query_info *query, 917 const struct intel_perf_query_result *results) 918 { 919 return 100; 920 } 921 922 static uint64_t ATTRIBUTE_NOINLINE 923 percentage_max_uint64(struct intel_perf_config *perf, 924 const struct intel_perf_query_info *query, 925 const struct intel_perf_query_result *results) 926 { 927 return 100; 928 } 929 """)) 930 931 # Print out all metric sets registration functions for each set in each 932 # generation. 933 for gen in gens: 934 for set in gen.sets: 935 counters = set.counters 936 937 c("\n") 938 c("\nstatic void\n") 939 c("{0}_register_{1}_counter_query(struct intel_perf_config *perf)\n".format(gen.chipset, set.underscore_name)) 940 c("{\n") 941 c_indent(3) 942 943 if gen.chipset == "hsw": 944 c("struct intel_perf_query_info *query = hsw_query_alloc(perf, %u);\n" % len(counters)) 945 else: 946 c("struct intel_perf_query_info *query = bdw_query_alloc(perf, %u);\n" % len(counters)) 947 c("\n") 948 c("query->name = \"" + set.name + "\";\n") 949 c("query->symbol_name = \"" + set.symbol_name + "\";\n") 950 c("query->guid = \"" + set.hw_config_guid + "\";\n") 951 952 c("\n") 953 c("struct intel_perf_query_counter *counter = query->counters;\n") 954 955 c("\n") 956 c("/* Note: we're assuming there can't be any variation in the definition ") 957 c(" * of a query between contexts so it's ok to describe a query within a ") 958 c(" * global variable which only needs to be initialized once... */") 959 c("\nif (!query->data_size) {") 960 c_indent(3) 961 962 generate_register_configs(set) 963 964 offset = 0 965 for counter in counters: 966 offset = output_counter_report(set, counter, counter_to_idx, offset) 967 968 969 c("\ncounter = &query->counters[query->n_counters - 1];\n") 970 c("query->data_size = counter->offset + intel_perf_query_counter_get_size(counter);\n") 971 972 c_outdent(3) 973 c("}"); 974 975 c("\n_mesa_hash_table_insert(perf->oa_metrics_table, query->guid, query);") 976 977 c_outdent(3) 978 c("}\n") 979 980 h("void intel_oa_register_queries_" + gen.chipset + "(struct intel_perf_config *perf);\n") 981 982 c("\nvoid") 983 c("intel_oa_register_queries_" + gen.chipset + "(struct intel_perf_config *perf)") 984 c("{") 985 c_indent(3) 986 987 for set in gen.sets: 988 c("{0}_register_{1}_counter_query(perf);".format(gen.chipset, set.underscore_name)) 989 990 c_outdent(3) 991 c("}") 992 993 994if __name__ == '__main__': 995 main() 996