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 os 24import sys 25import textwrap 26 27import xml.etree.ElementTree as et 28 29hashed_funcs = {} 30 31c_file = None 32_c_indent = 0 33 34def c(*args): 35 code = ' '.join(map(str,args)) 36 for line in code.splitlines(): 37 text = ''.rjust(_c_indent) + line 38 c_file.write(text.rstrip() + "\n") 39 40# indented, but no trailing newline... 41def c_line_start(code): 42 c_file.write(''.rjust(_c_indent) + code) 43def c_raw(code): 44 c_file.write(code) 45 46def c_indent(n): 47 global _c_indent 48 _c_indent = _c_indent + n 49def c_outdent(n): 50 global _c_indent 51 _c_indent = _c_indent - n 52 53header_file = None 54_h_indent = 0 55 56def h(*args): 57 code = ' '.join(map(str,args)) 58 for line in code.splitlines(): 59 text = ''.rjust(_h_indent) + line 60 header_file.write(text.rstrip() + "\n") 61 62def h_indent(n): 63 global _c_indent 64 _h_indent = _h_indent + n 65def h_outdent(n): 66 global _c_indent 67 _h_indent = _h_indent - n 68 69 70def emit_fadd(tmp_id, args): 71 c("double tmp{0} = {1} + {2};".format(tmp_id, args[1], args[0])) 72 return tmp_id + 1 73 74# Be careful to check for divide by zero... 75def emit_fdiv(tmp_id, args): 76 c("double tmp{0} = {1};".format(tmp_id, args[1])) 77 c("double tmp{0} = {1};".format(tmp_id + 1, args[0])) 78 c("double tmp{0} = tmp{1} ? tmp{2} / tmp{1} : 0;".format(tmp_id + 2, tmp_id + 1, tmp_id)) 79 return tmp_id + 3 80 81def emit_fmax(tmp_id, args): 82 c("double tmp{0} = {1};".format(tmp_id, args[1])) 83 c("double tmp{0} = {1};".format(tmp_id + 1, args[0])) 84 c("double tmp{0} = MAX(tmp{1}, tmp{2});".format(tmp_id + 2, tmp_id, tmp_id + 1)) 85 return tmp_id + 3 86 87def emit_fmul(tmp_id, args): 88 c("double tmp{0} = {1} * {2};".format(tmp_id, args[1], args[0])) 89 return tmp_id + 1 90 91def emit_fsub(tmp_id, args): 92 c("double tmp{0} = {1} - {2};".format(tmp_id, args[1], args[0])) 93 return tmp_id + 1 94 95def emit_read(tmp_id, args): 96 type = args[1].lower() 97 c("uint64_t tmp{0} = results->accumulator[query->{1}_offset + {2}];".format(tmp_id, type, args[0])) 98 return tmp_id + 1 99 100def emit_uadd(tmp_id, args): 101 c("uint64_t tmp{0} = {1} + {2};".format(tmp_id, args[1], args[0])) 102 return tmp_id + 1 103 104# Be careful to check for divide by zero... 105def emit_udiv(tmp_id, args): 106 c("uint64_t tmp{0} = {1};".format(tmp_id, args[1])) 107 c("uint64_t tmp{0} = {1};".format(tmp_id + 1, args[0])) 108 if args[0].isdigit(): 109 assert int(args[0]) > 0 110 c("uint64_t tmp{0} = tmp{2} / tmp{1};".format(tmp_id + 2, tmp_id + 1, tmp_id)) 111 else: 112 c("uint64_t tmp{0} = tmp{1} ? tmp{2} / tmp{1} : 0;".format(tmp_id + 2, tmp_id + 1, tmp_id)) 113 return tmp_id + 3 114 115def emit_umul(tmp_id, args): 116 c("uint64_t tmp{0} = {1} * {2};".format(tmp_id, args[1], args[0])) 117 return tmp_id + 1 118 119def emit_usub(tmp_id, args): 120 c("uint64_t tmp{0} = {1} - {2};".format(tmp_id, args[1], args[0])) 121 return tmp_id + 1 122 123def emit_umin(tmp_id, args): 124 c("uint64_t tmp{0} = MIN({1}, {2});".format(tmp_id, args[1], args[0])) 125 return tmp_id + 1 126 127def emit_lshft(tmp_id, args): 128 c("uint64_t tmp{0} = {1} << {2};".format(tmp_id, args[1], args[0])) 129 return tmp_id + 1 130 131def emit_rshft(tmp_id, args): 132 c("uint64_t tmp{0} = {1} >> {2};".format(tmp_id, args[1], args[0])) 133 return tmp_id + 1 134 135def emit_and(tmp_id, args): 136 c("uint64_t tmp{0} = {1} & {2};".format(tmp_id, args[1], args[0])) 137 return tmp_id + 1 138 139ops = {} 140# (n operands, emitter) 141ops["FADD"] = (2, emit_fadd) 142ops["FDIV"] = (2, emit_fdiv) 143ops["FMAX"] = (2, emit_fmax) 144ops["FMUL"] = (2, emit_fmul) 145ops["FSUB"] = (2, emit_fsub) 146ops["READ"] = (2, emit_read) 147ops["UADD"] = (2, emit_uadd) 148ops["UDIV"] = (2, emit_udiv) 149ops["UMUL"] = (2, emit_umul) 150ops["USUB"] = (2, emit_usub) 151ops["UMIN"] = (2, emit_umin) 152ops["<<"] = (2, emit_lshft) 153ops[">>"] = (2, emit_rshft) 154ops["AND"] = (2, emit_and) 155 156def brkt(subexp): 157 if " " in subexp: 158 return "(" + subexp + ")" 159 else: 160 return subexp 161 162def splice_bitwise_and(args): 163 return brkt(args[1]) + " & " + brkt(args[0]) 164 165def splice_logical_and(args): 166 return brkt(args[1]) + " && " + brkt(args[0]) 167 168def splice_ult(args): 169 return brkt(args[1]) + " < " + brkt(args[0]) 170 171def splice_ugte(args): 172 return brkt(args[1]) + " >= " + brkt(args[0]) 173 174exp_ops = {} 175# (n operands, splicer) 176exp_ops["AND"] = (2, splice_bitwise_and) 177exp_ops["UGTE"] = (2, splice_ugte) 178exp_ops["ULT"] = (2, splice_ult) 179exp_ops["&&"] = (2, splice_logical_and) 180 181 182hw_vars = {} 183hw_vars["$EuCoresTotalCount"] = "perf->sys_vars.n_eus" 184hw_vars["$EuSlicesTotalCount"] = "perf->sys_vars.n_eu_slices" 185hw_vars["$EuSubslicesTotalCount"] = "perf->sys_vars.n_eu_sub_slices" 186hw_vars["$EuThreadsCount"] = "perf->sys_vars.eu_threads_count" 187hw_vars["$SliceMask"] = "perf->sys_vars.slice_mask" 188# subslice_mask is interchangeable with subslice/dual-subslice since Gfx12+ 189# only has dual subslices which can be assimilated with 16EUs subslices. 190hw_vars["$SubsliceMask"] = "perf->sys_vars.subslice_mask" 191hw_vars["$DualSubsliceMask"] = "perf->sys_vars.subslice_mask" 192hw_vars["$GpuTimestampFrequency"] = "perf->sys_vars.timestamp_frequency" 193hw_vars["$GpuMinFrequency"] = "perf->sys_vars.gt_min_freq" 194hw_vars["$GpuMaxFrequency"] = "perf->sys_vars.gt_max_freq" 195hw_vars["$SkuRevisionId"] = "perf->sys_vars.revision" 196hw_vars["$QueryMode"] = "perf->sys_vars.query_mode" 197 198def output_rpn_equation_code(set, counter, equation): 199 c("/* RPN equation: " + equation + " */") 200 tokens = equation.split() 201 stack = [] 202 tmp_id = 0 203 tmp = None 204 205 for token in tokens: 206 stack.append(token) 207 while stack and stack[-1] in ops: 208 op = stack.pop() 209 argc, callback = ops[op] 210 args = [] 211 for i in range(0, argc): 212 operand = stack.pop() 213 if operand[0] == "$": 214 if operand in hw_vars: 215 operand = hw_vars[operand] 216 elif operand in set.counter_vars: 217 reference = set.counter_vars[operand] 218 operand = set.read_funcs[operand[1:]] + "(perf, query, results)" 219 else: 220 raise Exception("Failed to resolve variable " + operand + " in equation " + equation + " for " + set.name + " :: " + counter.get('name')); 221 args.append(operand) 222 223 tmp_id = callback(tmp_id, args) 224 225 tmp = "tmp{0}".format(tmp_id - 1) 226 stack.append(tmp) 227 228 if len(stack) != 1: 229 raise Exception("Spurious empty rpn code for " + set.name + " :: " + 230 counter.get('name') + ".\nThis is probably due to some unhandled RPN function, in the equation \"" + 231 equation + "\"") 232 233 value = stack[-1] 234 235 if value in hw_vars: 236 value = hw_vars[value] 237 if value in set.counter_vars: 238 value = set.read_funcs[value[1:]] + "(perf, query, results)" 239 240 c("\nreturn " + value + ";") 241 242def splice_rpn_expression(set, counter, expression): 243 tokens = expression.split() 244 stack = [] 245 246 for token in tokens: 247 stack.append(token) 248 while stack and stack[-1] in exp_ops: 249 op = stack.pop() 250 argc, callback = exp_ops[op] 251 args = [] 252 for i in range(0, argc): 253 operand = stack.pop() 254 if operand[0] == "$": 255 if operand in hw_vars: 256 operand = hw_vars[operand] 257 else: 258 raise Exception("Failed to resolve variable " + operand + " in expression " + expression + " for " + set.name + " :: " + counter.get('name')); 259 args.append(operand) 260 261 subexp = callback(args) 262 263 stack.append(subexp) 264 265 if len(stack) != 1: 266 raise Exception("Spurious empty rpn expression for " + set.name + " :: " + 267 counter.get('name') + ".\nThis is probably due to some unhandled RPN operation, in the expression \"" + 268 expression + "\"") 269 270 return stack[-1] 271 272def output_counter_read(gen, set, counter): 273 c("\n") 274 c("/* {0} :: {1} */".format(set.name, counter.get('name'))) 275 276 if counter.read_hash in hashed_funcs: 277 c("#define %s \\" % counter.read_sym) 278 c_indent(3) 279 c("%s" % hashed_funcs[counter.read_hash]) 280 c_outdent(3) 281 else: 282 ret_type = counter.get('data_type') 283 if ret_type == "uint64": 284 ret_type = "uint64_t" 285 286 read_eq = counter.get('equation') 287 288 c("static " + ret_type) 289 c(counter.read_sym + "(UNUSED struct intel_perf_config *perf,\n") 290 c_indent(len(counter.read_sym) + 1) 291 c("const struct intel_perf_query_info *query,\n") 292 c("const struct intel_perf_query_result *results)\n") 293 c_outdent(len(counter.read_sym) + 1) 294 295 c("{") 296 c_indent(3) 297 output_rpn_equation_code(set, counter, read_eq) 298 c_outdent(3) 299 c("}") 300 301 hashed_funcs[counter.read_hash] = counter.read_sym 302 303 304def output_counter_max(gen, set, counter): 305 max_eq = counter.get('max_equation') 306 307 if not counter.has_max_func(): 308 return 309 310 c("\n") 311 c("/* {0} :: {1} */".format(set.name, counter.get('name'))) 312 313 if counter.max_hash in hashed_funcs: 314 c("#define %s \\" % counter.max_sym()) 315 c_indent(3) 316 c("%s" % hashed_funcs[counter.max_hash]) 317 c_outdent(3) 318 else: 319 ret_type = counter.get('data_type') 320 if ret_type == "uint64": 321 ret_type = "uint64_t" 322 323 c("static " + ret_type) 324 c(counter.max_sym() + "(struct intel_perf_config *perf)\n") 325 c("{") 326 c_indent(3) 327 output_rpn_equation_code(set, counter, max_eq) 328 c_outdent(3) 329 c("}") 330 331 hashed_funcs[counter.max_hash] = counter.max_sym() 332 333 334c_type_sizes = { "uint32_t": 4, "uint64_t": 8, "float": 4, "double": 8, "bool": 4 } 335def sizeof(c_type): 336 return c_type_sizes[c_type] 337 338def pot_align(base, pot_alignment): 339 return (base + pot_alignment - 1) & ~(pot_alignment - 1); 340 341semantic_type_map = { 342 "duration": "raw", 343 "ratio": "event" 344 } 345 346def output_availability(set, availability, counter_name): 347 expression = splice_rpn_expression(set, counter_name, availability) 348 lines = expression.split(' && ') 349 n_lines = len(lines) 350 if n_lines == 1: 351 c("if (" + lines[0] + ") {") 352 else: 353 c("if (" + lines[0] + " &&") 354 c_indent(4) 355 for i in range(1, (n_lines - 1)): 356 c(lines[i] + " &&") 357 c(lines[(n_lines - 1)] + ") {") 358 c_outdent(4) 359 360 361def output_units(unit): 362 return unit.replace(' ', '_').upper() 363 364 365# should a unit be visible in description? 366units_map = { 367 "bytes" : True, 368 "cycles" : True, 369 "eu atomic requests to l3 cache lines" : False, 370 "eu bytes per l3 cache line" : False, 371 "eu requests to l3 cache lines" : False, 372 "eu sends to l3 cache lines" : False, 373 "events" : True, 374 "hz" : True, 375 "messages" : True, 376 "ns" : True, 377 "number" : False, 378 "percent" : True, 379 "pixels" : True, 380 "texels" : True, 381 "threads" : True, 382 "us" : True, 383 "utilization" : False, 384 } 385 386 387def desc_units(unit): 388 val = units_map.get(unit) 389 if val is None: 390 raise Exception("Unknown unit: " + unit) 391 if val == False: 392 return "" 393 if unit == 'hz': 394 unit = 'Hz' 395 return " Unit: " + unit + "." 396 397 398def output_counter_report(set, counter, current_offset): 399 data_type = counter.get('data_type') 400 data_type_uc = data_type.upper() 401 c_type = data_type 402 403 if "uint" in c_type: 404 c_type = c_type + "_t" 405 406 semantic_type = counter.get('semantic_type') 407 if semantic_type in semantic_type_map: 408 semantic_type = semantic_type_map[semantic_type] 409 410 semantic_type_uc = semantic_type.upper() 411 412 c("\n") 413 414 availability = counter.get('availability') 415 if availability: 416 output_availability(set, availability, counter.get('name')) 417 c_indent(3) 418 419 c("counter = &query->counters[query->n_counters++];\n") 420 c("counter->oa_counter_read_" + data_type + " = " + set.read_funcs[counter.get('symbol_name')] + ";\n") 421 c("counter->name = \"" + counter.get('name') + "\";\n") 422 c("counter->desc = \"" + counter.get('description') + desc_units(counter.get('units')) + "\";\n") 423 c("counter->symbol_name = \"" + counter.get('symbol_name') + "\";\n") 424 c("counter->category = \"" + counter.get('mdapi_group') + "\";\n") 425 c("counter->type = INTEL_PERF_COUNTER_TYPE_" + semantic_type_uc + ";\n") 426 c("counter->data_type = INTEL_PERF_COUNTER_DATA_TYPE_" + data_type_uc + ";\n") 427 c("counter->units = INTEL_PERF_COUNTER_UNITS_" + output_units(counter.get('units')) + ";\n") 428 c("counter->raw_max = " + set.max_values[counter.get('symbol_name')] + ";\n") 429 430 current_offset = pot_align(current_offset, sizeof(c_type)) 431 c("counter->offset = " + str(current_offset) + ";\n") 432 433 if availability: 434 c_outdent(3); 435 c("}") 436 437 return current_offset + sizeof(c_type) 438 439 440register_types = { 441 'FLEX': 'flex_regs', 442 'NOA': 'mux_regs', 443 'OA': 'b_counter_regs', 444} 445 446def compute_register_lengths(set): 447 register_lengths = {} 448 register_configs = set.findall('register_config') 449 for register_config in register_configs: 450 t = register_types[register_config.get('type')] 451 if t not in register_lengths: 452 register_lengths[t] = len(register_config.findall('register')) 453 else: 454 register_lengths[t] += len(register_config.findall('register')) 455 456 return register_lengths 457 458 459def generate_register_configs(set): 460 register_configs = set.findall('register_config') 461 462 for register_config in register_configs: 463 t = register_types[register_config.get('type')] 464 465 availability = register_config.get('availability') 466 if availability: 467 output_availability(set, availability, register_config.get('type') + ' register config') 468 c_indent(3) 469 470 registers = register_config.findall('register') 471 c("static const struct intel_perf_query_register_prog %s[] = {" % t) 472 c_indent(3) 473 for register in registers: 474 c("{ .reg = %s, .val = %s }," % (register.get('address'), register.get('value'))) 475 c_outdent(3) 476 c("};") 477 c("query->config.%s = %s;" % (t, t)) 478 c("query->config.n_%s = ARRAY_SIZE(%s);" % (t, t)) 479 480 if availability: 481 c_outdent(3) 482 c("}") 483 c("\n") 484 485 486# Wraps a <counter> element from the oa-*.xml files. 487class Counter: 488 def __init__(self, set, xml): 489 self.xml = xml 490 self.set = set 491 self.read_hash = None 492 self.max_hash = None 493 494 self.read_sym = "{0}__{1}__{2}__read".format(self.set.gen.chipset, 495 self.set.underscore_name, 496 self.xml.get('underscore_name')) 497 498 def get(self, prop): 499 return self.xml.get(prop) 500 501 # Compute the hash of a counter's equation by expanding (including all the 502 # sub-equations it depends on) 503 def compute_hashes(self): 504 if self.read_hash is not None: 505 return 506 507 def replace_token(token): 508 if token[0] != "$": 509 return token 510 if token not in self.set.counter_vars: 511 return token 512 self.set.counter_vars[token].compute_hashes() 513 return self.set.counter_vars[token].read_hash 514 515 read_eq = self.xml.get('equation') 516 self.read_hash = ' '.join(map(replace_token, read_eq.split())) 517 518 max_eq = self.xml.get('max_equation') 519 if max_eq: 520 self.max_hash = ' '.join(map(replace_token, max_eq.split())) 521 522 def has_max_func(self): 523 max_eq = self.xml.get('max_equation') 524 if not max_eq: 525 return False 526 527 try: 528 val = float(max_eq) 529 return False 530 except ValueError: 531 pass 532 533 for token in max_eq.split(): 534 if token[0] == '$' and token not in hw_vars: 535 return False 536 return True 537 538 def max_sym(self): 539 assert self.has_max_func() 540 return "{0}__{1}__{2}__max".format(self.set.gen.chipset, 541 self.set.underscore_name, 542 self.xml.get('underscore_name')) 543 544 def max_value(self): 545 max_eq = self.xml.get('max_equation') 546 if not max_eq: 547 return "0 /* undefined */" 548 549 try: 550 return "{0}".format(float(max_eq)) 551 except ValueError: 552 pass 553 554 for token in max_eq.split(): 555 if token[0] == '$' and token not in hw_vars: 556 return "0 /* unsupported (varies over time) */" 557 558 return "{0}__{1}__{2}__max(perf)".format(self.set.gen.chipset, 559 self.set.underscore_name, 560 self.xml.get('underscore_name')) 561 562# Wraps a <set> element from the oa-*.xml files. 563class Set: 564 def __init__(self, gen, xml): 565 self.gen = gen 566 self.xml = xml 567 568 self.counter_vars = {} 569 self.max_values = {} 570 self.read_funcs = {} 571 572 xml_counters = self.xml.findall("counter") 573 self.counters = [] 574 for xml_counter in xml_counters: 575 counter = Counter(self, xml_counter) 576 self.counters.append(counter) 577 self.counter_vars["$" + counter.get('symbol_name')] = counter 578 self.read_funcs[counter.get('symbol_name')] = counter.read_sym 579 self.max_values[counter.get('symbol_name')] = counter.max_value() 580 581 for counter in self.counters: 582 counter.compute_hashes() 583 584 @property 585 def hw_config_guid(self): 586 return self.xml.get('hw_config_guid') 587 588 @property 589 def name(self): 590 return self.xml.get('name') 591 592 @property 593 def symbol_name(self): 594 return self.xml.get('symbol_name') 595 596 @property 597 def underscore_name(self): 598 return self.xml.get('underscore_name') 599 600 def findall(self, path): 601 return self.xml.findall(path) 602 603 def find(self, path): 604 return self.xml.find(path) 605 606 607# Wraps an entire oa-*.xml file. 608class Gen: 609 def __init__(self, filename): 610 self.filename = filename 611 self.xml = et.parse(self.filename) 612 self.chipset = self.xml.find('.//set').get('chipset').lower() 613 self.sets = [] 614 615 for xml_set in self.xml.findall(".//set"): 616 self.sets.append(Set(self, xml_set)) 617 618 619def main(): 620 global c_file 621 global header_file 622 623 parser = argparse.ArgumentParser() 624 parser.add_argument("--header", help="Header file to write", required=True) 625 parser.add_argument("--code", help="C file to write", required=True) 626 parser.add_argument("xml_files", nargs='+', help="List of xml metrics files to process") 627 628 args = parser.parse_args() 629 630 c_file = open(args.code, 'w') 631 header_file = open(args.header, 'w') 632 633 gens = [] 634 for xml_file in args.xml_files: 635 gens.append(Gen(xml_file)) 636 637 638 copyright = textwrap.dedent("""\ 639 /* Autogenerated file, DO NOT EDIT manually! generated by {} 640 * 641 * Copyright (c) 2015 Intel Corporation 642 * 643 * Permission is hereby granted, free of charge, to any person obtaining a 644 * copy of this software and associated documentation files (the "Software"), 645 * to deal in the Software without restriction, including without limitation 646 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 647 * and/or sell copies of the Software, and to permit persons to whom the 648 * Software is furnished to do so, subject to the following conditions: 649 * 650 * The above copyright notice and this permission notice (including the next 651 * paragraph) shall be included in all copies or substantial portions of the 652 * Software. 653 * 654 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 655 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 656 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 657 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 658 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 659 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 660 * DEALINGS IN THE SOFTWARE. 661 */ 662 663 """).format(os.path.basename(__file__)) 664 665 h(copyright) 666 h(textwrap.dedent("""\ 667 #pragma once 668 669 struct intel_perf_config; 670 671 """)) 672 673 c(copyright) 674 c(textwrap.dedent("""\ 675 #include <stdint.h> 676 #include <stdbool.h> 677 678 #include <drm-uapi/i915_drm.h> 679 680 #include "util/hash_table.h" 681 #include "util/ralloc.h" 682 683 """)) 684 685 c("#include \"" + os.path.basename(args.header) + "\"") 686 687 c(textwrap.dedent("""\ 688 #include "perf/intel_perf.h" 689 690 691 #define MIN(a, b) ((a < b) ? (a) : (b)) 692 #define MAX(a, b) ((a > b) ? (a) : (b)) 693 694 695 """)) 696 697 # Print out all equation functions. 698 for gen in gens: 699 for set in gen.sets: 700 for counter in set.counters: 701 output_counter_read(gen, set, counter) 702 output_counter_max(gen, set, counter) 703 704 # Print out all metric sets registration functions for each set in each 705 # generation. 706 for gen in gens: 707 for set in gen.sets: 708 counters = set.counters 709 710 c("\n") 711 c("\nstatic void\n") 712 c("{0}_register_{1}_counter_query(struct intel_perf_config *perf)\n".format(gen.chipset, set.underscore_name)) 713 c("{\n") 714 c_indent(3) 715 716 c("struct intel_perf_query_info *query = rzalloc(perf, struct intel_perf_query_info);\n") 717 c("\n") 718 c("query->perf = perf;\n") 719 c("query->kind = INTEL_PERF_QUERY_TYPE_OA;\n") 720 c("query->name = \"" + set.name + "\";\n") 721 c("query->symbol_name = \"" + set.symbol_name + "\";\n") 722 c("query->guid = \"" + set.hw_config_guid + "\";\n") 723 724 c("query->counters = rzalloc_array(query, struct intel_perf_query_counter, %u);" % len(counters)) 725 c("query->n_counters = 0;") 726 c("query->oa_metrics_set_id = 0; /* determined at runtime, via sysfs */") 727 728 if gen.chipset == "hsw": 729 c(textwrap.dedent("""\ 730 query->oa_format = I915_OA_FORMAT_A45_B8_C8; 731 /* Accumulation buffer offsets... */ 732 query->gpu_time_offset = 0; 733 query->a_offset = query->gpu_time_offset + 1; 734 query->b_offset = query->a_offset + 45; 735 query->c_offset = query->b_offset + 8; 736 query->perfcnt_offset = query->c_offset + 8; 737 query->rpstat_offset = query->perfcnt_offset + 2; 738 """)) 739 else: 740 c(textwrap.dedent("""\ 741 query->oa_format = I915_OA_FORMAT_A32u40_A4u32_B8_C8; 742 /* Accumulation buffer offsets... */ 743 query->gpu_time_offset = 0; 744 query->gpu_clock_offset = query->gpu_time_offset + 1; 745 query->a_offset = query->gpu_clock_offset + 1; 746 query->b_offset = query->a_offset + 36; 747 query->c_offset = query->b_offset + 8; 748 query->perfcnt_offset = query->c_offset + 8; 749 query->rpstat_offset = query->perfcnt_offset + 2; 750 """)) 751 752 753 c("\n") 754 c("struct intel_perf_query_counter *counter = query->counters;\n") 755 756 c("\n") 757 c("/* Note: we're assuming there can't be any variation in the definition ") 758 c(" * of a query between contexts so it's ok to describe a query within a ") 759 c(" * global variable which only needs to be initialized once... */") 760 c("\nif (!query->data_size) {") 761 c_indent(3) 762 763 generate_register_configs(set) 764 765 offset = 0 766 for counter in counters: 767 offset = output_counter_report(set, counter, offset) 768 769 770 c("\nquery->data_size = counter->offset + intel_perf_query_counter_get_size(counter);\n") 771 772 c_outdent(3) 773 c("}"); 774 775 c("\n_mesa_hash_table_insert(perf->oa_metrics_table, query->guid, query);") 776 777 c_outdent(3) 778 c("}\n") 779 780 h("void intel_oa_register_queries_" + gen.chipset + "(struct intel_perf_config *perf);\n") 781 782 c("\nvoid") 783 c("intel_oa_register_queries_" + gen.chipset + "(struct intel_perf_config *perf)") 784 c("{") 785 c_indent(3) 786 787 for set in gen.sets: 788 c("{0}_register_{1}_counter_query(perf);".format(gen.chipset, set.underscore_name)) 789 790 c_outdent(3) 791 c("}") 792 793 794if __name__ == '__main__': 795 main() 796