19f464c52Smaya# Copyright (c) 2015-2017 Intel Corporation 29f464c52Smaya# 39f464c52Smaya# Permission is hereby granted, free of charge, to any person obtaining a 49f464c52Smaya# copy of this software and associated documentation files (the "Software"), 59f464c52Smaya# to deal in the Software without restriction, including without limitation 69f464c52Smaya# the rights to use, copy, modify, merge, publish, distribute, sublicense, 79f464c52Smaya# and/or sell copies of the Software, and to permit persons to whom the 89f464c52Smaya# Software is furnished to do so, subject to the following conditions: 99f464c52Smaya# 109f464c52Smaya# The above copyright notice and this permission notice (including the next 119f464c52Smaya# paragraph) shall be included in all copies or substantial portions of the 129f464c52Smaya# Software. 139f464c52Smaya# 149f464c52Smaya# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 159f464c52Smaya# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 169f464c52Smaya# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 179f464c52Smaya# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 189f464c52Smaya# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 199f464c52Smaya# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 209f464c52Smaya# IN THE SOFTWARE. 219f464c52Smaya 229f464c52Smayaimport argparse 239f464c52Smayaimport os 249f464c52Smayaimport sys 259f464c52Smayaimport textwrap 269f464c52Smaya 277ec681f3Smrgimport xml.etree.ElementTree as et 289f464c52Smaya 299f464c52Smayahashed_funcs = {} 309f464c52Smaya 319f464c52Smayac_file = None 329f464c52Smaya_c_indent = 0 339f464c52Smaya 349f464c52Smayadef c(*args): 359f464c52Smaya code = ' '.join(map(str,args)) 369f464c52Smaya for line in code.splitlines(): 379f464c52Smaya text = ''.rjust(_c_indent) + line 389f464c52Smaya c_file.write(text.rstrip() + "\n") 399f464c52Smaya 409f464c52Smaya# indented, but no trailing newline... 419f464c52Smayadef c_line_start(code): 429f464c52Smaya c_file.write(''.rjust(_c_indent) + code) 439f464c52Smayadef c_raw(code): 449f464c52Smaya c_file.write(code) 459f464c52Smaya 469f464c52Smayadef c_indent(n): 479f464c52Smaya global _c_indent 489f464c52Smaya _c_indent = _c_indent + n 499f464c52Smayadef c_outdent(n): 509f464c52Smaya global _c_indent 519f464c52Smaya _c_indent = _c_indent - n 529f464c52Smaya 539f464c52Smayaheader_file = None 549f464c52Smaya_h_indent = 0 559f464c52Smaya 569f464c52Smayadef h(*args): 579f464c52Smaya code = ' '.join(map(str,args)) 589f464c52Smaya for line in code.splitlines(): 599f464c52Smaya text = ''.rjust(_h_indent) + line 609f464c52Smaya header_file.write(text.rstrip() + "\n") 619f464c52Smaya 629f464c52Smayadef h_indent(n): 639f464c52Smaya global _c_indent 649f464c52Smaya _h_indent = _h_indent + n 659f464c52Smayadef h_outdent(n): 669f464c52Smaya global _c_indent 679f464c52Smaya _h_indent = _h_indent - n 689f464c52Smaya 699f464c52Smaya 709f464c52Smayadef emit_fadd(tmp_id, args): 719f464c52Smaya c("double tmp{0} = {1} + {2};".format(tmp_id, args[1], args[0])) 729f464c52Smaya return tmp_id + 1 739f464c52Smaya 749f464c52Smaya# Be careful to check for divide by zero... 759f464c52Smayadef emit_fdiv(tmp_id, args): 769f464c52Smaya c("double tmp{0} = {1};".format(tmp_id, args[1])) 779f464c52Smaya c("double tmp{0} = {1};".format(tmp_id + 1, args[0])) 789f464c52Smaya c("double tmp{0} = tmp{1} ? tmp{2} / tmp{1} : 0;".format(tmp_id + 2, tmp_id + 1, tmp_id)) 799f464c52Smaya return tmp_id + 3 809f464c52Smaya 819f464c52Smayadef emit_fmax(tmp_id, args): 829f464c52Smaya c("double tmp{0} = {1};".format(tmp_id, args[1])) 839f464c52Smaya c("double tmp{0} = {1};".format(tmp_id + 1, args[0])) 849f464c52Smaya c("double tmp{0} = MAX(tmp{1}, tmp{2});".format(tmp_id + 2, tmp_id, tmp_id + 1)) 859f464c52Smaya return tmp_id + 3 869f464c52Smaya 879f464c52Smayadef emit_fmul(tmp_id, args): 889f464c52Smaya c("double tmp{0} = {1} * {2};".format(tmp_id, args[1], args[0])) 899f464c52Smaya return tmp_id + 1 909f464c52Smaya 919f464c52Smayadef emit_fsub(tmp_id, args): 929f464c52Smaya c("double tmp{0} = {1} - {2};".format(tmp_id, args[1], args[0])) 939f464c52Smaya return tmp_id + 1 949f464c52Smaya 959f464c52Smayadef emit_read(tmp_id, args): 969f464c52Smaya type = args[1].lower() 977ec681f3Smrg c("uint64_t tmp{0} = results->accumulator[query->{1}_offset + {2}];".format(tmp_id, type, args[0])) 989f464c52Smaya return tmp_id + 1 999f464c52Smaya 1009f464c52Smayadef emit_uadd(tmp_id, args): 1019f464c52Smaya c("uint64_t tmp{0} = {1} + {2};".format(tmp_id, args[1], args[0])) 1029f464c52Smaya return tmp_id + 1 1039f464c52Smaya 1049f464c52Smaya# Be careful to check for divide by zero... 1059f464c52Smayadef emit_udiv(tmp_id, args): 1069f464c52Smaya c("uint64_t tmp{0} = {1};".format(tmp_id, args[1])) 1079f464c52Smaya c("uint64_t tmp{0} = {1};".format(tmp_id + 1, args[0])) 1087ec681f3Smrg if args[0].isdigit(): 1097ec681f3Smrg assert int(args[0]) > 0 1107ec681f3Smrg c("uint64_t tmp{0} = tmp{2} / tmp{1};".format(tmp_id + 2, tmp_id + 1, tmp_id)) 1117ec681f3Smrg else: 1127ec681f3Smrg c("uint64_t tmp{0} = tmp{1} ? tmp{2} / tmp{1} : 0;".format(tmp_id + 2, tmp_id + 1, tmp_id)) 1139f464c52Smaya return tmp_id + 3 1149f464c52Smaya 1159f464c52Smayadef emit_umul(tmp_id, args): 1169f464c52Smaya c("uint64_t tmp{0} = {1} * {2};".format(tmp_id, args[1], args[0])) 1179f464c52Smaya return tmp_id + 1 1189f464c52Smaya 1199f464c52Smayadef emit_usub(tmp_id, args): 1209f464c52Smaya c("uint64_t tmp{0} = {1} - {2};".format(tmp_id, args[1], args[0])) 1219f464c52Smaya return tmp_id + 1 1229f464c52Smaya 1239f464c52Smayadef emit_umin(tmp_id, args): 1249f464c52Smaya c("uint64_t tmp{0} = MIN({1}, {2});".format(tmp_id, args[1], args[0])) 1259f464c52Smaya return tmp_id + 1 1269f464c52Smaya 1279f464c52Smayadef emit_lshft(tmp_id, args): 1289f464c52Smaya c("uint64_t tmp{0} = {1} << {2};".format(tmp_id, args[1], args[0])) 1299f464c52Smaya return tmp_id + 1 1309f464c52Smaya 1319f464c52Smayadef emit_rshft(tmp_id, args): 1329f464c52Smaya c("uint64_t tmp{0} = {1} >> {2};".format(tmp_id, args[1], args[0])) 1339f464c52Smaya return tmp_id + 1 1349f464c52Smaya 1359f464c52Smayadef emit_and(tmp_id, args): 1369f464c52Smaya c("uint64_t tmp{0} = {1} & {2};".format(tmp_id, args[1], args[0])) 1379f464c52Smaya return tmp_id + 1 1389f464c52Smaya 1399f464c52Smayaops = {} 1409f464c52Smaya# (n operands, emitter) 1419f464c52Smayaops["FADD"] = (2, emit_fadd) 1429f464c52Smayaops["FDIV"] = (2, emit_fdiv) 1439f464c52Smayaops["FMAX"] = (2, emit_fmax) 1449f464c52Smayaops["FMUL"] = (2, emit_fmul) 1459f464c52Smayaops["FSUB"] = (2, emit_fsub) 1469f464c52Smayaops["READ"] = (2, emit_read) 1479f464c52Smayaops["UADD"] = (2, emit_uadd) 1489f464c52Smayaops["UDIV"] = (2, emit_udiv) 1499f464c52Smayaops["UMUL"] = (2, emit_umul) 1509f464c52Smayaops["USUB"] = (2, emit_usub) 1519f464c52Smayaops["UMIN"] = (2, emit_umin) 1529f464c52Smayaops["<<"] = (2, emit_lshft) 1539f464c52Smayaops[">>"] = (2, emit_rshft) 1549f464c52Smayaops["AND"] = (2, emit_and) 1559f464c52Smaya 1569f464c52Smayadef brkt(subexp): 1579f464c52Smaya if " " in subexp: 1589f464c52Smaya return "(" + subexp + ")" 1599f464c52Smaya else: 1609f464c52Smaya return subexp 1619f464c52Smaya 1629f464c52Smayadef splice_bitwise_and(args): 1639f464c52Smaya return brkt(args[1]) + " & " + brkt(args[0]) 1649f464c52Smaya 1659f464c52Smayadef splice_logical_and(args): 1669f464c52Smaya return brkt(args[1]) + " && " + brkt(args[0]) 1679f464c52Smaya 1689f464c52Smayadef splice_ult(args): 1699f464c52Smaya return brkt(args[1]) + " < " + brkt(args[0]) 1709f464c52Smaya 1719f464c52Smayadef splice_ugte(args): 1729f464c52Smaya return brkt(args[1]) + " >= " + brkt(args[0]) 1739f464c52Smaya 1749f464c52Smayaexp_ops = {} 1759f464c52Smaya# (n operands, splicer) 1769f464c52Smayaexp_ops["AND"] = (2, splice_bitwise_and) 1779f464c52Smayaexp_ops["UGTE"] = (2, splice_ugte) 1789f464c52Smayaexp_ops["ULT"] = (2, splice_ult) 1799f464c52Smayaexp_ops["&&"] = (2, splice_logical_and) 1809f464c52Smaya 1819f464c52Smaya 1829f464c52Smayahw_vars = {} 1839f464c52Smayahw_vars["$EuCoresTotalCount"] = "perf->sys_vars.n_eus" 1849f464c52Smayahw_vars["$EuSlicesTotalCount"] = "perf->sys_vars.n_eu_slices" 1859f464c52Smayahw_vars["$EuSubslicesTotalCount"] = "perf->sys_vars.n_eu_sub_slices" 1869f464c52Smayahw_vars["$EuThreadsCount"] = "perf->sys_vars.eu_threads_count" 1879f464c52Smayahw_vars["$SliceMask"] = "perf->sys_vars.slice_mask" 1887ec681f3Smrg# subslice_mask is interchangeable with subslice/dual-subslice since Gfx12+ 1897ec681f3Smrg# only has dual subslices which can be assimilated with 16EUs subslices. 1909f464c52Smayahw_vars["$SubsliceMask"] = "perf->sys_vars.subslice_mask" 1917ec681f3Smrghw_vars["$DualSubsliceMask"] = "perf->sys_vars.subslice_mask" 1929f464c52Smayahw_vars["$GpuTimestampFrequency"] = "perf->sys_vars.timestamp_frequency" 1939f464c52Smayahw_vars["$GpuMinFrequency"] = "perf->sys_vars.gt_min_freq" 1949f464c52Smayahw_vars["$GpuMaxFrequency"] = "perf->sys_vars.gt_max_freq" 1959f464c52Smayahw_vars["$SkuRevisionId"] = "perf->sys_vars.revision" 1967ec681f3Smrghw_vars["$QueryMode"] = "perf->sys_vars.query_mode" 1979f464c52Smaya 1989f464c52Smayadef output_rpn_equation_code(set, counter, equation): 1999f464c52Smaya c("/* RPN equation: " + equation + " */") 2009f464c52Smaya tokens = equation.split() 2019f464c52Smaya stack = [] 2029f464c52Smaya tmp_id = 0 2039f464c52Smaya tmp = None 2049f464c52Smaya 2059f464c52Smaya for token in tokens: 2069f464c52Smaya stack.append(token) 2079f464c52Smaya while stack and stack[-1] in ops: 2089f464c52Smaya op = stack.pop() 2099f464c52Smaya argc, callback = ops[op] 2109f464c52Smaya args = [] 2119f464c52Smaya for i in range(0, argc): 2129f464c52Smaya operand = stack.pop() 2139f464c52Smaya if operand[0] == "$": 2149f464c52Smaya if operand in hw_vars: 2159f464c52Smaya operand = hw_vars[operand] 2169f464c52Smaya elif operand in set.counter_vars: 2179f464c52Smaya reference = set.counter_vars[operand] 2187ec681f3Smrg operand = set.read_funcs[operand[1:]] + "(perf, query, results)" 2199f464c52Smaya else: 2209f464c52Smaya raise Exception("Failed to resolve variable " + operand + " in equation " + equation + " for " + set.name + " :: " + counter.get('name')); 2219f464c52Smaya args.append(operand) 2229f464c52Smaya 2239f464c52Smaya tmp_id = callback(tmp_id, args) 2249f464c52Smaya 2259f464c52Smaya tmp = "tmp{0}".format(tmp_id - 1) 2269f464c52Smaya stack.append(tmp) 2279f464c52Smaya 2289f464c52Smaya if len(stack) != 1: 2299f464c52Smaya raise Exception("Spurious empty rpn code for " + set.name + " :: " + 2309f464c52Smaya counter.get('name') + ".\nThis is probably due to some unhandled RPN function, in the equation \"" + 2319f464c52Smaya equation + "\"") 2329f464c52Smaya 2339f464c52Smaya value = stack[-1] 2349f464c52Smaya 2359f464c52Smaya if value in hw_vars: 2369f464c52Smaya value = hw_vars[value] 2379f464c52Smaya if value in set.counter_vars: 2387ec681f3Smrg value = set.read_funcs[value[1:]] + "(perf, query, results)" 2399f464c52Smaya 2409f464c52Smaya c("\nreturn " + value + ";") 2419f464c52Smaya 2429f464c52Smayadef splice_rpn_expression(set, counter, expression): 2439f464c52Smaya tokens = expression.split() 2449f464c52Smaya stack = [] 2459f464c52Smaya 2469f464c52Smaya for token in tokens: 2479f464c52Smaya stack.append(token) 2489f464c52Smaya while stack and stack[-1] in exp_ops: 2499f464c52Smaya op = stack.pop() 2509f464c52Smaya argc, callback = exp_ops[op] 2519f464c52Smaya args = [] 2529f464c52Smaya for i in range(0, argc): 2539f464c52Smaya operand = stack.pop() 2549f464c52Smaya if operand[0] == "$": 2559f464c52Smaya if operand in hw_vars: 2569f464c52Smaya operand = hw_vars[operand] 2579f464c52Smaya else: 2589f464c52Smaya raise Exception("Failed to resolve variable " + operand + " in expression " + expression + " for " + set.name + " :: " + counter.get('name')); 2599f464c52Smaya args.append(operand) 2609f464c52Smaya 2619f464c52Smaya subexp = callback(args) 2629f464c52Smaya 2639f464c52Smaya stack.append(subexp) 2649f464c52Smaya 2659f464c52Smaya if len(stack) != 1: 2669f464c52Smaya raise Exception("Spurious empty rpn expression for " + set.name + " :: " + 2679f464c52Smaya counter.get('name') + ".\nThis is probably due to some unhandled RPN operation, in the expression \"" + 2689f464c52Smaya expression + "\"") 2699f464c52Smaya 2709f464c52Smaya return stack[-1] 2719f464c52Smaya 2729f464c52Smayadef output_counter_read(gen, set, counter): 2739f464c52Smaya c("\n") 2749f464c52Smaya c("/* {0} :: {1} */".format(set.name, counter.get('name'))) 2759f464c52Smaya 2769f464c52Smaya if counter.read_hash in hashed_funcs: 2779f464c52Smaya c("#define %s \\" % counter.read_sym) 2789f464c52Smaya c_indent(3) 2799f464c52Smaya c("%s" % hashed_funcs[counter.read_hash]) 2809f464c52Smaya c_outdent(3) 2819f464c52Smaya else: 2829f464c52Smaya ret_type = counter.get('data_type') 2839f464c52Smaya if ret_type == "uint64": 2849f464c52Smaya ret_type = "uint64_t" 2859f464c52Smaya 2869f464c52Smaya read_eq = counter.get('equation') 2879f464c52Smaya 2889f464c52Smaya c("static " + ret_type) 2897ec681f3Smrg c(counter.read_sym + "(UNUSED struct intel_perf_config *perf,\n") 2909f464c52Smaya c_indent(len(counter.read_sym) + 1) 2917ec681f3Smrg c("const struct intel_perf_query_info *query,\n") 2927ec681f3Smrg c("const struct intel_perf_query_result *results)\n") 2939f464c52Smaya c_outdent(len(counter.read_sym) + 1) 2949f464c52Smaya 2959f464c52Smaya c("{") 2969f464c52Smaya c_indent(3) 2979f464c52Smaya output_rpn_equation_code(set, counter, read_eq) 2989f464c52Smaya c_outdent(3) 2999f464c52Smaya c("}") 3009f464c52Smaya 3019f464c52Smaya hashed_funcs[counter.read_hash] = counter.read_sym 3029f464c52Smaya 3039f464c52Smaya 3049f464c52Smayadef output_counter_max(gen, set, counter): 3059f464c52Smaya max_eq = counter.get('max_equation') 3069f464c52Smaya 3079f464c52Smaya if not counter.has_max_func(): 3089f464c52Smaya return 3099f464c52Smaya 3109f464c52Smaya c("\n") 3119f464c52Smaya c("/* {0} :: {1} */".format(set.name, counter.get('name'))) 3129f464c52Smaya 3139f464c52Smaya if counter.max_hash in hashed_funcs: 3149f464c52Smaya c("#define %s \\" % counter.max_sym()) 3159f464c52Smaya c_indent(3) 3169f464c52Smaya c("%s" % hashed_funcs[counter.max_hash]) 3179f464c52Smaya c_outdent(3) 3189f464c52Smaya else: 3199f464c52Smaya ret_type = counter.get('data_type') 3209f464c52Smaya if ret_type == "uint64": 3219f464c52Smaya ret_type = "uint64_t" 3229f464c52Smaya 3239f464c52Smaya c("static " + ret_type) 3247ec681f3Smrg c(counter.max_sym() + "(struct intel_perf_config *perf)\n") 3259f464c52Smaya c("{") 3269f464c52Smaya c_indent(3) 3279f464c52Smaya output_rpn_equation_code(set, counter, max_eq) 3289f464c52Smaya c_outdent(3) 3299f464c52Smaya c("}") 3309f464c52Smaya 3319f464c52Smaya hashed_funcs[counter.max_hash] = counter.max_sym() 3329f464c52Smaya 3339f464c52Smaya 3349f464c52Smayac_type_sizes = { "uint32_t": 4, "uint64_t": 8, "float": 4, "double": 8, "bool": 4 } 3359f464c52Smayadef sizeof(c_type): 3369f464c52Smaya return c_type_sizes[c_type] 3379f464c52Smaya 3389f464c52Smayadef pot_align(base, pot_alignment): 3399f464c52Smaya return (base + pot_alignment - 1) & ~(pot_alignment - 1); 3409f464c52Smaya 3419f464c52Smayasemantic_type_map = { 3429f464c52Smaya "duration": "raw", 3439f464c52Smaya "ratio": "event" 3449f464c52Smaya } 3459f464c52Smaya 3469f464c52Smayadef output_availability(set, availability, counter_name): 3479f464c52Smaya expression = splice_rpn_expression(set, counter_name, availability) 3489f464c52Smaya lines = expression.split(' && ') 3499f464c52Smaya n_lines = len(lines) 3509f464c52Smaya if n_lines == 1: 3519f464c52Smaya c("if (" + lines[0] + ") {") 3529f464c52Smaya else: 3539f464c52Smaya c("if (" + lines[0] + " &&") 3549f464c52Smaya c_indent(4) 3559f464c52Smaya for i in range(1, (n_lines - 1)): 3569f464c52Smaya c(lines[i] + " &&") 3579f464c52Smaya c(lines[(n_lines - 1)] + ") {") 3589f464c52Smaya c_outdent(4) 3599f464c52Smaya 3609f464c52Smaya 3617ec681f3Smrgdef output_units(unit): 3627ec681f3Smrg return unit.replace(' ', '_').upper() 3637ec681f3Smrg 3647ec681f3Smrg 3657ec681f3Smrg# should a unit be visible in description? 3667ec681f3Smrgunits_map = { 3677ec681f3Smrg "bytes" : True, 3687ec681f3Smrg "cycles" : True, 3697ec681f3Smrg "eu atomic requests to l3 cache lines" : False, 3707ec681f3Smrg "eu bytes per l3 cache line" : False, 3717ec681f3Smrg "eu requests to l3 cache lines" : False, 3727ec681f3Smrg "eu sends to l3 cache lines" : False, 3737ec681f3Smrg "events" : True, 3747ec681f3Smrg "hz" : True, 3757ec681f3Smrg "messages" : True, 3767ec681f3Smrg "ns" : True, 3777ec681f3Smrg "number" : False, 3787ec681f3Smrg "percent" : True, 3797ec681f3Smrg "pixels" : True, 3807ec681f3Smrg "texels" : True, 3817ec681f3Smrg "threads" : True, 3827ec681f3Smrg "us" : True, 3837ec681f3Smrg "utilization" : False, 3847ec681f3Smrg } 3857ec681f3Smrg 3867ec681f3Smrg 3877ec681f3Smrgdef desc_units(unit): 3887ec681f3Smrg val = units_map.get(unit) 3897ec681f3Smrg if val is None: 3907ec681f3Smrg raise Exception("Unknown unit: " + unit) 3917ec681f3Smrg if val == False: 3927ec681f3Smrg return "" 3937ec681f3Smrg if unit == 'hz': 3947ec681f3Smrg unit = 'Hz' 3957ec681f3Smrg return " Unit: " + unit + "." 3967ec681f3Smrg 3977ec681f3Smrg 3989f464c52Smayadef output_counter_report(set, counter, current_offset): 3999f464c52Smaya data_type = counter.get('data_type') 4009f464c52Smaya data_type_uc = data_type.upper() 4019f464c52Smaya c_type = data_type 4029f464c52Smaya 4039f464c52Smaya if "uint" in c_type: 4049f464c52Smaya c_type = c_type + "_t" 4059f464c52Smaya 4069f464c52Smaya semantic_type = counter.get('semantic_type') 4079f464c52Smaya if semantic_type in semantic_type_map: 4089f464c52Smaya semantic_type = semantic_type_map[semantic_type] 4099f464c52Smaya 4109f464c52Smaya semantic_type_uc = semantic_type.upper() 4119f464c52Smaya 4129f464c52Smaya c("\n") 4139f464c52Smaya 4149f464c52Smaya availability = counter.get('availability') 4159f464c52Smaya if availability: 4169f464c52Smaya output_availability(set, availability, counter.get('name')) 4179f464c52Smaya c_indent(3) 4189f464c52Smaya 4199f464c52Smaya c("counter = &query->counters[query->n_counters++];\n") 4209f464c52Smaya c("counter->oa_counter_read_" + data_type + " = " + set.read_funcs[counter.get('symbol_name')] + ";\n") 4219f464c52Smaya c("counter->name = \"" + counter.get('name') + "\";\n") 4227ec681f3Smrg c("counter->desc = \"" + counter.get('description') + desc_units(counter.get('units')) + "\";\n") 4237ec681f3Smrg c("counter->symbol_name = \"" + counter.get('symbol_name') + "\";\n") 4247ec681f3Smrg c("counter->category = \"" + counter.get('mdapi_group') + "\";\n") 4257ec681f3Smrg c("counter->type = INTEL_PERF_COUNTER_TYPE_" + semantic_type_uc + ";\n") 4267ec681f3Smrg c("counter->data_type = INTEL_PERF_COUNTER_DATA_TYPE_" + data_type_uc + ";\n") 4277ec681f3Smrg c("counter->units = INTEL_PERF_COUNTER_UNITS_" + output_units(counter.get('units')) + ";\n") 4289f464c52Smaya c("counter->raw_max = " + set.max_values[counter.get('symbol_name')] + ";\n") 4299f464c52Smaya 4309f464c52Smaya current_offset = pot_align(current_offset, sizeof(c_type)) 4319f464c52Smaya c("counter->offset = " + str(current_offset) + ";\n") 4329f464c52Smaya 4339f464c52Smaya if availability: 4349f464c52Smaya c_outdent(3); 4359f464c52Smaya c("}") 4369f464c52Smaya 4379f464c52Smaya return current_offset + sizeof(c_type) 4389f464c52Smaya 4399f464c52Smaya 4409f464c52Smayaregister_types = { 4419f464c52Smaya 'FLEX': 'flex_regs', 4429f464c52Smaya 'NOA': 'mux_regs', 4439f464c52Smaya 'OA': 'b_counter_regs', 4449f464c52Smaya} 4459f464c52Smaya 4469f464c52Smayadef compute_register_lengths(set): 4479f464c52Smaya register_lengths = {} 4489f464c52Smaya register_configs = set.findall('register_config') 4499f464c52Smaya for register_config in register_configs: 4509f464c52Smaya t = register_types[register_config.get('type')] 4519f464c52Smaya if t not in register_lengths: 4529f464c52Smaya register_lengths[t] = len(register_config.findall('register')) 4539f464c52Smaya else: 4549f464c52Smaya register_lengths[t] += len(register_config.findall('register')) 4559f464c52Smaya 4569f464c52Smaya return register_lengths 4579f464c52Smaya 4589f464c52Smaya 4599f464c52Smayadef generate_register_configs(set): 4609f464c52Smaya register_configs = set.findall('register_config') 4617ec681f3Smrg 4629f464c52Smaya for register_config in register_configs: 4639f464c52Smaya t = register_types[register_config.get('type')] 4649f464c52Smaya 4659f464c52Smaya availability = register_config.get('availability') 4669f464c52Smaya if availability: 4679f464c52Smaya output_availability(set, availability, register_config.get('type') + ' register config') 4689f464c52Smaya c_indent(3) 4699f464c52Smaya 4707ec681f3Smrg registers = register_config.findall('register') 4717ec681f3Smrg c("static const struct intel_perf_query_register_prog %s[] = {" % t) 4727ec681f3Smrg c_indent(3) 4737ec681f3Smrg for register in registers: 4747ec681f3Smrg c("{ .reg = %s, .val = %s }," % (register.get('address'), register.get('value'))) 4757ec681f3Smrg c_outdent(3) 4767ec681f3Smrg c("};") 4777ec681f3Smrg c("query->config.%s = %s;" % (t, t)) 4787ec681f3Smrg c("query->config.n_%s = ARRAY_SIZE(%s);" % (t, t)) 4799f464c52Smaya 4809f464c52Smaya if availability: 4819f464c52Smaya c_outdent(3) 4829f464c52Smaya c("}") 4839f464c52Smaya c("\n") 4849f464c52Smaya 4859f464c52Smaya 4869f464c52Smaya# Wraps a <counter> element from the oa-*.xml files. 4879f464c52Smayaclass Counter: 4889f464c52Smaya def __init__(self, set, xml): 4899f464c52Smaya self.xml = xml 4909f464c52Smaya self.set = set 4919f464c52Smaya self.read_hash = None 4929f464c52Smaya self.max_hash = None 4939f464c52Smaya 4949f464c52Smaya self.read_sym = "{0}__{1}__{2}__read".format(self.set.gen.chipset, 4959f464c52Smaya self.set.underscore_name, 4969f464c52Smaya self.xml.get('underscore_name')) 4979f464c52Smaya 4989f464c52Smaya def get(self, prop): 4999f464c52Smaya return self.xml.get(prop) 5009f464c52Smaya 5019f464c52Smaya # Compute the hash of a counter's equation by expanding (including all the 5029f464c52Smaya # sub-equations it depends on) 5039f464c52Smaya def compute_hashes(self): 5049f464c52Smaya if self.read_hash is not None: 5059f464c52Smaya return 5069f464c52Smaya 5079f464c52Smaya def replace_token(token): 5089f464c52Smaya if token[0] != "$": 5099f464c52Smaya return token 5109f464c52Smaya if token not in self.set.counter_vars: 5119f464c52Smaya return token 5129f464c52Smaya self.set.counter_vars[token].compute_hashes() 5139f464c52Smaya return self.set.counter_vars[token].read_hash 5149f464c52Smaya 5159f464c52Smaya read_eq = self.xml.get('equation') 5169f464c52Smaya self.read_hash = ' '.join(map(replace_token, read_eq.split())) 5179f464c52Smaya 5189f464c52Smaya max_eq = self.xml.get('max_equation') 5199f464c52Smaya if max_eq: 5209f464c52Smaya self.max_hash = ' '.join(map(replace_token, max_eq.split())) 5219f464c52Smaya 5229f464c52Smaya def has_max_func(self): 5239f464c52Smaya max_eq = self.xml.get('max_equation') 5249f464c52Smaya if not max_eq: 5259f464c52Smaya return False 5269f464c52Smaya 5279f464c52Smaya try: 5289f464c52Smaya val = float(max_eq) 5299f464c52Smaya return False 5309f464c52Smaya except ValueError: 5319f464c52Smaya pass 5329f464c52Smaya 5339f464c52Smaya for token in max_eq.split(): 5349f464c52Smaya if token[0] == '$' and token not in hw_vars: 5359f464c52Smaya return False 5369f464c52Smaya return True 5379f464c52Smaya 5389f464c52Smaya def max_sym(self): 5399f464c52Smaya assert self.has_max_func() 5409f464c52Smaya return "{0}__{1}__{2}__max".format(self.set.gen.chipset, 5419f464c52Smaya self.set.underscore_name, 5429f464c52Smaya self.xml.get('underscore_name')) 5439f464c52Smaya 5449f464c52Smaya def max_value(self): 5459f464c52Smaya max_eq = self.xml.get('max_equation') 5469f464c52Smaya if not max_eq: 5479f464c52Smaya return "0 /* undefined */" 5489f464c52Smaya 5499f464c52Smaya try: 5509f464c52Smaya return "{0}".format(float(max_eq)) 5519f464c52Smaya except ValueError: 5529f464c52Smaya pass 5539f464c52Smaya 5549f464c52Smaya for token in max_eq.split(): 5559f464c52Smaya if token[0] == '$' and token not in hw_vars: 5569f464c52Smaya return "0 /* unsupported (varies over time) */" 5579f464c52Smaya 5589f464c52Smaya return "{0}__{1}__{2}__max(perf)".format(self.set.gen.chipset, 5599f464c52Smaya self.set.underscore_name, 5609f464c52Smaya self.xml.get('underscore_name')) 5619f464c52Smaya 5629f464c52Smaya# Wraps a <set> element from the oa-*.xml files. 5639f464c52Smayaclass Set: 5649f464c52Smaya def __init__(self, gen, xml): 5659f464c52Smaya self.gen = gen 5669f464c52Smaya self.xml = xml 5679f464c52Smaya 5689f464c52Smaya self.counter_vars = {} 5699f464c52Smaya self.max_values = {} 5709f464c52Smaya self.read_funcs = {} 5719f464c52Smaya 5729f464c52Smaya xml_counters = self.xml.findall("counter") 5739f464c52Smaya self.counters = [] 5749f464c52Smaya for xml_counter in xml_counters: 5759f464c52Smaya counter = Counter(self, xml_counter) 5769f464c52Smaya self.counters.append(counter) 5779f464c52Smaya self.counter_vars["$" + counter.get('symbol_name')] = counter 5789f464c52Smaya self.read_funcs[counter.get('symbol_name')] = counter.read_sym 5799f464c52Smaya self.max_values[counter.get('symbol_name')] = counter.max_value() 5809f464c52Smaya 5819f464c52Smaya for counter in self.counters: 5829f464c52Smaya counter.compute_hashes() 5839f464c52Smaya 5849f464c52Smaya @property 5859f464c52Smaya def hw_config_guid(self): 5869f464c52Smaya return self.xml.get('hw_config_guid') 5879f464c52Smaya 5889f464c52Smaya @property 5899f464c52Smaya def name(self): 5909f464c52Smaya return self.xml.get('name') 5919f464c52Smaya 5929f464c52Smaya @property 5939f464c52Smaya def symbol_name(self): 5949f464c52Smaya return self.xml.get('symbol_name') 5959f464c52Smaya 5969f464c52Smaya @property 5979f464c52Smaya def underscore_name(self): 5989f464c52Smaya return self.xml.get('underscore_name') 5999f464c52Smaya 6009f464c52Smaya def findall(self, path): 6019f464c52Smaya return self.xml.findall(path) 6029f464c52Smaya 6039f464c52Smaya def find(self, path): 6049f464c52Smaya return self.xml.find(path) 6059f464c52Smaya 6069f464c52Smaya 6079f464c52Smaya# Wraps an entire oa-*.xml file. 6089f464c52Smayaclass Gen: 6099f464c52Smaya def __init__(self, filename): 6109f464c52Smaya self.filename = filename 6119f464c52Smaya self.xml = et.parse(self.filename) 6129f464c52Smaya self.chipset = self.xml.find('.//set').get('chipset').lower() 6139f464c52Smaya self.sets = [] 6149f464c52Smaya 6159f464c52Smaya for xml_set in self.xml.findall(".//set"): 6169f464c52Smaya self.sets.append(Set(self, xml_set)) 6179f464c52Smaya 6189f464c52Smaya 6199f464c52Smayadef main(): 6209f464c52Smaya global c_file 6219f464c52Smaya global header_file 6229f464c52Smaya 6239f464c52Smaya parser = argparse.ArgumentParser() 6249f464c52Smaya parser.add_argument("--header", help="Header file to write", required=True) 6259f464c52Smaya parser.add_argument("--code", help="C file to write", required=True) 6269f464c52Smaya parser.add_argument("xml_files", nargs='+', help="List of xml metrics files to process") 6279f464c52Smaya 6289f464c52Smaya args = parser.parse_args() 6299f464c52Smaya 6309f464c52Smaya c_file = open(args.code, 'w') 6319f464c52Smaya header_file = open(args.header, 'w') 6329f464c52Smaya 6339f464c52Smaya gens = [] 6349f464c52Smaya for xml_file in args.xml_files: 6359f464c52Smaya gens.append(Gen(xml_file)) 6369f464c52Smaya 6379f464c52Smaya 6389f464c52Smaya copyright = textwrap.dedent("""\ 6399f464c52Smaya /* Autogenerated file, DO NOT EDIT manually! generated by {} 6409f464c52Smaya * 6419f464c52Smaya * Copyright (c) 2015 Intel Corporation 6429f464c52Smaya * 6439f464c52Smaya * Permission is hereby granted, free of charge, to any person obtaining a 6449f464c52Smaya * copy of this software and associated documentation files (the "Software"), 6459f464c52Smaya * to deal in the Software without restriction, including without limitation 6469f464c52Smaya * the rights to use, copy, modify, merge, publish, distribute, sublicense, 6479f464c52Smaya * and/or sell copies of the Software, and to permit persons to whom the 6489f464c52Smaya * Software is furnished to do so, subject to the following conditions: 6499f464c52Smaya * 6509f464c52Smaya * The above copyright notice and this permission notice (including the next 6519f464c52Smaya * paragraph) shall be included in all copies or substantial portions of the 6529f464c52Smaya * Software. 6539f464c52Smaya * 6549f464c52Smaya * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 6559f464c52Smaya * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 6569f464c52Smaya * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 6579f464c52Smaya * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 6589f464c52Smaya * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 6599f464c52Smaya * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 6609f464c52Smaya * DEALINGS IN THE SOFTWARE. 6619f464c52Smaya */ 6629f464c52Smaya 6639f464c52Smaya """).format(os.path.basename(__file__)) 6649f464c52Smaya 6659f464c52Smaya h(copyright) 6669f464c52Smaya h(textwrap.dedent("""\ 6679f464c52Smaya #pragma once 6689f464c52Smaya 6697ec681f3Smrg struct intel_perf_config; 6709f464c52Smaya 6719f464c52Smaya """)) 6729f464c52Smaya 6739f464c52Smaya c(copyright) 6749f464c52Smaya c(textwrap.dedent("""\ 6759f464c52Smaya #include <stdint.h> 6769f464c52Smaya #include <stdbool.h> 6779f464c52Smaya 6789f464c52Smaya #include <drm-uapi/i915_drm.h> 6799f464c52Smaya 6809f464c52Smaya #include "util/hash_table.h" 6817ec681f3Smrg #include "util/ralloc.h" 6829f464c52Smaya 6839f464c52Smaya """)) 6849f464c52Smaya 6859f464c52Smaya c("#include \"" + os.path.basename(args.header) + "\"") 6869f464c52Smaya 6879f464c52Smaya c(textwrap.dedent("""\ 6887ec681f3Smrg #include "perf/intel_perf.h" 6899f464c52Smaya 6909f464c52Smaya 6919f464c52Smaya #define MIN(a, b) ((a < b) ? (a) : (b)) 6929f464c52Smaya #define MAX(a, b) ((a > b) ? (a) : (b)) 6939f464c52Smaya 6949f464c52Smaya 6959f464c52Smaya """)) 6969f464c52Smaya 6979f464c52Smaya # Print out all equation functions. 6989f464c52Smaya for gen in gens: 6999f464c52Smaya for set in gen.sets: 7009f464c52Smaya for counter in set.counters: 7019f464c52Smaya output_counter_read(gen, set, counter) 7029f464c52Smaya output_counter_max(gen, set, counter) 7039f464c52Smaya 7049f464c52Smaya # Print out all metric sets registration functions for each set in each 7059f464c52Smaya # generation. 7069f464c52Smaya for gen in gens: 7079f464c52Smaya for set in gen.sets: 7089f464c52Smaya counters = set.counters 7099f464c52Smaya 7109f464c52Smaya c("\n") 7117ec681f3Smrg c("\nstatic void\n") 7127ec681f3Smrg c("{0}_register_{1}_counter_query(struct intel_perf_config *perf)\n".format(gen.chipset, set.underscore_name)) 7137ec681f3Smrg c("{\n") 7149f464c52Smaya c_indent(3) 7159f464c52Smaya 7167ec681f3Smrg c("struct intel_perf_query_info *query = rzalloc(perf, struct intel_perf_query_info);\n") 7177ec681f3Smrg c("\n") 7187ec681f3Smrg c("query->perf = perf;\n") 7197ec681f3Smrg c("query->kind = INTEL_PERF_QUERY_TYPE_OA;\n") 7207ec681f3Smrg c("query->name = \"" + set.name + "\";\n") 7217ec681f3Smrg c("query->symbol_name = \"" + set.symbol_name + "\";\n") 7227ec681f3Smrg c("query->guid = \"" + set.hw_config_guid + "\";\n") 7239f464c52Smaya 7247ec681f3Smrg c("query->counters = rzalloc_array(query, struct intel_perf_query_counter, %u);" % len(counters)) 7257ec681f3Smrg c("query->n_counters = 0;") 7267ec681f3Smrg c("query->oa_metrics_set_id = 0; /* determined at runtime, via sysfs */") 7279f464c52Smaya 7289f464c52Smaya if gen.chipset == "hsw": 7299f464c52Smaya c(textwrap.dedent("""\ 7307ec681f3Smrg query->oa_format = I915_OA_FORMAT_A45_B8_C8; 7319f464c52Smaya /* Accumulation buffer offsets... */ 7327ec681f3Smrg query->gpu_time_offset = 0; 7337ec681f3Smrg query->a_offset = query->gpu_time_offset + 1; 7347ec681f3Smrg query->b_offset = query->a_offset + 45; 7357ec681f3Smrg query->c_offset = query->b_offset + 8; 7367ec681f3Smrg query->perfcnt_offset = query->c_offset + 8; 7377ec681f3Smrg query->rpstat_offset = query->perfcnt_offset + 2; 7389f464c52Smaya """)) 7399f464c52Smaya else: 7409f464c52Smaya c(textwrap.dedent("""\ 7417ec681f3Smrg query->oa_format = I915_OA_FORMAT_A32u40_A4u32_B8_C8; 7429f464c52Smaya /* Accumulation buffer offsets... */ 7437ec681f3Smrg query->gpu_time_offset = 0; 7447ec681f3Smrg query->gpu_clock_offset = query->gpu_time_offset + 1; 7457ec681f3Smrg query->a_offset = query->gpu_clock_offset + 1; 7467ec681f3Smrg query->b_offset = query->a_offset + 36; 7477ec681f3Smrg query->c_offset = query->b_offset + 8; 7487ec681f3Smrg query->perfcnt_offset = query->c_offset + 8; 7497ec681f3Smrg query->rpstat_offset = query->perfcnt_offset + 2; 7509f464c52Smaya """)) 7519f464c52Smaya 7529f464c52Smaya 7537ec681f3Smrg c("\n") 7547ec681f3Smrg c("struct intel_perf_query_counter *counter = query->counters;\n") 7559f464c52Smaya 7569f464c52Smaya c("\n") 7579f464c52Smaya c("/* Note: we're assuming there can't be any variation in the definition ") 7589f464c52Smaya c(" * of a query between contexts so it's ok to describe a query within a ") 7599f464c52Smaya c(" * global variable which only needs to be initialized once... */") 7609f464c52Smaya c("\nif (!query->data_size) {") 7619f464c52Smaya c_indent(3) 7629f464c52Smaya 7639f464c52Smaya generate_register_configs(set) 7649f464c52Smaya 7659f464c52Smaya offset = 0 7669f464c52Smaya for counter in counters: 7679f464c52Smaya offset = output_counter_report(set, counter, offset) 7689f464c52Smaya 7699f464c52Smaya 7707ec681f3Smrg c("\nquery->data_size = counter->offset + intel_perf_query_counter_get_size(counter);\n") 7719f464c52Smaya 7729f464c52Smaya c_outdent(3) 7739f464c52Smaya c("}"); 7749f464c52Smaya 7759f464c52Smaya c("\n_mesa_hash_table_insert(perf->oa_metrics_table, query->guid, query);") 7769f464c52Smaya 7779f464c52Smaya c_outdent(3) 7789f464c52Smaya c("}\n") 7799f464c52Smaya 7807ec681f3Smrg h("void intel_oa_register_queries_" + gen.chipset + "(struct intel_perf_config *perf);\n") 7819f464c52Smaya 7829f464c52Smaya c("\nvoid") 7837ec681f3Smrg c("intel_oa_register_queries_" + gen.chipset + "(struct intel_perf_config *perf)") 7849f464c52Smaya c("{") 7859f464c52Smaya c_indent(3) 7869f464c52Smaya 7879f464c52Smaya for set in gen.sets: 7889f464c52Smaya c("{0}_register_{1}_counter_query(perf);".format(gen.chipset, set.underscore_name)) 7899f464c52Smaya 7909f464c52Smaya c_outdent(3) 7919f464c52Smaya c("}") 7929f464c52Smaya 7939f464c52Smaya 7949f464c52Smayaif __name__ == '__main__': 7959f464c52Smaya main() 796