(root)/
gcc-13.2.0/
contrib/
gen_autofdo_event.py
       1  #!/usr/bin/python3
       2  # Generate Intel taken branches Linux perf event script for autofdo profiling.
       3  
       4  # Copyright (C) 2016-2023 Free Software Foundation, Inc.
       5  #
       6  # GCC is free software; you can redistribute it and/or modify it under
       7  # the terms of the GNU General Public License as published by the Free
       8  # Software Foundation; either version 3, or (at your option) any later
       9  # version.
      10  #
      11  # GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12  # WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13  # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14  # for more details.
      15  #
      16  # You should have received a copy of the GNU General Public License
      17  # along with GCC; see the file COPYING3.  If not see
      18  # <http://www.gnu.org/licenses/>.  */
      19  
      20  # Run it with perf record -b -e EVENT program ...
      21  # The Linux Kernel needs to support the PMU of the current CPU, and
      22  # It will likely not work in VMs.
      23  # Add --all to print for all cpus, otherwise for current cpu.
      24  # Add --script to generate shell script to run correct event.
      25  #
      26  # Requires internet (https) access. This may require setting up a proxy
      27  # with export https_proxy=...
      28  #
      29  import urllib.request
      30  import sys
      31  import json
      32  import argparse
      33  import collections
      34  import os
      35  
      36  baseurl = "https://download.01.org/perfmon"
      37  
      38  target_events = ('BR_INST_RETIRED.NEAR_TAKEN',
      39                   'BR_INST_EXEC.TAKEN',
      40                   'BR_INST_RETIRED.TAKEN_JCC',
      41                   'BR_INST_TYPE_RETIRED.COND_TAKEN')
      42  
      43  ap = argparse.ArgumentParser()
      44  ap.add_argument('--all', '-a', help='Print for all CPUs', action='store_true')
      45  ap.add_argument('--script', help='Generate shell script', action='store_true')
      46  args = ap.parse_args()
      47  
      48  eventmap = collections.defaultdict(list)
      49  
      50  def get_cpustr():
      51      cpuinfo = os.getenv("CPUINFO")
      52      if cpuinfo is None:
      53          cpuinfo = '/proc/cpuinfo'
      54      f = open(cpuinfo, 'r')
      55      cpu = [None, None, None, None]
      56      for j in f:
      57          n = j.split()
      58          if n[0] == 'vendor_id':
      59              cpu[0] = n[2]
      60          elif n[0] == 'model' and n[1] == ':':
      61              cpu[2] = int(n[2])
      62          elif n[0] == 'cpu' and n[1] == 'family':
      63              cpu[1] = int(n[3])
      64          elif n[0] == 'stepping' and n[1] == ':':
      65              cpu[3] = int(n[2])
      66          if all(v is not None for v in cpu):
      67              break
      68      # stepping for SKX only
      69      stepping = cpu[0] == "GenuineIntel" and cpu[1] == 6 and cpu[2] == 0x55
      70      if stepping:
      71          return "%s-%d-%X-%X" % tuple(cpu)
      72      return "%s-%d-%X" % tuple(cpu)[:3]
      73  
      74  def find_event(eventurl, model):
      75      print("Downloading", eventurl, file = sys.stderr)
      76      u = urllib.request.urlopen(eventurl)
      77      events = json.loads(u.read())
      78      u.close()
      79  
      80      found = 0
      81      for j in events:
      82          if j['EventName'] in target_events:
      83              event = "cpu/event=%s,umask=%s/" % (j['EventCode'], j['UMask'])
      84              if 'PEBS' in j and int(j['PEBS']) > 0:
      85                  event += "p"
      86              if args.script:
      87                  eventmap[event].append(model)
      88              else:
      89                  print(j['EventName'], "event for model", model, "is", event)
      90              found += 1
      91      return found
      92  
      93  if not args.all:
      94      cpu = get_cpustr()
      95      if not cpu:
      96          sys.exit("Unknown CPU type")
      97  
      98  url = baseurl + "/mapfile.csv"
      99  print("Downloading", url, file = sys.stderr)
     100  u = urllib.request.urlopen(url)
     101  found = 0
     102  cpufound = 0
     103  for j in u:
     104      n = j.rstrip().decode().split(',')
     105      if len(n) >= 4 and (args.all or n[0] == cpu) and n[3] == "core":
     106          components = n[0].split("-")
     107          model = components[2]
     108          model = int(model, 16)
     109          cpufound += 1
     110          found += find_event(baseurl + n[2], model)
     111  u.close()
     112  
     113  if args.script:
     114      print('''#!/bin/sh
     115  # Profile workload for gcc profile feedback (autofdo) using Linux perf.
     116  # Auto generated. To regenerate for new CPUs run
     117  # contrib/gen_autofdo_event.py --script --all in gcc source
     118  
     119  # usages:
     120  # gcc-auto-profile program             (profile program and children)
     121  # gcc-auto-profile -a sleep X          (profile all for X secs, may need root)
     122  # gcc-auto-profile -p PID sleep X      (profile PID)
     123  # gcc-auto-profile --kernel -a sleep X (profile kernel)
     124  # gcc-auto-profile --all -a sleep X    (profile kernel and user space)
     125  
     126  # Identify branches taken event for CPU.
     127  #
     128  
     129  FLAGS=u
     130  
     131  if [ "$1" = "--kernel" ] ; then
     132    FLAGS=k
     133    shift
     134  fi
     135  if [ "$1" = "--all" ] ; then
     136    FLAGS=uk
     137    shift
     138  fi
     139  
     140  if ! grep -q Intel /proc/cpuinfo ; then
     141    echo >&2 "Only Intel CPUs supported"
     142    exit 1
     143  fi
     144  
     145  if grep -q hypervisor /proc/cpuinfo ; then
     146    echo >&2 "Warning: branch profiling may not be functional in VMs"
     147  fi
     148  
     149  case `grep -E -q "^cpu family\s*: 6" /proc/cpuinfo &&
     150    grep -E "^model\s*:" /proc/cpuinfo | head -n1` in''')
     151      for event, mod in eventmap.items():
     152          for m in mod[:-1]:
     153              print("model*:\ %s|\\" % m)
     154          print('model*:\ %s) E="%s$FLAGS" ;;' % (mod[-1], event))
     155      print('''*)
     156  echo >&2 "Unknown CPU. Run contrib/gen_autofdo_event.py --all --script to update script."
     157  	exit 1 ;;''')
     158      print("esac")
     159      print("set -x")
     160      print('if ! perf record -e $E -b "$@" ; then')
     161      print('  # PEBS may not actually be working even if the processor supports it')
     162      print('  # (e.g., in a virtual machine). Trying to run without /p.')
     163      print('  set +x')
     164      print('  echo >&2 "Retrying without /p."')
     165      print('  E="$(echo "${E}" | sed -e \'s/\/p/\//\')"')
     166      print('  set -x')
     167      print('  exec perf record -e $E -b "$@"')
     168      print(' set +x')
     169      print('fi')
     170  
     171  if cpufound == 0 and not args.all:
     172      sys.exit('CPU %s not found' % cpu)
     173  
     174  if found == 0:
     175      sys.exit('Branch event not found')