diff --git a/Makefile.inc1 b/Makefile.inc1 index 970ba0248c0c..827838a0fa8d 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -1,3037 +1,3037 @@ # # $FreeBSD$ # # Make command line options: # -DNO_CLEANDIR run ${MAKE} clean, instead of ${MAKE} cleandir # -DNO_CLEAN do not clean at all # -DDB_FROM_SRC use the user/group databases in src/etc instead of # the system database when installing. # -DNO_SHARE do not go into share subdir # -DKERNFAST define NO_KERNEL{CONFIG,CLEAN,OBJ} # -DNO_KERNELCONFIG do not run config in ${MAKE} buildkernel # -DNO_KERNELCLEAN do not run ${MAKE} clean in ${MAKE} buildkernel # -DNO_KERNELOBJ do not run ${MAKE} obj in ${MAKE} buildkernel # -DNO_PORTSUPDATE do not update ports in ${MAKE} update # -DNO_ROOT install without using root privilege # -DNO_DOCUPDATE do not update doc in ${MAKE} update # -DWITHOUT_CTF do not run the DTrace CTF conversion tools on built objects # LOCAL_DIRS="list of dirs" to add additional dirs to the SUBDIR list # LOCAL_ITOOLS="list of tools" to add additional tools to the ITOOLS list # LOCAL_LIB_DIRS="list of dirs" to add additional dirs to libraries target # LOCAL_MTREE="list of mtree files" to process to allow local directories # to be created before files are installed # LOCAL_TOOL_DIRS="list of dirs" to add additional dirs to the build-tools # list # LOCAL_XTOOL_DIRS="list of dirs" to add additional dirs to the # cross-tools target # METALOG="path to metadata log" to write permission and ownership # when NO_ROOT is set. (default: ${DESTDIR}/METALOG) # TARGET="machine" to crossbuild world for a different machine type # TARGET_ARCH= may be required when a TARGET supports multiple endians # BUILDENV_SHELL= shell to launch for the buildenv target (def:${SHELL}) # WORLD_FLAGS= additional flags to pass to make(1) during buildworld # KERNEL_FLAGS= additional flags to pass to make(1) during buildkernel # SUBDIR_OVERRIDE="list of dirs" to build rather than everything. # All libraries and includes, and some build tools will still build. # # The intended user-driven targets are: # buildworld - rebuild *everything*, including glue to help do upgrades # installworld- install everything built by "buildworld" # checkworld - run test suite on installed world # doxygen - build API documentation of the kernel # update - convenient way to update your source tree (eg: svn/svnup) # # Standard targets (not defined here) are documented in the makefiles in # /usr/share/mk. These include: # obj depend all install clean cleandepend cleanobj .if !defined(TARGET) || !defined(TARGET_ARCH) .error "Both TARGET and TARGET_ARCH must be defined." .endif SRCDIR?= ${.CURDIR} LOCALBASE?= /usr/local # Cross toolchain changes must be in effect before bsd.compiler.mk # so that gets the right CC, and pass CROSS_TOOLCHAIN to submakes. .if defined(CROSS_TOOLCHAIN) .if exists(${LOCALBASE}/share/toolchains/${CROSS_TOOLCHAIN}.mk) .include "${LOCALBASE}/share/toolchains/${CROSS_TOOLCHAIN}.mk" .elif exists(${CROSS_TOOLCHAIN}) .include "${CROSS_TOOLCHAIN}" .else .error CROSS_TOOLCHAIN ${CROSS_TOOLCHAIN} not found .endif CROSSENV+=CROSS_TOOLCHAIN="${CROSS_TOOLCHAIN}" .endif .if defined(CROSS_TOOLCHAIN_PREFIX) CROSS_COMPILER_PREFIX?=${CROSS_TOOLCHAIN_PREFIX} .endif XCOMPILERS= CC CXX CPP .for COMPILER in ${XCOMPILERS} .if defined(CROSS_COMPILER_PREFIX) X${COMPILER}?= ${CROSS_COMPILER_PREFIX}${${COMPILER}} .else X${COMPILER}?= ${${COMPILER}} .endif .endfor # If a full path to an external cross compiler is given, don't build # a cross compiler. .if ${XCC:N${CCACHE_BIN}:M/*} MK_CLANG_BOOTSTRAP= no MK_GCC_BOOTSTRAP= no .endif # Pull in compiler metadata from buildworld/toolchain if possible to avoid # running CC from bsd.compiler.mk. .if make(installworld) || make(install) || make(distributeworld) || \ make(stageworld) .-include "${OBJTOP}/compiler-metadata.mk" .endif # Pull in COMPILER_TYPE and COMPILER_FREEBSD_VERSION early. Pull it from the # tree to be friendlier to foreign OS builds. It's safe to do so unconditionally # here since we will always have the right make, unlike in src/Makefile .include "share/mk/bsd.compiler.mk" .include "share/mk/src.opts.mk" # Check if there is a local compiler that can satisfy as an external compiler. # Which compiler is expected to be used? .if ${MK_CLANG_BOOTSTRAP} == "yes" WANT_COMPILER_TYPE= clang .elif ${MK_GCC_BOOTSTRAP} == "yes" WANT_COMPILER_TYPE= gcc .else WANT_COMPILER_TYPE= .endif .if !defined(WANT_COMPILER_FREEBSD_VERSION) .if ${WANT_COMPILER_TYPE} == "clang" WANT_COMPILER_FREEBSD_VERSION_FILE= lib/clang/freebsd_cc_version.h WANT_COMPILER_FREEBSD_VERSION!= \ awk '$$2 == "FREEBSD_CC_VERSION" {printf("%d\n", $$3)}' \ ${SRCDIR}/${WANT_COMPILER_FREEBSD_VERSION_FILE} || echo unknown WANT_COMPILER_VERSION_FILE= lib/clang/include/clang/Basic/Version.inc WANT_COMPILER_VERSION!= \ awk '$$2 == "CLANG_VERSION" {split($$3, a, "."); print a[1] * 10000 + a[2] * 100 + a[3]}' \ ${SRCDIR}/${WANT_COMPILER_VERSION_FILE} || echo unknown .elif ${WANT_COMPILER_TYPE} == "gcc" WANT_COMPILER_FREEBSD_VERSION_FILE= gnu/usr.bin/cc/cc_tools/freebsd-native.h WANT_COMPILER_FREEBSD_VERSION!= \ awk '$$2 == "FBSD_CC_VER" {printf("%d\n", $$3)}' \ ${SRCDIR}/${WANT_COMPILER_FREEBSD_VERSION_FILE} || echo unknown WANT_COMPILER_VERSION_FILE= contrib/gcc/BASE-VER WANT_COMPILER_VERSION!= \ awk -F. '{print $$1 * 10000 + $$2 * 100 + $$3}' \ ${SRCDIR}/${WANT_COMPILER_VERSION_FILE} || echo unknown .endif .export WANT_COMPILER_FREEBSD_VERSION WANT_COMPILER_VERSION .endif # !defined(WANT_COMPILER_FREEBSD_VERSION) # It needs to be the same revision as we would build for the bootstrap. # If the expected vs CC is different then we can't skip. # GCC cannot be used for cross-arch yet. For clang we pass -target later if # TARGET_ARCH!=MACHINE_ARCH. .if ${MK_SYSTEM_COMPILER} == "yes" && \ (${MK_CLANG_BOOTSTRAP} == "yes" || ${MK_GCC_BOOTSTRAP} == "yes") && \ !make(showconfig) && !make(xdev*) && \ ${WANT_COMPILER_TYPE} == ${COMPILER_TYPE} && \ (${COMPILER_TYPE} == "clang" || ${TARGET_ARCH} == ${MACHINE_ARCH}) && \ ${COMPILER_VERSION} == ${WANT_COMPILER_VERSION} && \ ${COMPILER_FREEBSD_VERSION} == ${WANT_COMPILER_FREEBSD_VERSION} # Everything matches, disable the bootstrap compiler. MK_CLANG_BOOTSTRAP= no MK_GCC_BOOTSTRAP= no USING_SYSTEM_COMPILER= yes .endif # ${WANT_COMPILER_TYPE} == ${COMPILER_TYPE} USING_SYSTEM_COMPILER?= no TEST_SYSTEM_COMPILER_VARS= \ USING_SYSTEM_COMPILER MK_SYSTEM_COMPILER \ MK_CROSS_COMPILER MK_CLANG_BOOTSTRAP MK_GCC_BOOTSTRAP \ WANT_COMPILER_TYPE WANT_COMPILER_VERSION WANT_COMPILER_VERSION_FILE \ WANT_COMPILER_FREEBSD_VERSION WANT_COMPILER_FREEBSD_VERSION_FILE \ CC COMPILER_TYPE COMPILER_FEATURES COMPILER_VERSION \ COMPILER_FREEBSD_VERSION \ X_COMPILER_TYPE X_COMPILER_FEATURES X_COMPILER_VERSION \ X_COMPILER_FREEBSD_VERSION \ LINKER_TYPE LINKER_FEATURES LINKER_VERSION \ X_LINKER_TYPE X_LINKER_FEATURES X_LINKER_VERSION test-system-compiler: .PHONY .for v in ${TEST_SYSTEM_COMPILER_VARS} ${_+_}@printf "%-35s= %s\n" "${v}" "${${v}}" .endfor .if ${USING_SYSTEM_COMPILER} == "yes" && \ (make(buildworld) || make(buildkernel) || make(kernel-toolchain) || \ make(toolchain) || make(_cross-tools)) .info SYSTEM_COMPILER: Determined that CC=${CC} matches the source tree. Not bootstrapping a cross-compiler. .endif # For installworld need to ensure that the looked-up compiler metadata is # passed along rather than trying to run cc from the restricted # STRICTTMPPATH. .if ${MK_CLANG_BOOTSTRAP} == "no" && ${MK_GCC_BOOTSTRAP} == "no" .if !defined(X_COMPILER_TYPE) CROSSENV+= COMPILER_VERSION=${COMPILER_VERSION} \ COMPILER_TYPE=${COMPILER_TYPE} \ COMPILER_FEATURES="${COMPILER_FEATURES}" \ COMPILER_FREEBSD_VERSION=${COMPILER_FREEBSD_VERSION} .else CROSSENV+= COMPILER_VERSION=${X_COMPILER_VERSION} \ COMPILER_FEATURES="${X_COMPILER_FEATURES}" \ COMPILER_TYPE=${X_COMPILER_TYPE} \ COMPILER_FREEBSD_VERSION=${X_COMPILER_FREEBSD_VERSION} .endif .endif # Store some compiler metadata for use in installworld where we don't # want to invoke CC at all. _COMPILER_METADATA_VARS= COMPILER_VERSION \ COMPILER_TYPE \ COMPILER_FEATURES \ COMPILER_FREEBSD_VERSION \ LINKER_VERSION \ LINKER_FEATURES \ LINKER_TYPE compiler-metadata.mk: .PHONY .META @: > ${.TARGET} @echo ".info Using cached compiler metadata from build at $$(hostname) on $$(date)" \ > ${.TARGET} .for v in ${_COMPILER_METADATA_VARS} @echo "${v}=${${v}}" >> ${.TARGET} .endfor @echo ".export ${_COMPILER_METADATA_VARS}" >> ${.TARGET} # Handle external binutils. .if defined(CROSS_TOOLCHAIN_PREFIX) CROSS_BINUTILS_PREFIX?=${CROSS_TOOLCHAIN_PREFIX} .endif # If we do not have a bootstrap binutils (because the in-tree one does not # support the target architecture), provide a default cross-binutils prefix. # This allows riscv64 builds, for example, to automatically use the # riscv64-binutils port or package. .if !make(showconfig) .if !empty(BROKEN_OPTIONS:MBINUTILS_BOOTSTRAP) && \ ${MK_LLD_BOOTSTRAP} == "no" && \ !defined(CROSS_BINUTILS_PREFIX) CROSS_BINUTILS_PREFIX=/usr/local/${TARGET_ARCH}-freebsd/bin/ .if !exists(${CROSS_BINUTILS_PREFIX}) .error In-tree binutils does not support the ${TARGET_ARCH} architecture. Install the ${TARGET_ARCH}-binutils port or package or set CROSS_BINUTILS_PREFIX. .endif .endif .endif XBINUTILS= AS AR LD NM OBJCOPY RANLIB SIZE STRINGS .for BINUTIL in ${XBINUTILS} .if defined(CROSS_BINUTILS_PREFIX) && \ exists(${CROSS_BINUTILS_PREFIX}${${BINUTIL}}) X${BINUTIL}?= ${CROSS_BINUTILS_PREFIX}${${BINUTIL}} .else X${BINUTIL}?= ${${BINUTIL}} .endif .endfor # We must do lib/ and libexec/ before bin/ in case of a mid-install error to # keep the users system reasonably usable. For static->dynamic root upgrades, # we don't want to install a dynamic binary without rtld and the needed # libraries. More commonly, for dynamic root, we don't want to install a # binary that requires a newer library version that hasn't been installed yet. # This ordering is not a guarantee though. The only guarantee of a working # system here would require fine-grained ordering of all components based # on their dependencies. .if !empty(SUBDIR_OVERRIDE) SUBDIR= ${SUBDIR_OVERRIDE} .else SUBDIR= lib libexec .if !defined(NO_ROOT) && (make(installworld) || make(install)) # Ensure libraries are installed before progressing. SUBDIR+=.WAIT .endif SUBDIR+=bin .if ${MK_CDDL} != "no" SUBDIR+=cddl .endif SUBDIR+=gnu include .if ${MK_KERBEROS} != "no" SUBDIR+=kerberos5 .endif .if ${MK_RESCUE} != "no" SUBDIR+=rescue .endif SUBDIR+=sbin .if ${MK_CRYPT} != "no" SUBDIR+=secure .endif .if !defined(NO_SHARE) SUBDIR+=share .endif .if ${MK_BOOT} != "no" SUBDIR+=stand .endif SUBDIR+=sys usr.bin usr.sbin .if ${MK_TESTS} != "no" SUBDIR+= tests .endif .if ${MK_OFED} != "no" SUBDIR+=contrib/ofed .endif # Local directories are built in parallel with the base system directories. # Users may insert a .WAIT directive at the beginning or elsewhere within # the LOCAL_DIRS and LOCAL_LIB_DIRS lists as needed. .for _DIR in ${LOCAL_DIRS} .if ${_DIR} == ".WAIT" || exists(${.CURDIR}/${_DIR}/Makefile) SUBDIR+= ${_DIR} .endif .endfor # Add LOCAL_LIB_DIRS, but only if they will not be picked up as a SUBDIR # of a LOCAL_DIRS directory. This allows LOCAL_DIRS=foo and # LOCAL_LIB_DIRS=foo/lib to behave as expected. .for _DIR in ${LOCAL_DIRS:M*/} ${LOCAL_DIRS:N*/:S|$|/|} _REDUNDANT_LIB_DIRS+= ${LOCAL_LIB_DIRS:M${_DIR}*} .endfor .for _DIR in ${LOCAL_LIB_DIRS} .if ${_DIR} == ".WAIT" || (empty(_REDUNDANT_LIB_DIRS:M${_DIR}) && exists(${.CURDIR}/${_DIR}/Makefile)) SUBDIR+= ${_DIR} .endif .endfor # We must do etc/ last as it hooks into building the man whatis file # by calling 'makedb' in share/man. This is only relevant for # install/distribute so they build the whatis file after every manpage is # installed. .if make(installworld) || make(install) SUBDIR+=.WAIT .endif SUBDIR+=etc .endif # !empty(SUBDIR_OVERRIDE) .if defined(NOCLEAN) .warning NOCLEAN option is deprecated. Use NO_CLEAN instead. NO_CLEAN= ${NOCLEAN} .endif .if defined(NO_CLEANDIR) CLEANDIR= clean cleandepend .else CLEANDIR= cleandir .endif .if defined(WORLDFAST) NO_CLEAN= t NO_OBJWALK= t .endif .if ${MK_META_MODE} == "yes" # If filemon is used then we can rely on the build being incremental-safe. # The .meta files will also track the build command and rebuild should # it change. .if empty(.MAKE.MODE:Mnofilemon) NO_CLEAN= t .endif .endif .if defined(NO_OBJWALK) || ${MK_AUTO_OBJ} == "yes" NO_OBJWALK= t NO_KERNELOBJ= t .endif .if !defined(NO_OBJWALK) _obj= obj .endif LOCAL_TOOL_DIRS?= PACKAGEDIR?= ${DESTDIR}/${DISTDIR} .if empty(SHELL:M*csh*) BUILDENV_SHELL?=${SHELL} .else BUILDENV_SHELL?=/bin/sh .endif .if !defined(SVN_CMD) || empty(SVN_CMD) . for _P in /usr/bin /usr/local/bin . for _S in svn svnlite . if exists(${_P}/${_S}) SVN_CMD= ${_P}/${_S} . endif . endfor . endfor .export SVN_CMD .endif SVNFLAGS?= -r HEAD .if !defined(VCS_REVISION) || empty(VCS_REVISION) .if !defined(SVNVERSION_CMD) || empty(SVNVERSION_CMD) . for _D in ${PATH:S,:, ,g} . if exists(${_D}/svnversion) SVNVERSION_CMD?=${_D}/svnversion . endif . if exists(${_D}/svnliteversion) SVNVERSION_CMD?=${_D}/svnliteversion . endif . endfor .endif _VCS_REVISION?= $$(eval ${SVNVERSION_CMD} ${SRCDIR}) . if !empty(_VCS_REVISION) VCS_REVISION= $$(echo r${_VCS_REVISION}) . endif .export VCS_REVISION .endif .if !defined(OSRELDATE) .if exists(/usr/include/osreldate.h) OSRELDATE!= awk '/^\#define[[:space:]]*__FreeBSD_version/ { print $$3 }' \ /usr/include/osreldate.h .else OSRELDATE= 0 .endif .export OSRELDATE .endif # Set VERSION for CTFMERGE to use via the default CTFFLAGS=-L VERSION. .if !defined(_REVISION) _REVISION!= ${MAKE} -C ${SRCDIR}/release MK_AUTO_OBJ=no -V REVISION .export _REVISION .endif .if !defined(_BRANCH) _BRANCH!= ${MAKE} -C ${SRCDIR}/release MK_AUTO_OBJ=no -V BRANCH .export _BRANCH .endif .if !defined(SRCRELDATE) SRCRELDATE!= awk '/^\#define[[:space:]]*__FreeBSD_version/ { print $$3 }' \ ${SRCDIR}/sys/sys/param.h .export SRCRELDATE .endif .if !defined(VERSION) VERSION= FreeBSD ${_REVISION}-${_BRANCH:C/-p[0-9]+$//} ${TARGET_ARCH} ${SRCRELDATE} .export VERSION .endif .if !defined(PKG_VERSION) .if ${_BRANCH:MSTABLE*} || ${_BRANCH:MCURRENT*} || ${_BRANCH:MALPHA*} TIMENOW= %Y%m%d%H%M%S EXTRA_REVISION= .s${TIMENOW:gmtime} .endif .if ${_BRANCH:M*-p*} EXTRA_REVISION= _${_BRANCH:C/.*-p([0-9]+$)/\1/} .endif PKG_VERSION= ${_REVISION}${EXTRA_REVISION} .endif KNOWN_ARCHES?= aarch64/arm64 \ amd64 \ arm \ armeb/arm \ armv6/arm \ armv7/arm \ i386 \ mips \ mipsel/mips \ mips64el/mips \ mipsn32el/mips \ mips64/mips \ mipsn32/mips \ mipshf/mips \ mipselhf/mips \ mips64elhf/mips \ mips64hf/mips \ powerpc \ powerpc64/powerpc \ powerpcspe/powerpc \ riscv64/riscv \ riscv64sf/riscv \ sparc64 .if ${TARGET} == ${TARGET_ARCH} _t= ${TARGET} .else _t= ${TARGET_ARCH}/${TARGET} .endif .for _t in ${_t} .if empty(KNOWN_ARCHES:M${_t}) .error Unknown target ${TARGET_ARCH}:${TARGET}. .endif .endfor .if ${TARGET} == ${MACHINE} TARGET_CPUTYPE?=${CPUTYPE} .else TARGET_CPUTYPE?= .endif .if !empty(TARGET_CPUTYPE) _TARGET_CPUTYPE=${TARGET_CPUTYPE} .else _TARGET_CPUTYPE=dummy .endif _CPUTYPE!= MAKEFLAGS= CPUTYPE=${_TARGET_CPUTYPE} ${MAKE} -f /dev/null \ -m ${.CURDIR}/share/mk MK_AUTO_OBJ=no -V CPUTYPE .if ${_CPUTYPE} != ${_TARGET_CPUTYPE} .error CPUTYPE global should be set with ?=. .endif .if make(buildworld) BUILD_ARCH!= uname -p .if ${MACHINE_ARCH} != ${BUILD_ARCH} .error To cross-build, set TARGET_ARCH. .endif .endif WORLDTMP?= ${OBJTOP}/tmp BPATH= ${CCACHE_WRAPPER_PATH_PFX}${WORLDTMP}/legacy/usr/sbin:${WORLDTMP}/legacy/usr/bin:${WORLDTMP}/legacy/bin XPATH= ${WORLDTMP}/usr/sbin:${WORLDTMP}/usr/bin STRICTTMPPATH= ${BPATH}:${XPATH} TMPPATH= ${STRICTTMPPATH}:${PATH} # # Avoid running mktemp(1) unless actually needed. # It may not be functional, e.g., due to new ABI # when in the middle of installing over this system. # .if make(distributeworld) || make(installworld) || make(stageworld) INSTALLTMP!= mktemp -d -u -t install .endif .if make(stagekernel) || make(distributekernel) TAGS+= kernel PACKAGE= kernel .endif # # Building a world goes through the following stages # # 1. legacy stage [BMAKE] # This stage is responsible for creating compatibility # shims that are needed by the bootstrap-tools, # build-tools and cross-tools stages. These are generally # APIs that tools from one of those three stages need to # build that aren't present on the host. # 1. bootstrap-tools stage [BMAKE] # This stage is responsible for creating programs that # are needed for backward compatibility reasons. They # are not built as cross-tools. # 2. build-tools stage [TMAKE] # This stage is responsible for creating the object # tree and building any tools that are needed during # the build process. Some programs are listed during # this phase because they build binaries to generate # files needed to build these programs. This stage also # builds the 'build-tools' target rather than 'all'. # 3. cross-tools stage [XMAKE] # This stage is responsible for creating any tools that # are needed for building the system. A cross-compiler is one # of them. This differs from build tools in two ways: # 1. the 'all' target is built rather than 'build-tools' # 2. these tools are installed into TMPPATH for stage 4. # 4. world stage [WMAKE] # This stage actually builds the world. # 5. install stage (optional) [IMAKE] # This stage installs a previously built world. # BOOTSTRAPPING?= 0 # Keep these in sync MINIMUM_SUPPORTED_OSREL?= 1002501 MINIMUM_SUPPORTED_REL?= 10.3 # Common environment for world related stages CROSSENV+= \ MACHINE_ARCH=${TARGET_ARCH} \ MACHINE=${TARGET} \ CPUTYPE=${TARGET_CPUTYPE} .if ${MK_META_MODE} != "no" # Don't rebuild build-tools targets during normal build. CROSSENV+= BUILD_TOOLS_META=.NOMETA .endif .if defined(TARGET_CFLAGS) CROSSENV+= ${TARGET_CFLAGS} .endif # bootstrap-tools stage BMAKEENV= INSTALL="sh ${.CURDIR}/tools/install.sh" \ TOOLS_PREFIX=${WORLDTMP} \ PATH=${BPATH}:${PATH} \ WORLDTMP=${WORLDTMP} \ MAKEFLAGS="-m ${.CURDIR}/tools/build/mk ${.MAKEFLAGS}" # need to keep this in sync with targets/pseudo/bootstrap-tools/Makefile BSARGS= DESTDIR= \ OBJTOP='${WORLDTMP}/obj-tools' \ OBJROOT='$${OBJTOP}/' \ MAKEOBJDIRPREFIX= \ BOOTSTRAPPING=${OSRELDATE} \ BWPHASE=${.TARGET:C,^_,,} \ SSP_CFLAGS= \ MK_HTML=no NO_LINT=yes MK_MAN=no \ -DNO_PIC MK_PROFILE=no -DNO_SHARED \ -DNO_CPU_CFLAGS MK_WARNS=no MK_CTF=no \ MK_CLANG_EXTRAS=no MK_CLANG_FULL=no \ MK_LLDB=no MK_TESTS=no \ MK_LLD=${MK_LLD_BOOTSTRAP} \ MK_INCLUDES=yes BMAKE= \ ${BMAKEENV} ${MAKE} ${WORLD_FLAGS} -f Makefile.inc1 \ ${BSARGS} # build-tools stage TMAKE= \ ${BMAKEENV} ${MAKE} ${WORLD_FLAGS} -f Makefile.inc1 \ TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ DESTDIR= \ BOOTSTRAPPING=${OSRELDATE} \ BWPHASE=${.TARGET:C,^_,,} \ SSP_CFLAGS= \ -DNO_LINT \ -DNO_CPU_CFLAGS MK_WARNS=no MK_CTF=no \ MK_CLANG_EXTRAS=no MK_CLANG_FULL=no \ MK_LLDB=no MK_TESTS=no # cross-tools stage # TOOLS_PREFIX set in BMAKE XMAKE= ${BMAKE} \ TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ MK_GDB=no MK_LLD_IS_LD=${MK_LLD_BOOTSTRAP} MK_TESTS=no # kernel-tools stage KTMAKEENV= INSTALL="sh ${.CURDIR}/tools/install.sh" \ PATH=${BPATH}:${PATH} \ WORLDTMP=${WORLDTMP} KTMAKE= TOOLS_PREFIX=${WORLDTMP} \ ${KTMAKEENV} ${MAKE} ${WORLD_FLAGS} -f Makefile.inc1 \ DESTDIR= \ OBJTOP='${WORLDTMP}/obj-kernel-tools' \ OBJROOT='$${OBJTOP}/' \ MAKEOBJDIRPREFIX= \ BOOTSTRAPPING=${OSRELDATE} \ SSP_CFLAGS= \ MK_HTML=no -DNO_LINT MK_MAN=no \ -DNO_PIC MK_PROFILE=no -DNO_SHARED \ -DNO_CPU_CFLAGS MK_WARNS=no MK_CTF=no # world stage WMAKEENV= ${CROSSENV} \ INSTALL="sh ${.CURDIR}/tools/install.sh" \ PATH=${TMPPATH} \ SYSROOT=${WORLDTMP} # make hierarchy HMAKE= PATH=${TMPPATH} ${MAKE} LOCAL_MTREE=${LOCAL_MTREE:Q} .if defined(NO_ROOT) HMAKE+= PATH=${TMPPATH} METALOG=${METALOG} -DNO_ROOT .endif CROSSENV+= CC="${XCC} ${XCFLAGS}" CXX="${XCXX} ${XCXXFLAGS} ${XCFLAGS}" \ CPP="${XCPP} ${XCFLAGS}" \ AS="${XAS}" AR="${XAR}" LD="${XLD}" LLVM_LINK="${XLLVM_LINK}" \ NM=${XNM} OBJCOPY="${XOBJCOPY}" \ RANLIB=${XRANLIB} STRINGS=${XSTRINGS} \ SIZE="${XSIZE}" .if defined(CROSS_BINUTILS_PREFIX) && exists(${CROSS_BINUTILS_PREFIX}) # In the case of xdev-build tools, CROSS_BINUTILS_PREFIX won't be a # directory, but the compiler will look in the right place for its # tools so we don't need to tell it where to look. BFLAGS+= -B${CROSS_BINUTILS_PREFIX} .endif # The internal bootstrap compiler has a default sysroot set by TOOLS_PREFIX # and target set by TARGET/TARGET_ARCH. However, there are several needs to # always pass an explicit --sysroot and -target. # - External compiler needs sysroot and target flags. # - External ld needs sysroot. # - To be clear about the use of a sysroot when using the internal compiler. # - Easier debugging. # - Allowing WITH_SYSTEM_COMPILER+WITH_META_MODE to work together due to # the flip-flopping build command when sometimes using external and # sometimes using internal. # - Allow using lld which has no support for default paths. .if !defined(CROSS_BINUTILS_PREFIX) || !exists(${CROSS_BINUTILS_PREFIX}) BFLAGS+= -B${WORLDTMP}/usr/bin .endif .if ${TARGET} == "arm" .if ${TARGET_ARCH:Marmv[67]*} != "" && ${TARGET_CPUTYPE:M*soft*} == "" TARGET_ABI= gnueabihf .else TARGET_ABI= gnueabi .endif .endif .if ${WANT_COMPILER_TYPE} == gcc || \ (defined(X_COMPILER_TYPE) && ${X_COMPILER_TYPE} == gcc) # GCC requires -isystem and -L when using a cross-compiler. --sysroot # won't set header path and -L is used to ensure the base library path # is added before the port PREFIX library path. XCFLAGS+= -isystem ${WORLDTMP}/usr/include -L${WORLDTMP}/usr/lib # GCC requires -B to find /usr/lib/crti.o when using a cross-compiler # combined with --sysroot. XCFLAGS+= -B${WORLDTMP}/usr/lib # Force using libc++ for external GCC. .if defined(X_COMPILER_TYPE) && \ ${X_COMPILER_TYPE} == gcc && ${X_COMPILER_VERSION} >= 40800 XCXXFLAGS+= -isystem ${WORLDTMP}/usr/include/c++/v1 -std=c++11 \ -nostdinc++ .endif .elif ${WANT_COMPILER_TYPE} == clang || \ (defined(X_COMPILER_TYPE) && ${X_COMPILER_TYPE} == clang) MACHINE_ABI?= unknown MACHINE_TRIPLE?=${MACHINE_ARCH:S/amd64/x86_64/:C/hf$//:S/mipsn32/mips64/}-${MACHINE_ABI}-freebsd12.0 TARGET_ABI?= unknown TARGET_TRIPLE?= ${TARGET_ARCH:S/amd64/x86_64/:C/hf$//:S/mipsn32/mips64/}-${TARGET_ABI}-freebsd12.0 XCFLAGS+= -target ${TARGET_TRIPLE} .endif XCFLAGS+= --sysroot=${WORLDTMP} .if !empty(BFLAGS) XCFLAGS+= ${BFLAGS} .endif .if ${MK_LIB32} != "no" && (${TARGET_ARCH} == "amd64" || \ ${TARGET_ARCH} == "powerpc64" || ${TARGET_ARCH:Mmips64*} != "") LIBCOMPAT= 32 .include "Makefile.libcompat" .elif ${MK_LIBSOFT} != "no" && ${TARGET_ARCH:Marmv[67]*} != "" LIBCOMPAT= SOFT .include "Makefile.libcompat" .endif # META_MODE normally ignores host file changes since every build updates # timestamps (see NO_META_IGNORE_HOST in sys.mk). There are known times # when the ABI breaks though that we want to force rebuilding WORLDTMP # to get updated host tools. .if ${MK_META_MODE} == "yes" && defined(NO_CLEAN) && \ !defined(NO_META_IGNORE_HOST) && !defined(NO_META_IGNORE_HOST_HEADERS) && \ !make(showconfig) # r318736 - ino64 major ABI breakage META_MODE_BAD_ABI_VERS+= 1200031 .if !defined(OBJDIR_HOST_OSRELDATE) .if exists(${OBJTOP}/host-osreldate.h) OBJDIR_HOST_OSRELDATE!= \ awk '/^\#define[[:space:]]*__FreeBSD_version/ { print $$3 }' \ ${OBJTOP}/host-osreldate.h .elif exists(${WORLDTMP}/usr/include/osreldate.h) OBJDIR_HOST_OSRELDATE= 0 .endif .export OBJDIR_HOST_OSRELDATE .endif # Note that this logic is the opposite of normal BOOTSTRAP handling. We want # to compare the WORLDTMP's OSRELDATE to the host's OSRELDATE. If the WORLDTMP # is older than the ABI-breakage OSRELDATE of the HOST then we rebuild. .if defined(OBJDIR_HOST_OSRELDATE) .for _ver in ${META_MODE_BAD_ABI_VERS} .if ${OSRELDATE} >= ${_ver} && ${OBJDIR_HOST_OSRELDATE} < ${_ver} _meta_mode_need_rebuild= ${_ver} .endif .endfor .if defined(_meta_mode_need_rebuild) .info META_MODE: Rebuilding host tools due to ABI breakage in __FreeBSD_version ${_meta_mode_need_rebuild}. NO_META_IGNORE_HOST_HEADERS= 1 .export NO_META_IGNORE_HOST_HEADERS .endif # defined(_meta_mode_need_rebuild) .endif # defined(OBJDIR_HOST_OSRELDATE) .endif # ${MK_META_MODE} == "yes" && defined(NO_CLEAN) ... # This is only used for META_MODE+filemon to track what the oldest # __FreeBSD_version is in WORLDTMP. This purposely does NOT have # a make dependency on /usr/include/osreldate.h as the file should # only be copied when it is missing or meta mode determines it has changed. # Since host files are normally ignored without NO_META_IGNORE_HOST # the file will never be updated unless that flag is specified. This # allows tracking the oldest osreldate to force rebuilds via # META_MODE_BADABI_REVS above. host-osreldate.h: # DO NOT ADD /usr/include/osreldate.h here @cp -f /usr/include/osreldate.h ${.TARGET} WMAKE= ${WMAKEENV} ${MAKE} ${WORLD_FLAGS} -f Makefile.inc1 \ BWPHASE=${.TARGET:C,^_,,} \ DESTDIR=${WORLDTMP} IMAKEENV= ${CROSSENV} IMAKE= ${IMAKEENV} ${MAKE} -f Makefile.inc1 \ ${IMAKE_INSTALL} ${IMAKE_MTREE} .if empty(.MAKEFLAGS:M-n) IMAKEENV+= PATH=${STRICTTMPPATH}:${INSTALLTMP} \ LD_LIBRARY_PATH=${INSTALLTMP} \ PATH_LOCALE=${INSTALLTMP}/locale IMAKE+= __MAKE_SHELL=${INSTALLTMP}/sh .else IMAKEENV+= PATH=${TMPPATH}:${INSTALLTMP} .endif .if defined(DB_FROM_SRC) INSTALLFLAGS+= -N ${.CURDIR}/etc MTREEFLAGS+= -N ${.CURDIR}/etc .endif _INSTALL_DDIR= ${DESTDIR}/${DISTDIR} INSTALL_DDIR= ${_INSTALL_DDIR:S://:/:g:C:/$::} .if defined(NO_ROOT) METALOG?= ${DESTDIR}/${DISTDIR}/METALOG METALOG:= ${METALOG:C,//+,/,g} IMAKE+= -DNO_ROOT METALOG=${METALOG} INSTALLFLAGS+= -U -M ${METALOG} -D ${INSTALL_DDIR} MTREEFLAGS+= -W .endif .if defined(BUILD_PKGS) INSTALLFLAGS+= -h sha256 .endif .if defined(DB_FROM_SRC) || defined(NO_ROOT) IMAKE_INSTALL= INSTALL="install ${INSTALLFLAGS}" IMAKE_MTREE= MTREE_CMD="mtree ${MTREEFLAGS}" .endif # kernel stage KMAKEENV= ${WMAKEENV:NSYSROOT=*} KMAKE= ${KMAKEENV} ${MAKE} ${.MAKEFLAGS} ${KERNEL_FLAGS} KERNEL=${INSTKERNNAME} # # buildworld # # Attempt to rebuild the entire system, with reasonable chance of # success, regardless of how old your existing system is. # _sanity_check: .PHONY .MAKE .if ${.CURDIR:C/[^,]//g} != "" # The m4 build of sendmail files doesn't like it if ',' is used # anywhere in the path of it's files. @echo @echo "*** Error: path to source tree contains a comma ','" @echo @false .elif ${.CURDIR:M*\:*} != "" # Using ':' leaks into PATH and breaks finding cross-tools. @echo @echo "*** Error: path to source tree contains a colon ':'" @echo @false .endif # Our current approach to dependency tracking cannot cope with certain source # tree changes, particularly with respect to removing source files and # replacing generated files. Handle these cases here in an ad-hoc fashion. _cleanobj_fast_depend_hack: .PHONY # Syscall stubs rewritten in C and obsolete MD assembly implementations # Date SVN Rev Syscalls # 20170624 r320278 fstat fstatat fstatfs getdirentries getfsstat statfs # 20180404 r332048 sigreturn # 20180405 r332080 shmat # 20180406 r332119 setlogin # 20180411 r332443 exect # 20180525 r334224 vadvise .for f in exect fstat fstatat fstatfs getdirentries getfsstat setlogin shmat sigreturn statfs vadvise .if exists(${OBJTOP}/lib/libc/.depend.${f}.o) @if egrep -qw '${f}\.[sS]' \ ${OBJTOP}/lib/libc/.depend.${f}.o; then \ echo Removing stale dependencies for ${f} syscall wrappers; \ rm -f ${OBJTOP}/lib/libc/.depend.${f}.* \ ${LIBCOMPAT:D${LIBCOMPAT_OBJTOP}/lib/libc/.depend.${f}.*}; \ fi .endif .endfor # 20170607 remove stale dependencies for utimens* wrappers removed in r319663 .for f in futimens utimensat .if exists(${OBJTOP}/lib/libc/.depend.${f}.o) @if egrep -q '/${f}.c' \ ${OBJTOP}/lib/libc/.depend.${f}.o; then \ echo Removing stale dependencies for ${f} syscall wrappers; \ rm -f ${OBJTOP}/lib/libc/.depend.${f}.* \ ${LIBCOMPAT:D${LIBCOMPAT_OBJTOP}/lib/libc/.depend.${f}.*}; \ fi .endif .endfor # 20170523 remove stale generated asm files for functions which are no longer # syscalls after r302092 (pipe) and r318736 (others) .for f in getdents lstat mknod pipe stat .if exists(${OBJTOP}/lib/libc/${f}.s) || \ exists(${OBJTOP}/lib/libc/${f}.S) @echo Removing stale generated ${f} syscall files @rm -f ${OBJTOP}/lib/libc/${f}.* \ ${OBJTOP}/lib/libc/.depend.${f}.* \ ${LIBCOMPAT:D${LIBCOMPAT_OBJTOP}/lib/libc/${f}.*} \ ${LIBCOMPAT:D${LIBCOMPAT_OBJTOP}/lib/libc/.depend.${f}.*} .endif .endfor _worldtmp: .PHONY @echo @echo "--------------------------------------------------------------" @echo ">>> Rebuilding the temporary build tree" @echo "--------------------------------------------------------------" .if !defined(NO_CLEAN) rm -rf ${WORLDTMP} .else .if exists(${WORLDTMP}) @echo ">>> Deleting stale files in build tree..." ${_+_}cd ${.CURDIR}; ${WMAKE} -DBATCH_DELETE_OLD_FILES \ delete-old delete-old-libs >/dev/null .endif rm -rf ${WORLDTMP}/legacy/usr/include .if ${USING_SYSTEM_COMPILER} == "yes" .for cc in cc c++ if [ -x ${WORLDTMP}/usr/bin/${cc} ]; then \ inum=$$(stat -f %i ${WORLDTMP}/usr/bin/${cc}); \ find ${WORLDTMP}/usr/bin -inum $${inum} -delete; \ fi .endfor .endif # ${USING_SYSTEM_COMPILER} == "yes" .endif # !defined(NO_CLEAN) @mkdir -p ${WORLDTMP} @touch ${WORLDTMP}/${.TARGET} .for _dir in \ lib lib/casper usr legacy/bin legacy/usr mkdir -p ${WORLDTMP}/${_dir} .endfor mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${WORLDTMP}/legacy/usr >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.include.dist \ -p ${WORLDTMP}/legacy/usr/include >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${WORLDTMP}/usr >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.include.dist \ -p ${WORLDTMP}/usr/include >/dev/null ln -sf ${.CURDIR}/sys ${WORLDTMP} .if ${MK_DEBUG_FILES} != "no" mtree -deU -f ${.CURDIR}/etc/mtree/BSD.debug.dist \ -p ${WORLDTMP}/legacy/usr/lib >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.debug.dist \ -p ${WORLDTMP}/usr/lib >/dev/null .endif .for _mtree in ${LOCAL_MTREE} mtree -deU -f ${.CURDIR}/${_mtree} -p ${WORLDTMP} > /dev/null .endfor _legacy: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 1.1: legacy release compatibility shims" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${BMAKE} legacy _bootstrap-tools: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 1.2: bootstrap tools" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${BMAKE} bootstrap-tools _cleanobj: .if !defined(NO_CLEAN) @echo @echo "--------------------------------------------------------------" @echo ">>> stage 2.1: cleaning up the object tree" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${WMAKE} ${CLEANDIR} .if defined(LIBCOMPAT) ${_+_}cd ${.CURDIR}; ${LIBCOMPATWMAKE} -f Makefile.inc1 ${CLEANDIR} .endif .else ${_+_}cd ${.CURDIR}; ${WMAKE} _cleanobj_fast_depend_hack .endif # !defined(NO_CLEAN) _obj: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 2.2: rebuilding the object tree" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${WMAKE} obj _build-tools: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 2.3: build tools" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${TMAKE} build-tools _cross-tools: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 3: cross tools" @echo "--------------------------------------------------------------" @rm -f ${OBJTOP}/compiler-metadata.mk ${_+_}cd ${.CURDIR}; ${XMAKE} cross-tools ${_+_}cd ${.CURDIR}; ${XMAKE} kernel-tools _build-metadata: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 3.1: recording build metadata" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${WMAKE} compiler-metadata.mk ${_+_}cd ${.CURDIR}; ${WMAKE} host-osreldate.h _includes: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 4.1: building includes" @echo "--------------------------------------------------------------" # Special handling for SUBDIR_OVERRIDE in buildworld as they most likely need # headers from default SUBDIR. Do SUBDIR_OVERRIDE includes last. ${_+_}cd ${.CURDIR}; ${WMAKE} SUBDIR_OVERRIDE= SHARED=symlinks \ MK_INCLUDES=yes includes .if !empty(SUBDIR_OVERRIDE) && make(buildworld) ${_+_}cd ${.CURDIR}; ${WMAKE} MK_INCLUDES=yes SHARED=symlinks includes .endif _libraries: @echo @echo "--------------------------------------------------------------" @echo ">>> stage 4.2: building libraries" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; \ ${WMAKE} -DNO_FSCHG MK_HTML=no -DNO_LINT MK_MAN=no \ MK_PROFILE=no MK_TESTS=no MK_TESTS_SUPPORT=${MK_TESTS} libraries everything: .PHONY @echo @echo "--------------------------------------------------------------" @echo ">>> stage 4.3: building everything" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; _PARALLEL_SUBDIR_OK=1 ${WMAKE} all WMAKE_TGTS= .if !defined(WORLDFAST) WMAKE_TGTS+= _sanity_check _worldtmp _legacy .if empty(SUBDIR_OVERRIDE) WMAKE_TGTS+= _bootstrap-tools .endif WMAKE_TGTS+= _cleanobj .if !defined(NO_OBJWALK) WMAKE_TGTS+= _obj .endif WMAKE_TGTS+= _build-tools _cross-tools WMAKE_TGTS+= _build-metadata WMAKE_TGTS+= _includes .endif .if !defined(NO_LIBS) WMAKE_TGTS+= _libraries .endif WMAKE_TGTS+= everything .if defined(LIBCOMPAT) && empty(SUBDIR_OVERRIDE) WMAKE_TGTS+= build${libcompat} .endif buildworld: buildworld_prologue ${WMAKE_TGTS} buildworld_epilogue .PHONY .ORDER: buildworld_prologue ${WMAKE_TGTS} buildworld_epilogue buildworld_prologue: .PHONY @echo "--------------------------------------------------------------" @echo ">>> World build started on `LC_ALL=C date`" @echo "--------------------------------------------------------------" buildworld_epilogue: .PHONY @echo @echo "--------------------------------------------------------------" @echo ">>> World build completed on `LC_ALL=C date`" @echo "--------------------------------------------------------------" # # We need to have this as a target because the indirection between Makefile # and Makefile.inc1 causes the correct PATH to be used, rather than a # modification of the current environment's PATH. In addition, we need # to quote multiword values. # buildenvvars: .PHONY @echo ${WMAKEENV:Q} ${.MAKE.EXPORTED:@v@$v=\"${$v}\"@} .if ${.TARGETS:Mbuildenv} .if ${.MAKEFLAGS:M-j} .error The buildenv target is incompatible with -j .endif .endif BUILDENV_DIR?= ${.CURDIR} # # Note: make will report any errors the shell reports. This can # be odd if the last command in an interactive shell generates an # error or is terminated by SIGINT. These reported errors look bad, # but are harmless. Allowing them also allows BUIDLENV_SHELL to # be a complex command whose status will be returned to the caller. # Some scripts in tools rely on this behavior to report build errors. # buildenv: .PHONY @echo Entering world for ${TARGET_ARCH}:${TARGET} .if ${BUILDENV_SHELL:M*zsh*} @echo For ZSH you must run: export CPUTYPE=${TARGET_CPUTYPE} .endif @cd ${BUILDENV_DIR} && env ${WMAKEENV} BUILDENV=1 ${BUILDENV_SHELL} TOOLCHAIN_TGTS= ${WMAKE_TGTS:Neverything:Nbuild${libcompat}} toolchain: ${TOOLCHAIN_TGTS} .PHONY KERNEL_TOOLCHAIN_TGTS= ${TOOLCHAIN_TGTS:N_obj:N_cleanobj:N_includes:N_libraries} .if make(kernel-toolchain) .ORDER: ${KERNEL_TOOLCHAIN_TGTS} .endif kernel-toolchain: ${KERNEL_TOOLCHAIN_TGTS} .PHONY # # installcheck # # Checks to be sure system is ready for installworld/installkernel. # installcheck: _installcheck_world _installcheck_kernel .PHONY _installcheck_world: .PHONY _installcheck_kernel: .PHONY # # Require DESTDIR to be set if installing for a different architecture or # using the user/group database in the source tree. # .if ${TARGET_ARCH} != ${MACHINE_ARCH} || ${TARGET} != ${MACHINE} || \ defined(DB_FROM_SRC) .if !make(distributeworld) _installcheck_world: __installcheck_DESTDIR _installcheck_kernel: __installcheck_DESTDIR __installcheck_DESTDIR: .PHONY .if !defined(DESTDIR) || empty(DESTDIR) @echo "ERROR: Please set DESTDIR!"; \ false .endif .endif .endif .if !defined(DB_FROM_SRC) # # Check for missing UIDs/GIDs. # CHECK_UIDS= auditdistd CHECK_GIDS= audit .if ${MK_SENDMAIL} != "no" CHECK_UIDS+= smmsp CHECK_GIDS+= smmsp .endif .if ${MK_PF} != "no" CHECK_UIDS+= proxy CHECK_GIDS+= proxy authpf .endif .if ${MK_UNBOUND} != "no" CHECK_UIDS+= unbound CHECK_GIDS+= unbound .endif _installcheck_world: __installcheck_UGID __installcheck_UGID: .PHONY .for uid in ${CHECK_UIDS} @if ! `id -u ${uid} >/dev/null 2>&1`; then \ echo "ERROR: Required ${uid} user is missing, see /usr/src/UPDATING."; \ false; \ fi .endfor .for gid in ${CHECK_GIDS} @if ! `find / -prune -group ${gid} >/dev/null 2>&1`; then \ echo "ERROR: Required ${gid} group is missing, see /usr/src/UPDATING."; \ false; \ fi .endfor .endif # # If installing over the running system (DESTDIR is / or unset) and the install # includes rescue, try running rescue from the objdir as a sanity check. If # rescue is not functional (e.g., because it depends on a system call not # supported by the currently running kernel), abort the installation. # .if !make(distributeworld) && ${MK_RESCUE} != "no" && \ (empty(DESTDIR) || ${DESTDIR} == "/") && empty(BYPASS_INSTALLCHECK_SH) _installcheck_world: __installcheck_sh_check __installcheck_sh_check: .PHONY @if [ "`${OBJTOP}/rescue/rescue/rescue sh -c 'echo OK'`" != \ OK ]; then \ echo "rescue/sh check failed, installation aborted" >&2; \ false; \ fi .endif # # Required install tools to be saved in a scratch dir for safety. # .if ${MK_ZONEINFO} != "no" _zoneinfo= zic tzsetup .endif ITOOLS= [ awk cap_mkdb cat chflags chmod chown cmp cp \ date echo egrep find grep id install ${_install-info} \ ln make mkdir mtree mv pwd_mkdb \ rm sed services_mkdb sh sort strip sysctl test true uname wc ${_zoneinfo} \ ${LOCAL_ITOOLS} # Needed for share/man .if ${MK_MAN_UTILS} != "no" ITOOLS+=makewhatis .endif # # distributeworld # # Distributes everything compiled by a `buildworld'. # # installworld # # Installs everything compiled by a 'buildworld'. # # Non-base distributions produced by the base system EXTRA_DISTRIBUTIONS= doc .if defined(LIBCOMPAT) EXTRA_DISTRIBUTIONS+= lib${libcompat} .endif .if ${MK_TESTS} != "no" EXTRA_DISTRIBUTIONS+= tests .endif DEBUG_DISTRIBUTIONS= .if ${MK_DEBUG_FILES} != "no" DEBUG_DISTRIBUTIONS+= base ${EXTRA_DISTRIBUTIONS:S,doc,,:S,tests,,} .endif MTREE_MAGIC?= mtree 2.0 distributeworld installworld stageworld: _installcheck_world .PHONY mkdir -p ${INSTALLTMP} progs=$$(for prog in ${ITOOLS}; do \ if progpath=`which $$prog`; then \ echo $$progpath; \ else \ echo "Required tool $$prog not found in PATH." >&2; \ exit 1; \ fi; \ done); \ libs=$$(ldd -f "%o %p\n" -f "%o %p\n" $$progs 2>/dev/null | sort -u | \ while read line; do \ set -- $$line; \ if [ "$$2 $$3" != "not found" ]; then \ echo $$2; \ else \ echo "Required library $$1 not found." >&2; \ exit 1; \ fi; \ done); \ cp $$libs $$progs ${INSTALLTMP} cp -R $${PATH_LOCALE:-"/usr/share/locale"} ${INSTALLTMP}/locale .if defined(NO_ROOT) -mkdir -p ${METALOG:H} echo "#${MTREE_MAGIC}" > ${METALOG} .endif .if make(distributeworld) .for dist in ${EXTRA_DISTRIBUTIONS} -mkdir ${DESTDIR}/${DISTDIR}/${dist} mtree -deU -f ${.CURDIR}/etc/mtree/BSD.root.dist \ -p ${DESTDIR}/${DISTDIR}/${dist} >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${DESTDIR}/${DISTDIR}/${dist}/usr >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.include.dist \ -p ${DESTDIR}/${DISTDIR}/${dist}/usr/include >/dev/null .if ${MK_DEBUG_FILES} != "no" mtree -deU -f ${.CURDIR}/etc/mtree/BSD.debug.dist \ -p ${DESTDIR}/${DISTDIR}/${dist}/usr/lib >/dev/null .endif .if defined(LIBCOMPAT) mtree -deU -f ${.CURDIR}/etc/mtree/BSD.lib${libcompat}.dist \ -p ${DESTDIR}/${DISTDIR}/${dist}/usr >/dev/null .if ${MK_DEBUG_FILES} != "no" mtree -deU -f ${.CURDIR}/etc/mtree/BSD.lib${libcompat}.dist \ -p ${DESTDIR}/${DISTDIR}/${dist}/usr/lib/debug/usr >/dev/null .endif .endif .if ${MK_TESTS} != "no" && ${dist} == "tests" -mkdir -p ${DESTDIR}/${DISTDIR}/${dist}${TESTSBASE} mtree -deU -f ${.CURDIR}/etc/mtree/BSD.tests.dist \ -p ${DESTDIR}/${DISTDIR}/${dist}${TESTSBASE} >/dev/null .if ${MK_DEBUG_FILES} != "no" mtree -deU -f ${.CURDIR}/etc/mtree/BSD.tests.dist \ -p ${DESTDIR}/${DISTDIR}/${dist}/usr/lib/debug/${TESTSBASE} >/dev/null .endif .endif .if defined(NO_ROOT) ${IMAKEENV} mtree -C -f ${.CURDIR}/etc/mtree/BSD.root.dist | \ sed -e 's#^\./#./${dist}/#' >> ${METALOG} ${IMAKEENV} mtree -C -f ${.CURDIR}/etc/mtree/BSD.usr.dist | \ sed -e 's#^\./#./${dist}/usr/#' >> ${METALOG} ${IMAKEENV} mtree -C -f ${.CURDIR}/etc/mtree/BSD.include.dist | \ sed -e 's#^\./#./${dist}/usr/include/#' >> ${METALOG} .if defined(LIBCOMPAT) ${IMAKEENV} mtree -C -f ${.CURDIR}/etc/mtree/BSD.lib${libcompat}.dist | \ sed -e 's#^\./#./${dist}/usr/#' >> ${METALOG} .endif .endif .endfor -mkdir ${DESTDIR}/${DISTDIR}/base ${_+_}cd ${.CURDIR}/etc; ${CROSSENV} PATH=${TMPPATH} ${MAKE} \ METALOG=${METALOG} ${IMAKE_INSTALL} ${IMAKE_MTREE} \ DISTBASE=/base DESTDIR=${DESTDIR}/${DISTDIR}/base \ LOCAL_MTREE=${LOCAL_MTREE:Q} distrib-dirs .endif ${_+_}cd ${.CURDIR}; ${IMAKE} re${.TARGET:S/world$//}; \ ${IMAKEENV} rm -rf ${INSTALLTMP} .if make(distributeworld) .for dist in ${EXTRA_DISTRIBUTIONS} find ${DESTDIR}/${DISTDIR}/${dist} -mindepth 1 -type d -empty -delete .endfor .if defined(NO_ROOT) .for dist in base ${EXTRA_DISTRIBUTIONS} @# For each file that exists in this dist, print the corresponding @# line from the METALOG. This relies on the fact that @# a line containing only the filename will sort immediately before @# the relevant mtree line. cd ${DESTDIR}/${DISTDIR}; \ find ./${dist} | sort -u ${METALOG} - | \ awk 'BEGIN { print "#${MTREE_MAGIC}" } !/ type=/ { file = $$1 } / type=/ { if ($$1 == file) { sub(/^\.\/${dist}\//, "./"); print } }' > \ ${DESTDIR}/${DISTDIR}/${dist}.meta .endfor .for dist in ${DEBUG_DISTRIBUTIONS} @# For each file that exists in this dist, print the corresponding @# line from the METALOG. This relies on the fact that @# a line containing only the filename will sort immediately before @# the relevant mtree line. cd ${DESTDIR}/${DISTDIR}; \ find ./${dist}/usr/lib/debug | sort -u ${METALOG} - | \ awk 'BEGIN { print "#${MTREE_MAGIC}" } !/ type=/ { file = $$1 } / type=/ { if ($$1 == file) { sub(/^\.\/${dist}\//, "./"); print } }' > \ ${DESTDIR}/${DISTDIR}/${dist}.debug.meta .endfor .endif .endif packageworld: .PHONY .for dist in base ${EXTRA_DISTRIBUTIONS} .if defined(NO_ROOT) ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ tar cvf - --exclude usr/lib/debug \ @${DESTDIR}/${DISTDIR}/${dist}.meta | \ ${XZ_CMD} > ${PACKAGEDIR}/${dist}.txz .else ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ tar cvf - --exclude usr/lib/debug . | \ ${XZ_CMD} > ${PACKAGEDIR}/${dist}.txz .endif .endfor .for dist in ${DEBUG_DISTRIBUTIONS} . if defined(NO_ROOT) ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ tar cvf - @${DESTDIR}/${DISTDIR}/${dist}.debug.meta | \ ${XZ_CMD} > ${PACKAGEDIR}/${dist}-dbg.txz . else ${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \ tar cvLf - usr/lib/debug | \ ${XZ_CMD} > ${PACKAGEDIR}/${dist}-dbg.txz . endif .endfor # # reinstall # # If you have a build server, you can NFS mount the source and obj directories # and do a 'make reinstall' on the *client* to install new binaries from the # most recent server build. # restage reinstall: .MAKE .PHONY @echo "--------------------------------------------------------------" @echo ">>> Making hierarchy" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 \ LOCAL_MTREE=${LOCAL_MTREE:Q} hierarchy .if make(restage) @echo "--------------------------------------------------------------" @echo ">>> Making distribution" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 \ LOCAL_MTREE=${LOCAL_MTREE:Q} distribution .endif @echo @echo "--------------------------------------------------------------" @echo ">>> Installing everything" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 install .if defined(LIBCOMPAT) ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 install${libcompat} .endif redistribute: .MAKE .PHONY @echo "--------------------------------------------------------------" @echo ">>> Distributing everything" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 distribute .if defined(LIBCOMPAT) ${_+_}cd ${.CURDIR}; ${MAKE} -f Makefile.inc1 distribute${libcompat} \ DISTRIBUTION=lib${libcompat} .endif distrib-dirs distribution: .MAKE .PHONY ${_+_}cd ${.CURDIR}/etc; ${CROSSENV} PATH=${TMPPATH} ${MAKE} \ ${IMAKE_INSTALL} ${IMAKE_MTREE} METALOG=${METALOG} ${.TARGET} .if make(distribution) ${_+_}cd ${.CURDIR}; ${CROSSENV} PATH=${TMPPATH} \ ${MAKE} -f Makefile.inc1 ${IMAKE_INSTALL} \ METALOG=${METALOG} MK_TESTS=no installconfig .endif # # buildkernel and installkernel # # Which kernels to build and/or install is specified by setting # KERNCONF. If not defined a GENERIC kernel is built/installed. # Only the existing (depending TARGET) config files are used # for building kernels and only the first of these is designated # as the one being installed. # # Note that we have to use TARGET instead of TARGET_ARCH when # we're in kernel-land. Since only TARGET_ARCH is (expected) to # be set to cross-build, we have to make sure TARGET is set # properly. .if defined(KERNFAST) NO_KERNELCLEAN= t NO_KERNELCONFIG= t NO_KERNELOBJ= t # Shortcut for KERNCONF=Blah -DKERNFAST is now KERNFAST=Blah .if !defined(KERNCONF) && ${KERNFAST} != "1" KERNCONF=${KERNFAST} .endif .endif .if ${TARGET_ARCH} == "powerpc64" KERNCONF?= GENERIC64 .else KERNCONF?= GENERIC .endif INSTKERNNAME?= kernel KERNSRCDIR?= ${.CURDIR}/sys KRNLCONFDIR= ${KERNSRCDIR}/${TARGET}/conf KRNLOBJDIR= ${OBJTOP}${KERNSRCDIR:C,^${.CURDIR},,} KERNCONFDIR?= ${KRNLCONFDIR} BUILDKERNELS= INSTALLKERNEL= .if defined(NO_INSTALLKERNEL) # All of the BUILDKERNELS loops start at index 1. BUILDKERNELS+= dummy .endif .for _kernel in ${KERNCONF} .if exists(${KERNCONFDIR}/${_kernel}) BUILDKERNELS+= ${_kernel} .if empty(INSTALLKERNEL) && !defined(NO_INSTALLKERNEL) INSTALLKERNEL= ${_kernel} .endif .else .if make(buildkernel) .error Missing KERNCONF ${KERNCONFDIR}/${_kernel} .endif .endif .endfor _cleankernobj_fast_depend_hack: .PHONY # 20180320 remove stale generated assym.s after renaming to .inc in r331254 .if exists(${OBJTOP}/sys/${KERNCONF}/assym.s) @echo Removing stale generated assym files @rm -f ${OBJTOP}/sys/${KERNCONF}/assym.* \ ${OBJTOP}/sys/${KERNCONF}/.depend.assym.* .endif ${WMAKE_TGTS:N_worldtmp:Nbuild${libcompat}} ${.ALLTARGETS:M_*:N_worldtmp}: .MAKE .PHONY # # buildkernel # # Builds all kernels defined by BUILDKERNELS. # buildkernel: .MAKE .PHONY .if empty(BUILDKERNELS:Ndummy) @echo "ERROR: Missing kernel configuration file(s) (${KERNCONF})."; \ false .endif @echo .for _kernel in ${BUILDKERNELS:Ndummy} @echo "--------------------------------------------------------------" @echo ">>> Kernel build for ${_kernel} started on `LC_ALL=C date`" @echo "--------------------------------------------------------------" @echo "===> ${_kernel}" mkdir -p ${KRNLOBJDIR} .if !defined(NO_KERNELCONFIG) @echo @echo "--------------------------------------------------------------" @echo ">>> stage 1: configuring the kernel" @echo "--------------------------------------------------------------" cd ${KRNLCONFDIR}; \ PATH=${TMPPATH} \ config ${CONFIGARGS} -d ${KRNLOBJDIR}/${_kernel} \ -I '${KERNCONFDIR}' '${KERNCONFDIR}/${_kernel}' .endif .if !defined(NO_CLEAN) && !defined(NO_KERNELCLEAN) @echo @echo "--------------------------------------------------------------" @echo ">>> stage 2.1: cleaning up the object tree" @echo "--------------------------------------------------------------" ${_+_}cd ${KRNLOBJDIR}/${_kernel}; ${KMAKE} ${CLEANDIR} .else ${_+_}cd ${.CURDIR}; ${WMAKE} _cleankernobj_fast_depend_hack .endif .if !defined(NO_KERNELOBJ) @echo @echo "--------------------------------------------------------------" @echo ">>> stage 2.2: rebuilding the object tree" @echo "--------------------------------------------------------------" ${_+_}cd ${KRNLOBJDIR}/${_kernel}; ${KMAKE} obj .endif @echo @echo "--------------------------------------------------------------" @echo ">>> stage 2.3: build tools" @echo "--------------------------------------------------------------" ${_+_}cd ${.CURDIR}; ${KTMAKE} kernel-tools @echo @echo "--------------------------------------------------------------" @echo ">>> stage 3.1: building everything" @echo "--------------------------------------------------------------" ${_+_}cd ${KRNLOBJDIR}/${_kernel}; ${KMAKE} all -DNO_MODULES_OBJ @echo "--------------------------------------------------------------" @echo ">>> Kernel build for ${_kernel} completed on `LC_ALL=C date`" @echo "--------------------------------------------------------------" .endfor NO_INSTALLEXTRAKERNELS?= yes # # installkernel, etc. # # Install the kernel defined by INSTALLKERNEL # installkernel installkernel.debug \ reinstallkernel reinstallkernel.debug: _installcheck_kernel .PHONY .if !defined(NO_INSTALLKERNEL) .if empty(INSTALLKERNEL) @echo "ERROR: No kernel \"${KERNCONF}\" to install."; \ false .endif @echo "--------------------------------------------------------------" @echo ">>> Installing kernel ${INSTALLKERNEL} on $$(LC_ALL=C date)" @echo "--------------------------------------------------------------" ${_+_}cd ${KRNLOBJDIR}/${INSTALLKERNEL}; \ ${CROSSENV} PATH=${TMPPATH} \ ${MAKE} ${IMAKE_INSTALL} KERNEL=${INSTKERNNAME} ${.TARGET:S/kernel//} @echo "--------------------------------------------------------------" @echo ">>> Installing kernel ${INSTALLKERNEL} completed on $$(LC_ALL=C date)" @echo "--------------------------------------------------------------" .endif .if ${BUILDKERNELS:[#]} > 1 && ${NO_INSTALLEXTRAKERNELS} != "yes" .for _kernel in ${BUILDKERNELS:[2..-1]} @echo "--------------------------------------------------------------" @echo ">>> Installing kernel ${_kernel} $$(LC_ALL=C date)" @echo "--------------------------------------------------------------" ${_+_}cd ${KRNLOBJDIR}/${_kernel}; \ ${CROSSENV} PATH=${TMPPATH} \ ${MAKE} ${IMAKE_INSTALL} KERNEL=${INSTKERNNAME}.${_kernel} ${.TARGET:S/kernel//} @echo "--------------------------------------------------------------" @echo ">>> Installing kernel ${_kernel} completed on $$(LC_ALL=C date)" @echo "--------------------------------------------------------------" .endfor .endif distributekernel distributekernel.debug: .PHONY .if !defined(NO_INSTALLKERNEL) .if empty(INSTALLKERNEL) @echo "ERROR: No kernel \"${KERNCONF}\" to install."; \ false .endif mkdir -p ${DESTDIR}/${DISTDIR} .if defined(NO_ROOT) @echo "#${MTREE_MAGIC}" > ${DESTDIR}/${DISTDIR}/kernel.premeta .endif ${_+_}cd ${KRNLOBJDIR}/${INSTALLKERNEL}; \ ${IMAKEENV} ${IMAKE_INSTALL:S/METALOG/kernel.premeta/} \ ${IMAKE_MTREE} PATH=${TMPPATH} ${MAKE} KERNEL=${INSTKERNNAME} \ DESTDIR=${INSTALL_DDIR}/kernel \ ${.TARGET:S/distributekernel/install/} .if defined(NO_ROOT) @sed -e 's|^./kernel|.|' ${DESTDIR}/${DISTDIR}/kernel.premeta > \ ${DESTDIR}/${DISTDIR}/kernel.meta .endif .endif .if ${BUILDKERNELS:[#]} > 1 && ${NO_INSTALLEXTRAKERNELS} != "yes" .for _kernel in ${BUILDKERNELS:[2..-1]} .if defined(NO_ROOT) @echo "#${MTREE_MAGIC}" > ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.premeta .endif ${_+_}cd ${KRNLOBJDIR}/${_kernel}; \ ${IMAKEENV} ${IMAKE_INSTALL:S/METALOG/kernel.${_kernel}.premeta/} \ ${IMAKE_MTREE} PATH=${TMPPATH} ${MAKE} \ KERNEL=${INSTKERNNAME}.${_kernel} \ DESTDIR=${INSTALL_DDIR}/kernel.${_kernel} \ ${.TARGET:S/distributekernel/install/} .if defined(NO_ROOT) @sed -e "s|^./kernel.${_kernel}|.|" \ ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.premeta > \ ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.meta .endif .endfor .endif packagekernel: .PHONY .if defined(NO_ROOT) .if !defined(NO_INSTALLKERNEL) cd ${DESTDIR}/${DISTDIR}/kernel; \ tar cvf - --exclude '*.debug' \ @${DESTDIR}/${DISTDIR}/kernel.meta | \ ${XZ_CMD} > ${PACKAGEDIR}/kernel.txz .endif .if ${MK_DEBUG_FILES} != "no" cd ${DESTDIR}/${DISTDIR}/kernel; \ tar cvf - --include '*/*/*.debug' \ @${DESTDIR}/${DISTDIR}/kernel.meta | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel-dbg.txz .endif .if ${BUILDKERNELS:[#]} > 1 && ${NO_INSTALLEXTRAKERNELS} != "yes" .for _kernel in ${BUILDKERNELS:[2..-1]} cd ${DESTDIR}/${DISTDIR}/kernel.${_kernel}; \ tar cvf - --exclude '*.debug' \ @${DESTDIR}/${DISTDIR}/kernel.${_kernel}.meta | \ ${XZ_CMD} > ${PACKAGEDIR}/kernel.${_kernel}.txz .if ${MK_DEBUG_FILES} != "no" cd ${DESTDIR}/${DISTDIR}/kernel.${_kernel}; \ tar cvf - --include '*/*/*.debug' \ @${DESTDIR}/${DISTDIR}/kernel.${_kernel}.meta | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.${_kernel}-dbg.txz .endif .endfor .endif .else .if !defined(NO_INSTALLKERNEL) cd ${DESTDIR}/${DISTDIR}/kernel; \ tar cvf - --exclude '*.debug' . | \ ${XZ_CMD} > ${PACKAGEDIR}/kernel.txz .endif .if ${MK_DEBUG_FILES} != "no" cd ${DESTDIR}/${DISTDIR}/kernel; \ tar cvf - --include '*/*/*.debug' $$(eval find .) | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel-dbg.txz .endif .if ${BUILDKERNELS:[#]} > 1 && ${NO_INSTALLEXTRAKERNELS} != "yes" .for _kernel in ${BUILDKERNELS:[2..-1]} cd ${DESTDIR}/${DISTDIR}/kernel.${_kernel}; \ tar cvf - --exclude '*.debug' . | \ ${XZ_CMD} > ${PACKAGEDIR}/kernel.${_kernel}.txz .if ${MK_DEBUG_FILES} != "no" cd ${DESTDIR}/${DISTDIR}/kernel.${_kernel}; \ tar cvf - --include '*/*/*.debug' $$(eval find .) | \ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.${_kernel}-dbg.txz .endif .endfor .endif .endif stagekernel: .PHONY ${_+_}${MAKE} -C ${.CURDIR} ${.MAKEFLAGS} distributekernel PORTSDIR?= /usr/ports WSTAGEDIR?= ${OBJTOP}/worldstage KSTAGEDIR?= ${OBJTOP}/kernelstage REPODIR?= ${OBJROOT}repo PKGSIGNKEY?= # empty .ORDER: stage-packages create-packages .ORDER: create-packages create-world-packages .ORDER: create-packages create-kernel-packages .ORDER: create-packages sign-packages _pkgbootstrap: .PHONY .if !exists(${LOCALBASE}/sbin/pkg) @env ASSUME_ALWAYS_YES=YES pkg bootstrap .endif packages: .PHONY ${_+_}${MAKE} -C ${.CURDIR} PKG_VERSION=${PKG_VERSION} real-packages package-pkg: .PHONY rm -rf /tmp/ports.${TARGET} || : env ${WMAKEENV:Q} SRCDIR=${.CURDIR} PORTSDIR=${PORTSDIR} REVISION=${_REVISION} \ PKG_CMD=${PKG_CMD} PKG_VERSION=${PKG_VERSION} REPODIR=${REPODIR} \ WSTAGEDIR=${WSTAGEDIR} \ sh ${.CURDIR}/release/scripts/make-pkg-package.sh real-packages: stage-packages create-packages sign-packages .PHONY stage-packages-world: .PHONY @mkdir -p ${WSTAGEDIR} ${_+_}@cd ${.CURDIR}; \ ${MAKE} DESTDIR=${WSTAGEDIR} -DNO_ROOT stageworld stage-packages-kernel: .PHONY @mkdir -p ${KSTAGEDIR} ${_+_}@cd ${.CURDIR}; \ ${MAKE} DESTDIR=${KSTAGEDIR} -DNO_ROOT stagekernel stage-packages: .PHONY stage-packages-world stage-packages-kernel _repodir: .PHONY @mkdir -p ${REPODIR} create-packages-world: _pkgbootstrap _repodir .PHONY ${_+_}@cd ${.CURDIR}; \ ${MAKE} -f Makefile.inc1 \ DESTDIR=${WSTAGEDIR} \ PKG_VERSION=${PKG_VERSION} create-world-packages create-packages-kernel: _pkgbootstrap _repodir .PHONY ${_+_}@cd ${.CURDIR}; \ ${MAKE} -f Makefile.inc1 \ DESTDIR=${KSTAGEDIR} \ PKG_VERSION=${PKG_VERSION} DISTDIR=kernel \ create-kernel-packages create-packages: .PHONY create-packages-world create-packages-kernel create-world-packages: _pkgbootstrap .PHONY @rm -f ${WSTAGEDIR}/*.plist 2>/dev/null || : @cd ${WSTAGEDIR} ; \ env -i LC_COLLATE=C sort ${WSTAGEDIR}/METALOG | \ awk -f ${SRCDIR}/release/scripts/mtree-to-plist.awk @for plist in ${WSTAGEDIR}/*.plist; do \ plist=$${plist##*/} ; \ pkgname=$${plist%.plist} ; \ echo "_PKGS+= $${pkgname}" ; \ done > ${WSTAGEDIR}/packages.mk ${_+_}@cd ${.CURDIR}; \ ${MAKE} -f Makefile.inc1 create-world-packages-jobs \ .MAKE.JOB.PREFIX= .if make(create-world-packages-jobs) .include "${WSTAGEDIR}/packages.mk" .endif create-world-packages-jobs: .PHONY .for pkgname in ${_PKGS} create-world-packages-jobs: create-world-package-${pkgname} create-world-package-${pkgname}: .PHONY @sh ${SRCDIR}/release/packages/generate-ucl.sh -o ${pkgname} \ -s ${SRCDIR} -u ${WSTAGEDIR}/${pkgname}.ucl @awk -F\" ' \ /^name/ { printf("===> Creating %s-", $$2); next } \ /^version/ { print $$2; next } \ ' ${WSTAGEDIR}/${pkgname}.ucl @if [ "${pkgname}" == "runtime" ]; then \ sed -i '' -e "s/%VCS_REVISION%/${VCS_REVISION}/" ${WSTAGEDIR}/${pkgname}.ucl ; \ fi ${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh -o ALLOW_BASE_SHLIBS=yes \ create -M ${WSTAGEDIR}/${pkgname}.ucl \ -p ${WSTAGEDIR}/${pkgname}.plist \ -r ${WSTAGEDIR} \ -o ${REPODIR}/$$(${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh config ABI)/${PKG_VERSION} .endfor create-kernel-packages: .PHONY _default_flavor= -default .if exists(${KSTAGEDIR}/kernel.meta) . if ${MK_DEBUG_FILES} != "no" _debug=-debug . endif . for flavor in "" ${_debug} create-kernel-packages: create-kernel-packages-flavor${flavor:C,^""$,${_default_flavor},} create-kernel-packages-flavor${flavor:C,^""$,${_default_flavor},}: _pkgbootstrap .PHONY @cd ${KSTAGEDIR}/${DISTDIR} ; \ env -i LC_COLLATE=C sort ${KSTAGEDIR}/kernel.meta | \ awk -f ${SRCDIR}/release/scripts/mtree-to-plist.awk \ -v kernel=yes -v _kernconf=${INSTALLKERNEL} ; \ cap_arg=`cd ${SRCDIR}/etc ; ${MAKE} -VCAP_MKDB_ENDIAN` ; \ pwd_arg=`cd ${SRCDIR}/etc ; ${MAKE} -VPWD_MKDB_ENDIAN` ; \ sed -e "s/%VERSION%/${PKG_VERSION}/" \ -e "s/%PKGNAME%/kernel-${INSTALLKERNEL:tl}${flavor}/" \ -e "s/%KERNELDIR%/kernel/" \ -e "s/%COMMENT%/FreeBSD ${INSTALLKERNEL} kernel ${flavor}/" \ -e "s/%DESC%/FreeBSD ${INSTALLKERNEL} kernel ${flavor}/" \ -e "s/%CAP_MKDB_ENDIAN%/$${cap_arg}/g" \ -e "s/%PWD_MKDB_ENDIAN%/$${pwd_arg}/g" \ -e "s/ %VCS_REVISION%/${VCS_REVISION}/" \ ${SRCDIR}/release/packages/kernel.ucl \ > ${KSTAGEDIR}/${DISTDIR}/kernel.${INSTALLKERNEL}${flavor}.ucl ; \ awk -F\" ' \ /name/ { printf("===> Creating %s-", $$2); next } \ /version/ {print $$2; next } ' \ ${KSTAGEDIR}/${DISTDIR}/kernel.${INSTALLKERNEL}${flavor}.ucl ; \ ${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh -o ALLOW_BASE_SHLIBS=yes \ create -M ${KSTAGEDIR}/${DISTDIR}/kernel.${INSTALLKERNEL}${flavor}.ucl \ -p ${KSTAGEDIR}/${DISTDIR}/kernel.${INSTALLKERNEL}${flavor}.plist \ -r ${KSTAGEDIR}/${DISTDIR} \ -o ${REPODIR}/$$(${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh config ABI)/${PKG_VERSION} . endfor .endif .if ${BUILDKERNELS:[#]} > 1 && ${NO_INSTALLEXTRAKERNELS} != "yes" . for _kernel in ${BUILDKERNELS:[2..-1]} . if exists(${KSTAGEDIR}/kernel.${_kernel}.meta) . if ${MK_DEBUG_FILES} != "no" _debug=-debug . endif . for flavor in "" ${_debug} create-kernel-packages: create-kernel-packages-extra-flavor${flavor:C,^""$,${_default_flavor},}-${_kernel} create-kernel-packages-extra-flavor${flavor:C,^""$,${_default_flavor},}-${_kernel}: _pkgbootstrap .PHONY @cd ${KSTAGEDIR}/kernel.${_kernel} ; \ env -i LC_COLLATE=C sort ${KSTAGEDIR}/kernel.${_kernel}.meta | \ awk -f ${SRCDIR}/release/scripts/mtree-to-plist.awk \ -v kernel=yes -v _kernconf=${_kernel} ; \ cap_arg=`cd ${SRCDIR}/etc ; ${MAKE} -VCAP_MKDB_ENDIAN` ; \ pwd_arg=`cd ${SRCDIR}/etc ; ${MAKE} -VPWD_MKDB_ENDIAN` ; \ sed -e "s/%VERSION%/${PKG_VERSION}/" \ -e "s/%PKGNAME%/kernel-${_kernel:tl}${flavor}/" \ -e "s/%KERNELDIR%/kernel.${_kernel}/" \ -e "s/%COMMENT%/FreeBSD ${_kernel} kernel ${flavor}/" \ -e "s/%DESC%/FreeBSD ${_kernel} kernel ${flavor}/" \ -e "s/%CAP_MKDB_ENDIAN%/$${cap_arg}/g" \ -e "s/%PWD_MKDB_ENDIAN%/$${pwd_arg}/g" \ -e "s/ %VCS_REVISION%/${VCS_REVISION}/" \ ${SRCDIR}/release/packages/kernel.ucl \ > ${KSTAGEDIR}/kernel.${_kernel}/kernel.${_kernel}${flavor}.ucl ; \ awk -F\" ' \ /name/ { printf("===> Creating %s-", $$2); next } \ /version/ {print $$2; next } ' \ ${KSTAGEDIR}/kernel.${_kernel}/kernel.${_kernel}${flavor}.ucl ; \ ${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh -o ALLOW_BASE_SHLIBS=yes \ create -M ${KSTAGEDIR}/kernel.${_kernel}/kernel.${_kernel}${flavor}.ucl \ -p ${KSTAGEDIR}/kernel.${_kernel}/kernel.${_kernel}${flavor}.plist \ -r ${KSTAGEDIR}/kernel.${_kernel} \ -o ${REPODIR}/$$(${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh config ABI)/${PKG_VERSION} . endfor . endif . endfor .endif sign-packages: _pkgbootstrap .PHONY @[ -L "${REPODIR}/$$(${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh config ABI)/latest" ] && \ unlink ${REPODIR}/$$(${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh config ABI)/latest ; \ ${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh repo \ -o ${REPODIR}/$$(${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh config ABI)/${PKG_VERSION} \ ${REPODIR}/$$(${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh config ABI)/${PKG_VERSION} \ ${PKGSIGNKEY} ; \ cd ${REPODIR}/$$(${PKG_CMD} -o ABI_FILE=${WSTAGEDIR}/bin/sh config ABI); \ ln -s ${PKG_VERSION} latest # # # checkworld # # Run test suite on installed world. # checkworld: .PHONY @if [ ! -x "${LOCALBASE}/bin/kyua" ]; then \ echo "You need kyua (devel/kyua) to run the test suite." | /usr/bin/fmt; \ exit 1; \ fi ${_+_}PATH="$$PATH:${LOCALBASE}/bin" kyua test -k ${TESTSBASE}/Kyuafile # # # doxygen # # Build the API documentation with doxygen # doxygen: .PHONY @if [ ! -x "${LOCALBASE}/bin/doxygen" ]; then \ echo "You need doxygen (devel/doxygen) to generate the API documentation of the kernel." | /usr/bin/fmt; \ exit 1; \ fi ${_+_}cd ${.CURDIR}/tools/kerneldoc/subsys; ${MAKE} obj all # # update # # Update the source tree(s), by running svn/svnup to update to the # latest copy. # update: .PHONY .if defined(SVN_UPDATE) @echo "--------------------------------------------------------------" @echo ">>> Updating ${.CURDIR} using Subversion" @echo "--------------------------------------------------------------" @(cd ${.CURDIR}; ${SVN_CMD} update ${SVNFLAGS}) .endif # # ------------------------------------------------------------------------ # # From here onwards are utility targets used by the 'make world' and # related targets. If your 'world' breaks, you may like to try to fix # the problem and manually run the following targets to attempt to # complete the build. Beware, this is *not* guaranteed to work, you # need to have a pretty good grip on the current state of the system # to attempt to manually finish it. If in doubt, 'make world' again. # # # legacy: Build compatibility shims for the next three targets. This is a # minimal set of tools and shims necessary to compensate for older systems # which don't have the APIs required by the targets built in bootstrap-tools, # build-tools or cross-tools. # # ELF Tool Chain libraries are needed for ELF tools and dtrace tools. # r296685 fix cross-endian objcopy # r310724 fixed PR 215350, a crash in libdwarf with objects built by GCC 6.2. .if ${BOOTSTRAPPING} < 1200020 _elftoolchain_libs= lib/libelf lib/libdwarf .endif legacy: .PHONY .if ${BOOTSTRAPPING} < ${MINIMUM_SUPPORTED_OSREL} && ${BOOTSTRAPPING} != 0 @echo "ERROR: Source upgrades from versions prior to ${MINIMUM_SUPPORTED_REL} are not supported."; \ false .endif .for _tool in tools/build ${_elftoolchain_libs} ${_+_}@${ECHODIR} "===> ${_tool} (obj,includes,all,install)"; \ cd ${.CURDIR}/${_tool}; \ if [ -z "${NO_OBJWALK}" ]; then ${MAKE} DIRPRFX=${_tool}/ obj; fi; \ ${MAKE} DIRPRFX=${_tool}/ DESTDIR=${WORLDTMP}/legacy includes; \ ${MAKE} DIRPRFX=${_tool}/ MK_INCLUDES=no all; \ ${MAKE} DIRPRFX=${_tool}/ MK_INCLUDES=no \ DESTDIR=${WORLDTMP}/legacy install .endfor # # bootstrap-tools: Build tools needed for compatibility. These are binaries that # are built to build other binaries in the system. However, the focus of these # binaries is usually quite narrow. Bootstrap tools use the host's compiler and # libraries, augmented by -legacy. # _bt= _bootstrap-tools .if ${MK_GAMES} != "no" _strfile= usr.bin/fortune/strfile .endif .if ${MK_GCC} != "no" && ${MK_CXX} != "no" _gperf= gnu/usr.bin/gperf .endif .if ${MK_VT} != "no" _vtfontcvt= usr.bin/vtfontcvt .endif .if ${BOOTSTRAPPING} < 1000033 _m4= usr.bin/m4 _lex= usr.bin/lex ${_bt}-usr.bin/m4: ${_bt}-lib/libopenbsd ${_bt}-usr.bin/lex: ${_bt}-usr.bin/m4 .endif # r245440 mtree -N support added # r313404 requires sha384.h for libnetbsd, added to libmd in r292782 .if ${BOOTSTRAPPING} < 1100093 _nmtree= lib/libmd \ lib/libnetbsd \ usr.sbin/nmtree ${_bt}-lib/libnetbsd: ${_bt}-lib/libmd ${_bt}-usr.sbin/nmtree: ${_bt}-lib/libnetbsd .endif # r246097: log addition login.conf.db, passwd, pwd.db, and spwd.db with cat -l .if ${BOOTSTRAPPING} < 1000027 _cat= bin/cat .endif # r277259 crunchide: Correct 64-bit section header offset # r281674 crunchide: always include both 32- and 64-bit ELF support .if ${BOOTSTRAPPING} < 1100078 _crunchide= usr.sbin/crunch/crunchide .endif # r285986 crunchen: use STRIPBIN rather than STRIP # 1100113: Support MK_AUTO_OBJ # 1200006: META_MODE fixes .if ${BOOTSTRAPPING} < 1100078 || \ (${MK_AUTO_OBJ} == "yes" && ${BOOTSTRAPPING} < 1100114) || \ (${MK_META_MODE} == "yes" && ${BOOTSTRAPPING} < 1200006) _crunchgen= usr.sbin/crunch/crunchgen .endif # r296926 -P keymap search path, MFC to stable/10 in r298297 .if ${BOOTSTRAPPING} < 1003501 || \ (${BOOTSTRAPPING} >= 1100000 && ${BOOTSTRAPPING} < 1100103) _kbdcontrol= usr.sbin/kbdcontrol .endif _yacc= lib/liby \ usr.bin/yacc ${_bt}-usr.bin/yacc: ${_bt}-lib/liby .if ${MK_BSNMP} != "no" _gensnmptree= usr.sbin/bsnmpd/gensnmptree .endif # We need to build tblgen when we're building clang or lld, either as # bootstrap tools, or as the part of the normal build. .if ${MK_CLANG_BOOTSTRAP} != "no" || ${MK_CLANG} != "no" || \ ${MK_LLD_BOOTSTRAP} != "no" || ${MK_LLD} != "no" _clang_tblgen= \ lib/clang/libllvmminimal \ usr.bin/clang/llvm-tblgen \ usr.bin/clang/clang-tblgen ${_bt}-usr.bin/clang/clang-tblgen: ${_bt}-lib/clang/libllvmminimal ${_bt}-usr.bin/clang/llvm-tblgen: ${_bt}-lib/clang/libllvmminimal .endif # Default to building the GPL DTC, but build the BSDL one if users explicitly # request it. _dtc= usr.bin/dtc .if ${MK_GPL_DTC} != "no" _dtc= gnu/usr.bin/dtc .endif .if ${MK_KERBEROS} != "no" _kerberos5_bootstrap_tools= \ kerberos5/tools/make-roken \ kerberos5/lib/libroken \ kerberos5/lib/libvers \ kerberos5/tools/asn1_compile \ kerberos5/tools/slc \ usr.bin/compile_et .ORDER: ${_kerberos5_bootstrap_tools:C/^/${_bt}-/g} .endif ${_bt}-usr.bin/mandoc: ${_bt}-lib/libopenbsd bootstrap-tools: .PHONY # Please document (add comment) why something is in 'bootstrap-tools'. # Try to bound the building of the bootstrap-tool to just the # FreeBSD versions that need the tool built at this stage of the build. .for _tool in \ ${_clang_tblgen} \ ${_kerberos5_bootstrap_tools} \ ${_strfile} \ ${_gperf} \ ${_dtc} \ ${_cat} \ ${_kbdcontrol} \ usr.bin/lorder \ lib/libopenbsd \ usr.bin/mandoc \ usr.bin/rpcgen \ ${_yacc} \ ${_m4} \ ${_lex} \ usr.bin/xinstall \ ${_gensnmptree} \ usr.sbin/config \ ${_crunchide} \ ${_crunchgen} \ ${_nmtree} \ ${_vtfontcvt} \ usr.bin/localedef ${_bt}-${_tool}: .PHONY .MAKE ${_+_}@${ECHODIR} "===> ${_tool} (obj,all,install)"; \ cd ${.CURDIR}/${_tool}; \ if [ -z "${NO_OBJWALK}" ]; then ${MAKE} DIRPRFX=${_tool}/ obj; fi; \ ${MAKE} DIRPRFX=${_tool}/ all; \ ${MAKE} DIRPRFX=${_tool}/ DESTDIR=${WORLDTMP}/legacy install bootstrap-tools: ${_bt}-${_tool} .endfor # # build-tools: Build special purpose build tools # .if !defined(NO_SHARE) && ${MK_SYSCONS} != "no" _share= share/syscons/scrnmaps .endif .if ${MK_GCC} != "no" _gcc_tools= gnu/usr.bin/cc/cc_tools .endif .if ${MK_RESCUE} != "no" # rescue includes programs that have build-tools targets _rescue=rescue/rescue .endif .if ${MK_TCSH} != "no" _tcsh=bin/csh .endif .if ${MK_FILE} != "no" _libmagic=lib/libmagic .endif .if ${MACHINE_CPUARCH} == "amd64" -_jevents=lib/libpmcstat/pmu-events +_jevents=lib/libpmc/pmu-events .endif # kernel-toolchain skips _cleanobj, so handle cleaning up previous # build-tools directories if needed. .if !defined(NO_CLEAN) && make(kernel-toolchain) _bt_clean= ${CLEANDIR} .endif .for _tool in \ ${_tcsh} \ bin/sh \ ${LOCAL_TOOL_DIRS} \ ${_jevents} \ lib/ncurses/ncurses \ lib/ncurses/ncursesw \ ${_rescue} \ ${_share} \ usr.bin/awk \ ${_libmagic} \ usr.bin/mkesdb_static \ usr.bin/mkcsmapper_static \ usr.bin/vi/catalog \ ${_gcc_tools} build-tools_${_tool}: .PHONY ${_+_}@${ECHODIR} "===> ${_tool} (${_bt_clean:D${_bt_clean},}obj,build-tools)"; \ cd ${.CURDIR}/${_tool}; \ if [ -n "${_bt_clean}" ]; then ${MAKE} DIRPRFX=${_tool}/ ${_bt_clean}; fi; \ if [ -z "${NO_OBJWALK}" ]; then ${MAKE} DIRPRFX=${_tool}/ obj; fi; \ ${MAKE} DIRPRFX=${_tool}/ build-tools build-tools: build-tools_${_tool} .endfor # # kernel-tools: Build kernel-building tools # kernel-tools: .PHONY mkdir -p ${WORLDTMP}/usr mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${WORLDTMP}/usr >/dev/null # # cross-tools: All the tools needed to build the rest of the system after # we get done with the earlier stages. It is the last set of tools needed # to begin building the target binaries. # .if ${TARGET_ARCH} != ${MACHINE_ARCH} .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386" _btxld= usr.sbin/btxld .endif .endif # Rebuild ctfconvert and ctfmerge to avoid difficult-to-diagnose failures # resulting from missing bug fixes or ELF Toolchain updates. .if ${MK_CDDL} != "no" _dtrace_tools= cddl/lib/libctf cddl/usr.bin/ctfconvert \ cddl/usr.bin/ctfmerge .endif # If we're given an XAS, don't build binutils. .if ${XAS:M/*} == "" .if ${MK_BINUTILS_BOOTSTRAP} != "no" _binutils= gnu/usr.bin/binutils .endif .if ${MK_ELFTOOLCHAIN_BOOTSTRAP} != "no" _elftctools= lib/libelftc \ lib/libpe \ usr.bin/elfcopy \ usr.bin/nm \ usr.bin/size \ usr.bin/strings # These are not required by the build, but can be useful for developers who # cross-build on a FreeBSD 10 host: _elftctools+= usr.bin/addr2line .endif .elif ${TARGET_ARCH} != ${MACHINE_ARCH} && ${MK_ELFTOOLCHAIN_BOOTSTRAP} != "no" # If cross-building with an external binutils we still need to build strip for # the target (for at least crunchide). _elftctools= lib/libelftc \ lib/libpe \ usr.bin/elfcopy .endif .if ${MK_CLANG_BOOTSTRAP} != "no" _clang= usr.bin/clang .endif .if ${MK_LLD_BOOTSTRAP} != "no" _lld= usr.bin/clang/lld .endif .if ${MK_CLANG_BOOTSTRAP} != "no" || ${MK_LLD_BOOTSTRAP} != "no" _clang_libs= lib/clang .endif .if ${MK_GCC_BOOTSTRAP} != "no" _gcc= gnu/usr.bin/cc .endif .if ${MK_USB} != "no" _usb_tools= stand/usb/tools .endif cross-tools: .MAKE .PHONY .for _tool in \ ${LOCAL_XTOOL_DIRS} \ ${_clang_libs} \ ${_clang} \ ${_lld} \ ${_binutils} \ ${_elftctools} \ ${_dtrace_tools} \ ${_gcc} \ ${_btxld} \ ${_usb_tools} ${_+_}@${ECHODIR} "===> ${_tool} (obj,all,install)"; \ cd ${.CURDIR}/${_tool}; \ if [ -z "${NO_OBJWALK}" ]; then ${MAKE} DIRPRFX=${_tool}/ obj; fi; \ ${MAKE} DIRPRFX=${_tool}/ all; \ ${MAKE} DIRPRFX=${_tool}/ DESTDIR=${WORLDTMP} install .endfor # # native-xtools is the current target for qemu-user cross builds of ports # via poudriere and the imgact_binmisc kernel module. # This target merely builds a toolchan/sysroot, then builds the tools it wants # with the options it wants in a special MAKEOBJDIRPREFIX, using the toolchain # already built. It then installs the static tools to NXBDESTDIR for Poudriere # to pickup. # NXBOBJROOT= ${OBJROOT}${MACHINE}.${MACHINE_ARCH}/nxb/ NXBOBJTOP= ${NXBOBJROOT}${NXB_TARGET}.${NXB_TARGET_ARCH} NXTP?= /nxb-bin .if ${NXTP:N/*} .error NXTP variable should be an absolute path .endif NXBDESTDIR?= ${DESTDIR}${NXTP} # This is the list of tools to be built/installed as static and where # appropriate to build for the given TARGET.TARGET_ARCH. NXBDIRS+= \ bin/cat \ bin/chmod \ bin/cp \ ${_tcsh} \ bin/echo \ bin/expr \ bin/hostname \ bin/ln \ bin/ls \ bin/mkdir \ bin/mv \ bin/ps \ bin/realpath \ bin/rm \ bin/rmdir \ bin/sh \ bin/sleep \ sbin/md5 \ sbin/sysctl \ usr.bin/addr2line \ usr.bin/ar \ usr.bin/awk \ usr.bin/basename \ usr.bin/bmake \ usr.bin/bzip2 \ usr.bin/cmp \ usr.bin/diff \ usr.bin/dirname \ usr.bin/elfcopy \ usr.bin/env \ usr.bin/fetch \ usr.bin/find \ usr.bin/grep \ usr.bin/gzip \ usr.bin/id \ usr.bin/lex \ usr.bin/limits \ usr.bin/lorder \ usr.bin/mandoc \ usr.bin/mktemp \ usr.bin/mt \ usr.bin/nm \ usr.bin/patch \ usr.bin/readelf \ usr.bin/sed \ usr.bin/size \ usr.bin/sort \ usr.bin/strings \ usr.bin/tar \ usr.bin/touch \ usr.bin/tr \ usr.bin/true \ usr.bin/uniq \ usr.bin/unzip \ usr.bin/xargs \ usr.bin/xinstall \ usr.bin/xz \ usr.bin/yacc \ usr.sbin/chown SUBDIR_DEPEND_usr.bin/clang= lib/clang .if ${MK_CLANG} != "no" NXBDIRS+= lib/clang NXBDIRS+= usr.bin/clang .endif .if ${MK_GCC} != "no" NXBDIRS+= gnu/usr.bin/cc .endif .if ${MK_BINUTILS} != "no" NXBDIRS+= gnu/usr.bin/binutils .endif # XXX: native-xtools passes along ${NXBDIRS} in SUBDIR_OVERRIDE that needs # to be evaluated after NXBDIRS is set. .if make(install) && !empty(SUBDIR_OVERRIDE) SUBDIR= ${SUBDIR_OVERRIDE} .endif NXBMAKEARGS+= \ OBJTOP=${NXBOBJTOP:Q} \ OBJROOT=${NXBOBJROOT:Q} \ MAKEOBJDIRPREFIX= \ -DNO_SHARED \ -DNO_CPU_CFLAGS \ -DNO_PIC \ SSP_CFLAGS= \ MK_CLANG_EXTRAS=no \ MK_CLANG_FULL=no \ MK_CTF=no \ MK_DEBUG_FILES=no \ MK_GDB=no \ MK_HTML=no \ MK_LLDB=no \ MK_MAN=no \ MK_MAN_UTILS=yes \ MK_OFED=no \ MK_OPENSSH=no \ MK_PROFILE=no \ MK_SENDMAIL=no \ MK_SVNLITE=no \ MK_TESTS=no \ MK_WARNS=no \ MK_ZFS=no .if make(native-xtools*) && \ (!defined(NXB_TARGET) || !defined(NXB_TARGET_ARCH)) .error Missing NXB_TARGET / NXB_TARGET_ARCH .endif # For 'toolchain' we want to produce native binaries that themselves generate # native binaries. NXBTMAKE= ${NXBMAKEENV} ${MAKE} ${NXBMAKEARGS:N-DNO_PIC:N-DNO_SHARED} \ TARGET=${MACHINE} TARGET_ARCH=${MACHINE_ARCH} # For 'everything' we want to produce native binaries (hence -target to # be MACHINE) that themselves generate TARGET.TARGET_ARCH binaries. # TARGET/TARGET_ARCH are still passed along from user. # # Use the toolchain we create as an external toolchain. .if ${USING_SYSTEM_COMPILER} == "yes" || ${XCC:N${CCACHE_BIN}:M/*} NXBMAKE+= XCC="${XCC}" \ XCXX="${XCXX}" \ XCPP="${XCPP}" .else NXBMAKE+= XCC="${NXBOBJTOP}/tmp/usr/bin/cc" \ XCXX="${NXBOBJTOP}/tmp/usr/bin/c++" \ XCPP="${NXBOBJTOP}/tmp/usr/bin/cpp" .endif NXBMAKE+= ${NXBMAKEENV} ${MAKE} -f Makefile.inc1 ${NXBMAKEARGS} \ TARGET=${NXB_TARGET} TARGET_ARCH=${NXB_TARGET_ARCH} \ TARGET_TRIPLE=${MACHINE_TRIPLE:Q} # NXBDIRS is improperly based on MACHINE rather than NXB_TARGET. Need to # invoke a sub-make to reevaluate MK_GCC, etc, for NXBDIRS. NXBMAKE+= SUBDIR_OVERRIDE='$${NXBDIRS:M*}' # Need to avoid the -isystem logic when using clang as an external toolchain # even if the TARGET being built for wants GCC. NXBMAKE+= WANT_COMPILER_TYPE='$${X_COMPILER_TYPE}' native-xtools: .PHONY ${_+_}cd ${.CURDIR}; ${NXBTMAKE} _cleanobj MK_GCC=yes # Build the bootstrap/host/cross tools that produce native binaries # Pass along MK_GCC=yes to ensure GCC-needed build tools are built. # We don't quite know what the NXB_TARGET wants so just build it. ${_+_}cd ${.CURDIR}; ${NXBTMAKE} kernel-toolchain MK_GCC=yes # Populate includes/libraries sysroot that produce native binaries. # This is split out from 'toolchain' above mostly so that target LLVM # libraries have a proper LLVM_DEFAULT_TARGET_TRIPLE without # polluting the cross-compiler build. The LLVM/GCC libs are skipped # here to avoid the problem but are kept in 'toolchain' so that # needed build tools are built. ${_+_}cd ${.CURDIR}; ${NXBTMAKE} _includes MK_CLANG=no MK_GCC=no ${_+_}cd ${.CURDIR}; ${NXBTMAKE} _libraries MK_CLANG=no MK_GCC=no # Clean out improper TARGET=MACHINE files ${_+_}cd ${.CURDIR}/gnu/usr.bin/cc/cc_tools; ${NXBTMAKE} cleandir .if !defined(NO_OBJWALK) ${_+_}cd ${.CURDIR}; ${NXBMAKE} _obj .endif ${_+_}cd ${.CURDIR}; ${NXBMAKE} everything @echo ">> native-xtools done. Use 'make native-xtools-install' to install to a given DESTDIR" native-xtools-install: .PHONY mkdir -p ${NXBDESTDIR}/bin ${NXBDESTDIR}/sbin ${NXBDESTDIR}/usr mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${NXBDESTDIR}/usr >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.include.dist \ -p ${NXBDESTDIR}/usr/include >/dev/null ${_+_}cd ${.CURDIR}; ${NXBMAKE} \ DESTDIR=${NXBDESTDIR} \ -DNO_ROOT \ install # # hierarchy - ensure that all the needed directories are present # hierarchy hier: .MAKE .PHONY ${_+_}cd ${.CURDIR}/etc; ${HMAKE} distrib-dirs # # libraries - build all libraries, and install them under ${DESTDIR}. # # The list of libraries with dependents (${_prebuild_libs}) and their # interdependencies (__L) are built automatically by the # ${.CURDIR}/tools/make_libdeps.sh script. # libraries: .MAKE .PHONY ${_+_}cd ${.CURDIR}; \ ${MAKE} -f Makefile.inc1 _prereq_libs; \ ${MAKE} -f Makefile.inc1 _startup_libs; \ ${MAKE} -f Makefile.inc1 _prebuild_libs; \ ${MAKE} -f Makefile.inc1 _generic_libs # # static libgcc.a prerequisite for shared libc # _prereq_libs= lib/libcompiler_rt .if ${MK_SSP} != "no" _prereq_libs+= gnu/lib/libssp/libssp_nonshared .endif # These dependencies are not automatically generated: # # gnu/lib/csu, gnu/lib/libgcc, lib/csu and lib/libc must be built before # all shared libraries for ELF. # _startup_libs= gnu/lib/csu _startup_libs+= lib/csu _startup_libs+= lib/libcompiler_rt _startup_libs+= lib/libc _startup_libs+= lib/libc_nonshared .if ${MK_LIBCPLUSPLUS} != "no" _startup_libs+= lib/libcxxrt .endif .if ${MK_LLVM_LIBUNWIND} != "no" _prereq_libs+= lib/libgcc_eh lib/libgcc_s _startup_libs+= lib/libgcc_eh lib/libgcc_s lib/libgcc_s__L: lib/libc__L lib/libgcc_s__L: lib/libc_nonshared__L .if ${MK_LIBCPLUSPLUS} != "no" lib/libcxxrt__L: lib/libgcc_s__L .endif .else # MK_LLVM_LIBUNWIND == no _prereq_libs+= gnu/lib/libgcc _startup_libs+= gnu/lib/libgcc gnu/lib/libgcc__L: lib/libc__L gnu/lib/libgcc__L: lib/libc_nonshared__L .if ${MK_LIBCPLUSPLUS} != "no" lib/libcxxrt__L: gnu/lib/libgcc__L .endif .endif _prebuild_libs= ${_kerberos5_lib_libasn1} \ ${_kerberos5_lib_libhdb} \ ${_kerberos5_lib_libheimbase} \ ${_kerberos5_lib_libheimntlm} \ ${_libsqlite3} \ ${_kerberos5_lib_libheimipcc} \ ${_kerberos5_lib_libhx509} ${_kerberos5_lib_libkrb5} \ ${_kerberos5_lib_libroken} \ ${_kerberos5_lib_libwind} \ lib/libbz2 ${_libcom_err} lib/libcrypt \ lib/libelf lib/libexpat \ lib/libfigpar \ ${_lib_libgssapi} \ lib/libkiconv lib/libkvm lib/liblzma lib/libmd lib/libnv \ ${_lib_casper} \ lib/ncurses/ncurses lib/ncurses/ncursesw \ lib/libopie lib/libpam/libpam ${_lib_libthr} \ ${_lib_libradius} lib/libsbuf lib/libtacplus \ lib/libgeom \ ${_cddl_lib_libumem} ${_cddl_lib_libnvpair} \ ${_cddl_lib_libuutil} \ ${_cddl_lib_libavl} \ ${_cddl_lib_libzfs_core} \ ${_cddl_lib_libctf} \ lib/libutil lib/libpjdlog ${_lib_libypclnt} lib/libz lib/msun \ ${_secure_lib_libcrypto} ${_lib_libldns} \ ${_secure_lib_libssh} ${_secure_lib_libssl} .if ${MK_GNUCXX} != "no" _prebuild_libs+= gnu/lib/libstdc++ gnu/lib/libsupc++ gnu/lib/libstdc++__L: lib/msun__L gnu/lib/libsupc++__L: gnu/lib/libstdc++__L .endif .if ${MK_DIALOG} != "no" _prebuild_libs+= gnu/lib/libdialog gnu/lib/libdialog__L: lib/msun__L lib/ncurses/ncursesw__L .endif .if ${MK_LIBCPLUSPLUS} != "no" _prebuild_libs+= lib/libc++ .endif lib/libgeom__L: lib/libexpat__L lib/libkvm__L: lib/libelf__L .if ${MK_LIBTHR} != "no" _lib_libthr= lib/libthr .endif .if ${MK_RADIUS_SUPPORT} != "no" _lib_libradius= lib/libradius .endif .if ${MK_OFED} != "no" # # The OFED libraries are built in four steps # as reflected below, due to interdependencies. # # NOTE: Depending on contrib/ofed/include is only needed for # the lib32 compat build. # _ofed_lib= \ contrib/ofed/include \ contrib/ofed/usr.lib/0 \ contrib/ofed/usr.lib/1 \ contrib/ofed/usr.lib/2 \ contrib/ofed/usr.lib/3 contrib/ofed/usr.lib/0__L: contrib/ofed/include__L lib/libthr__L contrib/ofed/usr.lib/1__L: contrib/ofed/usr.lib/0__L contrib/ofed/usr.lib/2__L: contrib/ofed/usr.lib/1__L contrib/ofed/usr.lib/3__L: contrib/ofed/usr.lib/2__L .endif .if ${MK_CASPER} != "no" _lib_casper= lib/libcasper .endif lib/libpjdlog__L: lib/libutil__L lib/libcasper__L: lib/libnv__L lib/liblzma__L: lib/libthr__L _generic_libs= ${_cddl_lib} gnu/lib ${_kerberos5_lib} lib ${_secure_lib} usr.bin/lex/lib ${_ofed_lib} .if ${MK_IPFILTER} != "no" _generic_libs+= sbin/ipf/libipf .endif .for _DIR in ${LOCAL_LIB_DIRS} .if ${_DIR} == ".WAIT" || (empty(_generic_libs:M${_DIR}) && exists(${.CURDIR}/${_DIR}/Makefile)) _generic_libs+= ${_DIR} .endif .endfor lib/libopie__L lib/libtacplus__L: lib/libmd__L .if ${MK_CDDL} != "no" _cddl_lib_libumem= cddl/lib/libumem _cddl_lib_libnvpair= cddl/lib/libnvpair _cddl_lib_libavl= cddl/lib/libavl _cddl_lib_libuutil= cddl/lib/libuutil .if ${MK_ZFS} != "no" _cddl_lib_libzfs_core= cddl/lib/libzfs_core cddl/lib/libzfs_core__L: cddl/lib/libnvpair__L .endif _cddl_lib_libctf= cddl/lib/libctf _cddl_lib= cddl/lib cddl/lib/libctf__L: lib/libz__L .endif # cddl/lib/libdtrace requires lib/libproc and lib/librtld_db; it's only built # on select architectures though (see cddl/lib/Makefile) .if ${MACHINE_CPUARCH} != "sparc64" _prebuild_libs+= lib/libprocstat lib/libproc lib/librtld_db lib/libprocstat__L: lib/libelf__L lib/libkvm__L lib/libutil__L lib/libproc__L: lib/libprocstat__L lib/librtld_db__L: lib/libprocstat__L .endif .if ${MK_CRYPT} != "no" .if ${MK_OPENSSL} != "no" _secure_lib_libcrypto= secure/lib/libcrypto _secure_lib_libssl= secure/lib/libssl lib/libradius__L secure/lib/libssl__L: secure/lib/libcrypto__L .if ${MK_LDNS} != "no" _lib_libldns= lib/libldns lib/libldns__L: secure/lib/libcrypto__L .endif .if ${MK_OPENSSH} != "no" _secure_lib_libssh= secure/lib/libssh secure/lib/libssh__L: lib/libz__L secure/lib/libcrypto__L lib/libcrypt__L .if ${MK_LDNS} != "no" secure/lib/libssh__L: lib/libldns__L .endif .if ${MK_GSSAPI} != "no" && ${MK_KERBEROS_SUPPORT} != "no" secure/lib/libssh__L: lib/libgssapi__L kerberos5/lib/libkrb5__L \ kerberos5/lib/libhx509__L kerberos5/lib/libasn1__L lib/libcom_err__L \ lib/libmd__L kerberos5/lib/libroken__L .endif .endif .endif _secure_lib= secure/lib .endif .if ${MK_KERBEROS} != "no" kerberos5/lib/libasn1__L: lib/libcom_err__L kerberos5/lib/libroken__L kerberos5/lib/libhdb__L: kerberos5/lib/libasn1__L lib/libcom_err__L \ kerberos5/lib/libkrb5__L kerberos5/lib/libroken__L \ kerberos5/lib/libwind__L lib/libsqlite3__L kerberos5/lib/libheimntlm__L: secure/lib/libcrypto__L kerberos5/lib/libkrb5__L \ kerberos5/lib/libroken__L lib/libcom_err__L kerberos5/lib/libhx509__L: kerberos5/lib/libasn1__L lib/libcom_err__L \ secure/lib/libcrypto__L kerberos5/lib/libroken__L kerberos5/lib/libwind__L kerberos5/lib/libkrb5__L: kerberos5/lib/libasn1__L lib/libcom_err__L \ lib/libcrypt__L secure/lib/libcrypto__L kerberos5/lib/libhx509__L \ kerberos5/lib/libroken__L kerberos5/lib/libwind__L \ kerberos5/lib/libheimbase__L kerberos5/lib/libheimipcc__L kerberos5/lib/libroken__L: lib/libcrypt__L kerberos5/lib/libwind__L: kerberos5/lib/libroken__L lib/libcom_err__L kerberos5/lib/libheimbase__L: lib/libthr__L kerberos5/lib/libheimipcc__L: kerberos5/lib/libroken__L kerberos5/lib/libheimbase__L lib/libthr__L .endif lib/libsqlite3__L: lib/libthr__L .if ${MK_GSSAPI} != "no" _lib_libgssapi= lib/libgssapi .endif .if ${MK_KERBEROS} != "no" _kerberos5_lib= kerberos5/lib _kerberos5_lib_libasn1= kerberos5/lib/libasn1 _kerberos5_lib_libhdb= kerberos5/lib/libhdb _kerberos5_lib_libheimbase= kerberos5/lib/libheimbase _kerberos5_lib_libkrb5= kerberos5/lib/libkrb5 _kerberos5_lib_libhx509= kerberos5/lib/libhx509 _kerberos5_lib_libroken= kerberos5/lib/libroken _kerberos5_lib_libheimntlm= kerberos5/lib/libheimntlm _libsqlite3= lib/libsqlite3 _kerberos5_lib_libheimipcc= kerberos5/lib/libheimipcc _kerberos5_lib_libwind= kerberos5/lib/libwind _libcom_err= lib/libcom_err .endif .if ${MK_NIS} != "no" _lib_libypclnt= lib/libypclnt .endif .if ${MK_OPENSSL} == "no" lib/libradius__L: lib/libmd__L .endif lib/libproc__L: \ ${_cddl_lib_libctf:D${_cddl_lib_libctf}__L} lib/libelf__L lib/librtld_db__L lib/libutil__L .if ${MK_CXX} != "no" .if ${MK_LIBCPLUSPLUS} != "no" lib/libproc__L: lib/libcxxrt__L .else # This implies MK_GNUCXX != "no"; see lib/libproc lib/libproc__L: gnu/lib/libsupc++__L .endif .endif .for _lib in ${_prereq_libs} ${_lib}__PL: .PHONY .MAKE .if exists(${.CURDIR}/${_lib}) ${_+_}@${ECHODIR} "===> ${_lib} (obj,all,install)"; \ cd ${.CURDIR}/${_lib}; \ if [ -z "${NO_OBJWALK}" ]; then ${MAKE} MK_TESTS=no DIRPRFX=${_lib}/ obj; fi; \ ${MAKE} MK_TESTS=no MK_PROFILE=no -DNO_PIC \ DIRPRFX=${_lib}/ all; \ ${MAKE} MK_TESTS=no MK_PROFILE=no -DNO_PIC \ DIRPRFX=${_lib}/ install .endif .endfor .for _lib in ${_startup_libs} ${_prebuild_libs} ${_generic_libs} ${_lib}__L: .PHONY .MAKE .if exists(${.CURDIR}/${_lib}) ${_+_}@${ECHODIR} "===> ${_lib} (obj,all,install)"; \ cd ${.CURDIR}/${_lib}; \ if [ -z "${NO_OBJWALK}" ]; then ${MAKE} MK_TESTS=no DIRPRFX=${_lib}/ obj; fi; \ ${MAKE} MK_TESTS=no DIRPRFX=${_lib}/ all; \ ${MAKE} MK_TESTS=no DIRPRFX=${_lib}/ install .endif .endfor _prereq_libs: ${_prereq_libs:S/$/__PL/} _startup_libs: ${_startup_libs:S/$/__L/} _prebuild_libs: ${_prebuild_libs:S/$/__L/} _generic_libs: ${_generic_libs:S/$/__L/} # Enable SUBDIR_PARALLEL when not calling 'make all', unless called from # 'everything' with _PARALLEL_SUBDIR_OK set. This is because it is unlikely # that running 'make all' from the top-level, especially with a SUBDIR_OVERRIDE # or LOCAL_DIRS set, will have a reliable build if SUBDIRs are built in # parallel. This is safe for the world stage of buildworld though since it has # already built libraries in a proper order and installed includes into # WORLDTMP. Special handling is done for SUBDIR ordering for 'install*' to # avoid trashing a system if it crashes mid-install. .if !make(all) || defined(_PARALLEL_SUBDIR_OK) SUBDIR_PARALLEL= .endif .include .if make(check-old) || make(check-old-dirs) || \ make(check-old-files) || make(check-old-libs) || \ make(delete-old) || make(delete-old-dirs) || \ make(delete-old-files) || make(delete-old-libs) # # check for / delete old files section # .include "ObsoleteFiles.inc" OLD_LIBS_MESSAGE="Please be sure no application still uses those libraries, \ else you can not start such an application. Consult UPDATING for more \ information regarding how to cope with the removal/revision bump of a \ specific library." .if !defined(BATCH_DELETE_OLD_FILES) RM_I=-i .else RM_I=-v .endif delete-old-files: .PHONY @echo ">>> Removing old files (only deletes safe to delete libs)" # Ask for every old file if the user really wants to remove it. # It's annoying, but better safe than sorry. # NB: We cannot pass the list of OLD_FILES as a parameter because the # argument list will get too long. Using .for/.endfor make "loops" will make # the Makefile parser segfault. @exec 3<&0; \ cd ${.CURDIR}; \ ${MAKE} -f ${.CURDIR}/Makefile.inc1 ${.MAKEFLAGS} ${.TARGET} \ -V OLD_FILES -V "OLD_FILES:Musr/share/*.gz:R" | xargs -n1 | \ while read file; do \ if [ -f "${DESTDIR}/$${file}" -o -L "${DESTDIR}/$${file}" ]; then \ chflags noschg "${DESTDIR}/$${file}" 2>/dev/null || true; \ rm ${RM_I} "${DESTDIR}/$${file}" <&3; \ fi; \ for ext in debug symbols; do \ if ! [ -e "${DESTDIR}/$${file}" ] && [ -f \ "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}" ]; then \ rm ${RM_I} "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}" \ <&3; \ fi; \ done; \ done # Remove catpages without corresponding manpages. @exec 3<&0; \ find ${DESTDIR}/usr/share/man/cat* ! -type d 2>/dev/null | \ sed -ep -e's:${DESTDIR}/usr/share/man/cat:${DESTDIR}/usr/share/man/man:' | \ while read catpage; do \ read manpage; \ if [ ! -e "$${manpage}" ]; then \ rm ${RM_I} $${catpage} <&3; \ fi; \ done @echo ">>> Old files removed" check-old-files: .PHONY @echo ">>> Checking for old files" @cd ${.CURDIR}; \ ${MAKE} -f ${.CURDIR}/Makefile.inc1 ${.MAKEFLAGS} ${.TARGET} \ -V OLD_FILES -V "OLD_FILES:Musr/share/*.gz:R" | xargs -n1 | \ while read file; do \ if [ -f "${DESTDIR}/$${file}" -o -L "${DESTDIR}/$${file}" ]; then \ echo "${DESTDIR}/$${file}"; \ fi; \ for ext in debug symbols; do \ if [ -f "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}" ]; then \ echo "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}"; \ fi; \ done; \ done # Check for catpages without corresponding manpages. @find ${DESTDIR}/usr/share/man/cat* ! -type d 2>/dev/null | \ sed -ep -e's:${DESTDIR}/usr/share/man/cat:${DESTDIR}/usr/share/man/man:' | \ while read catpage; do \ read manpage; \ if [ ! -e "$${manpage}" ]; then \ echo $${catpage}; \ fi; \ done delete-old-libs: .PHONY @echo ">>> Removing old libraries" @echo "${OLD_LIBS_MESSAGE}" | fmt @exec 3<&0; \ cd ${.CURDIR}; \ ${MAKE} -f ${.CURDIR}/Makefile.inc1 ${.MAKEFLAGS} ${.TARGET} \ -V OLD_LIBS | xargs -n1 | \ while read file; do \ if [ -f "${DESTDIR}/$${file}" -o -L "${DESTDIR}/$${file}" ]; then \ chflags noschg "${DESTDIR}/$${file}" 2>/dev/null || true; \ rm ${RM_I} "${DESTDIR}/$${file}" <&3; \ fi; \ for ext in debug symbols; do \ if ! [ -e "${DESTDIR}/$${file}" ] && [ -f \ "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}" ]; then \ rm ${RM_I} "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}" \ <&3; \ fi; \ done; \ done @echo ">>> Old libraries removed" check-old-libs: .PHONY @echo ">>> Checking for old libraries" @cd ${.CURDIR}; \ ${MAKE} -f ${.CURDIR}/Makefile.inc1 ${.MAKEFLAGS} ${.TARGET} \ -V OLD_LIBS | xargs -n1 | \ while read file; do \ if [ -f "${DESTDIR}/$${file}" -o -L "${DESTDIR}/$${file}" ]; then \ echo "${DESTDIR}/$${file}"; \ fi; \ for ext in debug symbols; do \ if [ -f "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}" ]; then \ echo "${DESTDIR}${DEBUGDIR}/$${file}.$${ext}"; \ fi; \ done; \ done delete-old-dirs: .PHONY @echo ">>> Removing old directories" @cd ${.CURDIR}; \ ${MAKE} -f ${.CURDIR}/Makefile.inc1 ${.MAKEFLAGS} ${.TARGET} \ -V OLD_DIRS | xargs -n1 | sort -r | \ while read dir; do \ if [ -d "${DESTDIR}/$${dir}" ]; then \ rmdir -v "${DESTDIR}/$${dir}" || true; \ elif [ -L "${DESTDIR}/$${dir}" ]; then \ echo "${DESTDIR}/$${dir} is a link, please remove everything manually."; \ fi; \ if [ -d "${DESTDIR}${DEBUGDIR}/$${dir}" ]; then \ rmdir -v "${DESTDIR}${DEBUGDIR}/$${dir}" || true; \ elif [ -L "${DESTDIR}${DEBUGDIR}/$${dir}" ]; then \ echo "${DESTDIR}${DEBUGDIR}/$${dir} is a link, please remove everything manually."; \ fi; \ done @echo ">>> Old directories removed" check-old-dirs: .PHONY @echo ">>> Checking for old directories" @cd ${.CURDIR}; \ ${MAKE} -f ${.CURDIR}/Makefile.inc1 ${.MAKEFLAGS} ${.TARGET} \ -V OLD_DIRS | xargs -n1 | \ while read dir; do \ if [ -d "${DESTDIR}/$${dir}" ]; then \ echo "${DESTDIR}/$${dir}"; \ elif [ -L "${DESTDIR}/$${dir}" ]; then \ echo "${DESTDIR}/$${dir} is a link, please remove everything manually."; \ fi; \ if [ -d "${DESTDIR}${DEBUGDIR}/$${dir}" ]; then \ echo "${DESTDIR}${DEBUGDIR}/$${dir}"; \ elif [ -L "${DESTDIR}${DEBUGDIR}/$${dir}" ]; then \ echo "${DESTDIR}${DEBUGDIR}/$${dir} is a link, please remove everything manually."; \ fi; \ done delete-old: delete-old-files delete-old-dirs .PHONY @echo "To remove old libraries run '${MAKE_CMD} delete-old-libs'." check-old: check-old-files check-old-libs check-old-dirs .PHONY @echo "To remove old files and directories run '${MAKE_CMD} delete-old'." @echo "To remove old libraries run '${MAKE_CMD} delete-old-libs'." .endif # # showconfig - show build configuration. # showconfig: .PHONY @(${MAKE} -n -f ${.CURDIR}/sys/conf/kern.opts.mk -V dummy -dg1 UPDATE_DEPENDFILE=no NO_OBJ=yes; \ ${MAKE} -n -f ${.CURDIR}/share/mk/src.opts.mk -V dummy -dg1 UPDATE_DEPENDFILE=no NO_OBJ=yes) 2>&1 | grep ^MK_ | sort -u .if !empty(KRNLOBJDIR) && !empty(KERNCONF) DTBOUTPUTPATH= ${KRNLOBJDIR}/${KERNCONF}/ .if !defined(FDT_DTS_FILE) || empty(FDT_DTS_FILE) .if exists(${KERNCONFDIR}/${KERNCONF}) FDT_DTS_FILE!= awk 'BEGIN {FS="="} /^makeoptions[[:space:]]+FDT_DTS_FILE/ {print $$2}' \ '${KERNCONFDIR}/${KERNCONF}' ; echo .endif .endif .endif .if !defined(DTBOUTPUTPATH) || !exists(${DTBOUTPUTPATH}) DTBOUTPUTPATH= ${.CURDIR} .endif # # Build 'standalone' Device Tree Blob # builddtb: .PHONY @PATH=${TMPPATH} MACHINE=${TARGET} \ ${.CURDIR}/sys/tools/fdt/make_dtb.sh ${.CURDIR}/sys \ "${FDT_DTS_FILE}" ${DTBOUTPUTPATH} ############### # cleanworld # In the following, the first 'rm' in a series will usually remove all # files and directories. If it does not, then there are probably some # files with file flags set, so this unsets them and tries the 'rm' a # second time. There are situations where this target will be cleaning # some directories via more than one method, but that duplication is # needed to correctly handle all the possible situations. Removing all # files without file flags set in the first 'rm' instance saves time, # because 'chflags' will need to operate on fewer files afterwards. # # It is expected that BW_CANONICALOBJDIR == the CANONICALOBJDIR as would be # created by bsd.obj.mk, except that we don't want to .include that file # in this makefile. We don't do a cleandir walk if MK_AUTO_OBJ is yes # since it is not possible for files to land in the wrong place. # .if make(cleanworld) BW_CANONICALOBJDIR:=${OBJTOP}/ .elif make(cleanuniverse) BW_CANONICALOBJDIR:=${OBJROOT} .if ${MK_UNIFIED_OBJDIR} == "no" .error ${.TARGETS} only supported with WITH_UNIFIED_OBJDIR enabled. .endif .endif cleanworld cleanuniverse: .PHONY .if !empty(BW_CANONICALOBJDIR) && exists(${BW_CANONICALOBJDIR}) && \ ${.CURDIR:tA} != ${BW_CANONICALOBJDIR:tA} -rm -rf ${BW_CANONICALOBJDIR}* -chflags -R 0 ${BW_CANONICALOBJDIR} rm -rf ${BW_CANONICALOBJDIR}* .endif .if make(cleanworld) && ${MK_AUTO_OBJ} == "no" && \ (empty(BW_CANONICALOBJDIR) || ${.CURDIR:tA} == ${BW_CANONICALOBJDIR:tA}) .if ${.CURDIR} == ${.OBJDIR} || ${.CURDIR}/obj == ${.OBJDIR} # To be safe in this case, fall back to a 'make cleandir' ${_+_}@cd ${.CURDIR}; ${MAKE} cleandir .endif .endif .if ${TARGET} == ${MACHINE} && ${TARGET_ARCH} == ${MACHINE_ARCH} XDEV_CPUTYPE?=${CPUTYPE} .else XDEV_CPUTYPE?=${TARGET_CPUTYPE} .endif NOFUN=-DNO_FSCHG MK_HTML=no -DNO_LINT \ MK_MAN=no MK_NLS=no MK_PROFILE=no \ MK_KERBEROS=no MK_RESCUE=no MK_TESTS=no MK_WARNS=no \ TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} \ CPUTYPE=${XDEV_CPUTYPE} XDDIR=${TARGET_ARCH}-freebsd XDTP?=/usr/${XDDIR} .if ${XDTP:N/*} .error XDTP variable should be an absolute path .endif CDBOBJROOT= ${OBJROOT}${MACHINE}.${MACHINE_ARCH}/xdev/ CDBOBJTOP= ${CDBOBJROOT}${XDDIR} CDBENV= \ INSTALL="sh ${.CURDIR}/tools/install.sh" CDENV= ${CDBENV} \ TOOLS_PREFIX=${XDTP} CDMAKEARGS= \ OBJTOP=${CDBOBJTOP:Q} \ OBJROOT=${CDBOBJROOT:Q} CD2MAKEARGS= ${CDMAKEARGS} .if ${WANT_COMPILER_TYPE} == gcc || \ (defined(X_COMPILER_TYPE) && ${X_COMPILER_TYPE} == gcc) # GCC requires -isystem and -L when using a cross-compiler. --sysroot # won't set header path and -L is used to ensure the base library path # is added before the port PREFIX library path. CD2CFLAGS+= -isystem ${XDDESTDIR}/usr/include -L${XDDESTDIR}/usr/lib # GCC requires -B to find /usr/lib/crti.o when using a cross-compiler # combined with --sysroot. CD2CFLAGS+= -B${XDDESTDIR}/usr/lib # Force using libc++ for external GCC. .if defined(X_COMPILER_TYPE) && \ ${X_COMPILER_TYPE} == gcc && ${X_COMPILER_VERSION} >= 40800 CD2CXXFLAGS+= -isystem ${XDDESTDIR}/usr/include/c++/v1 -std=c++11 \ -nostdinc++ .endif .endif CD2CFLAGS+= --sysroot=${XDDESTDIR}/ CD2ENV=${CDENV} CC="${CC} ${CD2CFLAGS}" CXX="${CXX} ${CD2CXXFLAGS} ${CD2CFLAGS}" \ CPP="${CPP} ${CD2CFLAGS}" \ MACHINE=${TARGET} MACHINE_ARCH=${TARGET_ARCH} CDTMP= ${OBJTOP}/${XDDIR}/tmp CDMAKE=${CDENV} PATH=${CDTMP}/usr/bin:${PATH} ${MAKE} ${CDMAKEARGS} ${NOFUN} CD2MAKE=${CD2ENV} PATH=${CDTMP}/usr/bin:${XDDESTDIR}/usr/bin:${PATH} \ ${MAKE} ${CD2MAKEARGS} ${NOFUN} .if ${MK_META_MODE} != "no" # Don't rebuild build-tools targets during normal build. CD2MAKE+= BUILD_TOOLS_META=.NOMETA .endif XDDESTDIR=${DESTDIR}${XDTP} .ORDER: xdev-build xdev-install xdev-links xdev: xdev-build xdev-install .PHONY .ORDER: _xb-worldtmp _xb-bootstrap-tools _xb-build-tools _xb-cross-tools xdev-build: _xb-worldtmp _xb-bootstrap-tools _xb-build-tools _xb-cross-tools .PHONY _xb-worldtmp: .PHONY mkdir -p ${CDTMP}/usr mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${CDTMP}/usr >/dev/null _xb-bootstrap-tools: .PHONY .for _tool in \ ${_clang_tblgen} \ ${_gperf} \ ${_yacc} ${_+_}@${ECHODIR} "===> ${_tool} (obj,all,install)"; \ cd ${.CURDIR}/${_tool}; \ if [ -z "${NO_OBJWALK}" ]; then ${CDMAKE} DIRPRFX=${_tool}/ obj; fi; \ ${CDMAKE} DIRPRFX=${_tool}/ all; \ ${CDMAKE} DIRPRFX=${_tool}/ DESTDIR=${CDTMP} install .endfor _xb-build-tools: .PHONY ${_+_}@cd ${.CURDIR}; \ ${CDBENV} ${MAKE} ${CDMAKEARGS} -f Makefile.inc1 ${NOFUN} build-tools XDEVDIRS= \ ${_clang_libs} \ ${_lld} \ ${_binutils} \ ${_elftctools} \ usr.bin/ar \ ${_clang} \ ${_gcc} _xb-cross-tools: .PHONY .for _tool in ${XDEVDIRS} ${_+_}@${ECHODIR} "===> xdev ${_tool} (obj,all)"; \ cd ${.CURDIR}/${_tool}; \ if [ -z "${NO_OBJWALK}" ]; then ${CDMAKE} DIRPRFX=${_tool}/ obj; fi; \ ${CDMAKE} DIRPRFX=${_tool}/ all .endfor _xi-mtree: .PHONY ${_+_}@${ECHODIR} "mtree populating ${XDDESTDIR}" mkdir -p ${XDDESTDIR} mtree -deU -f ${.CURDIR}/etc/mtree/BSD.root.dist \ -p ${XDDESTDIR} >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.usr.dist \ -p ${XDDESTDIR}/usr >/dev/null mtree -deU -f ${.CURDIR}/etc/mtree/BSD.include.dist \ -p ${XDDESTDIR}/usr/include >/dev/null .if defined(LIBCOMPAT) mtree -deU -f ${.CURDIR}/etc/mtree/BSD.lib${libcompat}.dist \ -p ${XDDESTDIR}/usr >/dev/null .endif .if ${MK_TESTS} != "no" mkdir -p ${XDDESTDIR}${TESTSBASE} mtree -deU -f ${.CURDIR}/etc/mtree/BSD.tests.dist \ -p ${XDDESTDIR}${TESTSBASE} >/dev/null .endif .ORDER: xdev-build _xi-mtree _xi-cross-tools _xi-includes _xi-libraries xdev-install: xdev-build _xi-mtree _xi-cross-tools _xi-includes _xi-libraries .PHONY _xi-cross-tools: .PHONY @echo "_xi-cross-tools" .for _tool in ${XDEVDIRS} ${_+_}@${ECHODIR} "===> xdev ${_tool} (install)"; \ cd ${.CURDIR}/${_tool}; \ ${CDMAKE} DIRPRFX=${_tool}/ install DESTDIR=${XDDESTDIR} .endfor _xi-includes: .PHONY .if !defined(NO_OBJWALK) ${_+_}cd ${.CURDIR}; ${CD2MAKE} -f Makefile.inc1 _obj \ DESTDIR=${XDDESTDIR} .endif ${_+_}cd ${.CURDIR}; ${CD2MAKE} -f Makefile.inc1 includes \ DESTDIR=${XDDESTDIR} _xi-libraries: .PHONY ${_+_}cd ${.CURDIR}; ${CD2MAKE} -f Makefile.inc1 libraries \ DESTDIR=${XDDESTDIR} xdev-links: .PHONY ${_+_}cd ${XDDESTDIR}/usr/bin; \ mkdir -p ../../../../usr/bin; \ for i in *; do \ ln -sf ../../${XDTP}/usr/bin/$$i \ ../../../../usr/bin/${XDDIR}-$$i; \ ln -sf ../../${XDTP}/usr/bin/$$i \ ../../../../usr/bin/${XDDIR}${_REVISION}-$$i; \ done diff --git a/lib/libpmc/Makefile b/lib/libpmc/Makefile index 30510f6144b0..6eb2ad6863d2 100644 --- a/lib/libpmc/Makefile +++ b/lib/libpmc/Makefile @@ -1,82 +1,104 @@ # $FreeBSD$ PACKAGE=lib${LIB} LIB= pmc -SRCS= libpmc.c pmclog.c +SRCS= libpmc.c pmclog.c libpmc_pmu_util.c INCS= pmc.h pmclog.h +CFLAGS+= -I${.CURDIR} + +.if ${MACHINE_CPUARCH} == "amd64" + +.if ${MACHINE_CPUARCH} == "aarch64" +EVENT_ARCH="arm64" +.elif ${MACHINE_CPUARCH} == "amd64" +EVENT_ARCH="x86" +.elif ${MACHINE_CPUARCH} == "powerpc" +EVENT_ARCH="powerpc" +.endif + +JEVENTS= ${BTOOLSPATH:U.}/pmu-events/jevents +# This file is built in a subdirectory so never try to rebuild +# it here due to missing meta file. +${JEVENTS}: .NOMETA + +libpmc_events.c: ${JEVENTS} + ${JEVENTS} ${EVENT_ARCH} ${.CURDIR}/pmu-events/arch libpmc_events.c +SRCS+= libpmc_events.c +.endif + MAN= pmc.3 MAN+= pmc_allocate.3 MAN+= pmc_attach.3 MAN+= pmc_capabilities.3 MAN+= pmc_configure_logfile.3 MAN+= pmc_disable.3 MAN+= pmc_event_names_of_class.3 MAN+= pmc_get_driver_stats.3 MAN+= pmc_get_msr.3 MAN+= pmc_init.3 MAN+= pmc_name_of_capability.3 MAN+= pmc_read.3 MAN+= pmc_set.3 MAN+= pmc_start.3 MAN+= pmclog.3 MAN+= pmc.soft.3 # PMC-dependent manual pages MAN+= pmc.atom.3 MAN+= pmc.atomsilvermont.3 MAN+= pmc.core.3 MAN+= pmc.core2.3 MAN+= pmc.corei7.3 MAN+= pmc.corei7uc.3 MAN+= pmc.haswell.3 MAN+= pmc.haswelluc.3 MAN+= pmc.haswellxeon.3 MAN+= pmc.iaf.3 MAN+= pmc.ivybridge.3 MAN+= pmc.ivybridgexeon.3 MAN+= pmc.k7.3 MAN+= pmc.k8.3 MAN+= pmc.mips24k.3 MAN+= pmc.octeon.3 MAN+= pmc.p4.3 MAN+= pmc.p5.3 MAN+= pmc.p6.3 MAN+= pmc.sandybridge.3 MAN+= pmc.sandybridgeuc.3 MAN+= pmc.sandybridgexeon.3 MAN+= pmc.tsc.3 MAN+= pmc.ucf.3 MAN+= pmc.westmere.3 MAN+= pmc.westmereuc.3 MAN+= pmc.xscale.3 MLINKS+= \ pmc_allocate.3 pmc_release.3 \ pmc_attach.3 pmc_detach.3 \ pmc_capabilities.3 pmc_ncpu.3 \ pmc_capabilities.3 pmc_npmc.3 \ pmc_capabilities.3 pmc_pmcinfo.3 \ pmc_capabilities.3 pmc_cpuinfo.3 \ pmc_capabilities.3 pmc_width.3 \ pmc_configure_logfile.3 pmc_flush_logfile.3 \ pmc_configure_logfile.3 pmc_writelog.3 \ pmc_disable.3 pmc_enable.3 \ pmc_name_of_capability.3 pmc_name_of_class.3 \ pmc_name_of_capability.3 pmc_name_of_cputype.3 \ pmc_name_of_capability.3 pmc_name_of_disposition.3 \ pmc_name_of_capability.3 pmc_name_of_event.3 \ pmc_name_of_capability.3 pmc_name_of_mode.3 \ pmc_name_of_capability.3 pmc_name_of_state.3 \ pmc_read.3 pmc_rw.3 \ pmc_read.3 pmc_write.3 \ pmc_start.3 pmc_stop.3 MLINKS+= \ pmclog.3 pmclog_open.3 \ pmclog.3 pmclog_close.3 \ pmclog.3 pmclog_feed.3 \ pmclog.3 pmclog_read.3 .include diff --git a/lib/libpmc/libpmc.c b/lib/libpmc/libpmc.c index 8b25768d33d1..05fd84bc0b90 100644 --- a/lib/libpmc/libpmc.c +++ b/lib/libpmc/libpmc.c @@ -1,3945 +1,3957 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2003-2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libpmcinternal.h" /* Function prototypes */ #if defined(__i386__) static int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif #if defined(__amd64__) || defined(__i386__) static int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); static int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); static int ucf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); static int ucp_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); static int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); static int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif #if defined(__i386__) static int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); static int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif #if defined(__amd64__) || defined(__i386__) static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif #if defined(__arm__) #if defined(__XSCALE__) static int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif static int armv7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif #if defined(__aarch64__) static int arm64_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif #if defined(__mips__) static int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif /* __mips__ */ static int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #if defined(__powerpc__) static int powerpc_allocate_pmc(enum pmc_event _pe, char* ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif /* __powerpc__ */ #define PMC_CALL(cmd, params) \ syscall(pmc_syscall, PMC_OP_##cmd, (params)) /* * Event aliases provide a way for the user to ask for generic events * like "cache-misses", or "instructions-retired". These aliases are * mapped to the appropriate canonical event descriptions using a * lookup table. */ struct pmc_event_alias { const char *pm_alias; const char *pm_spec; }; static const struct pmc_event_alias *pmc_mdep_event_aliases; /* * The pmc_event_descr structure maps symbolic names known to the user * to integer codes used by the PMC KLD. */ struct pmc_event_descr { const char *pm_ev_name; enum pmc_event pm_ev_code; }; /* * The pmc_class_descr structure maps class name prefixes for * event names to event tables and other PMC class data. */ struct pmc_class_descr { const char *pm_evc_name; size_t pm_evc_name_size; enum pmc_class pm_evc_class; const struct pmc_event_descr *pm_evc_event_table; size_t pm_evc_event_table_size; int (*pm_evc_allocate_pmc)(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pa); }; #define PMC_TABLE_SIZE(N) (sizeof(N)/sizeof(N[0])) #define PMC_EVENT_TABLE_SIZE(N) PMC_TABLE_SIZE(N##_event_table) #undef __PMC_EV #define __PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N }, /* * PMC_CLASSDEP_TABLE(NAME, CLASS) * * Define a table mapping event names and aliases to HWPMC event IDs. */ #define PMC_CLASSDEP_TABLE(N, C) \ static const struct pmc_event_descr N##_event_table[] = \ { \ __PMC_EV_##C() \ } PMC_CLASSDEP_TABLE(iaf, IAF); PMC_CLASSDEP_TABLE(k7, K7); PMC_CLASSDEP_TABLE(k8, K8); PMC_CLASSDEP_TABLE(p4, P4); PMC_CLASSDEP_TABLE(p5, P5); PMC_CLASSDEP_TABLE(p6, P6); PMC_CLASSDEP_TABLE(xscale, XSCALE); PMC_CLASSDEP_TABLE(armv7, ARMV7); PMC_CLASSDEP_TABLE(armv8, ARMV8); PMC_CLASSDEP_TABLE(mips24k, MIPS24K); PMC_CLASSDEP_TABLE(mips74k, MIPS74K); PMC_CLASSDEP_TABLE(octeon, OCTEON); PMC_CLASSDEP_TABLE(ucf, UCF); PMC_CLASSDEP_TABLE(ppc7450, PPC7450); PMC_CLASSDEP_TABLE(ppc970, PPC970); PMC_CLASSDEP_TABLE(e500, E500); static struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT]; #undef __PMC_EV_ALIAS #define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE }, static const struct pmc_event_descr atom_event_table[] = { __PMC_EV_ALIAS_ATOM() }; static const struct pmc_event_descr atom_silvermont_event_table[] = { __PMC_EV_ALIAS_ATOM_SILVERMONT() }; static const struct pmc_event_descr core_event_table[] = { __PMC_EV_ALIAS_CORE() }; static const struct pmc_event_descr core2_event_table[] = { __PMC_EV_ALIAS_CORE2() }; static const struct pmc_event_descr corei7_event_table[] = { __PMC_EV_ALIAS_COREI7() }; static const struct pmc_event_descr nehalem_ex_event_table[] = { __PMC_EV_ALIAS_COREI7() }; static const struct pmc_event_descr haswell_event_table[] = { __PMC_EV_ALIAS_HASWELL() }; static const struct pmc_event_descr haswell_xeon_event_table[] = { __PMC_EV_ALIAS_HASWELL_XEON() }; static const struct pmc_event_descr broadwell_event_table[] = { __PMC_EV_ALIAS_BROADWELL() }; static const struct pmc_event_descr broadwell_xeon_event_table[] = { __PMC_EV_ALIAS_BROADWELL_XEON() }; static const struct pmc_event_descr skylake_event_table[] = { __PMC_EV_ALIAS_SKYLAKE() }; static const struct pmc_event_descr skylake_xeon_event_table[] = { __PMC_EV_ALIAS_SKYLAKE_XEON() }; static const struct pmc_event_descr ivybridge_event_table[] = { __PMC_EV_ALIAS_IVYBRIDGE() }; static const struct pmc_event_descr ivybridge_xeon_event_table[] = { __PMC_EV_ALIAS_IVYBRIDGE_XEON() }; static const struct pmc_event_descr sandybridge_event_table[] = { __PMC_EV_ALIAS_SANDYBRIDGE() }; static const struct pmc_event_descr sandybridge_xeon_event_table[] = { __PMC_EV_ALIAS_SANDYBRIDGE_XEON() }; static const struct pmc_event_descr westmere_event_table[] = { __PMC_EV_ALIAS_WESTMERE() }; static const struct pmc_event_descr westmere_ex_event_table[] = { __PMC_EV_ALIAS_WESTMERE() }; static const struct pmc_event_descr corei7uc_event_table[] = { __PMC_EV_ALIAS_COREI7UC() }; static const struct pmc_event_descr haswelluc_event_table[] = { __PMC_EV_ALIAS_HASWELLUC() }; static const struct pmc_event_descr broadwelluc_event_table[] = { __PMC_EV_ALIAS_BROADWELLUC() }; static const struct pmc_event_descr sandybridgeuc_event_table[] = { __PMC_EV_ALIAS_SANDYBRIDGEUC() }; static const struct pmc_event_descr westmereuc_event_table[] = { __PMC_EV_ALIAS_WESTMEREUC() }; static const struct pmc_event_descr cortex_a8_event_table[] = { __PMC_EV_ALIAS_ARMV7_CORTEX_A8() }; static const struct pmc_event_descr cortex_a9_event_table[] = { __PMC_EV_ALIAS_ARMV7_CORTEX_A9() }; static const struct pmc_event_descr cortex_a53_event_table[] = { __PMC_EV_ALIAS_ARMV8_CORTEX_A53() }; static const struct pmc_event_descr cortex_a57_event_table[] = { __PMC_EV_ALIAS_ARMV8_CORTEX_A57() }; /* * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) * * Map a CPU to the PMC classes it supports. */ #define PMC_MDEP_TABLE(N,C,...) \ static const enum pmc_class N##_pmc_classes[] = { \ PMC_CLASS_##C, __VA_ARGS__ \ } PMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); PMC_MDEP_TABLE(atom_silvermont, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); PMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC); PMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); PMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); PMC_MDEP_TABLE(nehalem_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); PMC_MDEP_TABLE(haswell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); PMC_MDEP_TABLE(haswell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); PMC_MDEP_TABLE(broadwell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); PMC_MDEP_TABLE(broadwell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); PMC_MDEP_TABLE(skylake, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); PMC_MDEP_TABLE(skylake_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); PMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); PMC_MDEP_TABLE(ivybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); PMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); PMC_MDEP_TABLE(sandybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); PMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); PMC_MDEP_TABLE(westmere_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); PMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC); PMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC); PMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC); PMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC); PMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC); PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE); PMC_MDEP_TABLE(cortex_a8, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7); PMC_MDEP_TABLE(cortex_a9, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7); PMC_MDEP_TABLE(cortex_a53, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8); PMC_MDEP_TABLE(cortex_a57, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8); PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K); PMC_MDEP_TABLE(mips74k, MIPS74K, PMC_CLASS_SOFT, PMC_CLASS_MIPS74K); PMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON); PMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450, PMC_CLASS_TSC); PMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970, PMC_CLASS_TSC); PMC_MDEP_TABLE(e500, E500, PMC_CLASS_SOFT, PMC_CLASS_E500, PMC_CLASS_TSC); PMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT); static const struct pmc_event_descr tsc_event_table[] = { __PMC_EV_TSC() }; #undef PMC_CLASS_TABLE_DESC #define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ static const struct pmc_class_descr NAME##_class_table_descr = \ { \ .pm_evc_name = #CLASS "-", \ .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ .pm_evc_class = PMC_CLASS_##CLASS , \ .pm_evc_event_table = EVENTS##_event_table , \ .pm_evc_event_table_size = \ PMC_EVENT_TABLE_SIZE(EVENTS), \ .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ } #if defined(__i386__) || defined(__amd64__) PMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); PMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); PMC_CLASS_TABLE_DESC(atom_silvermont, IAP, atom_silvermont, iap); PMC_CLASS_TABLE_DESC(core, IAP, core, iap); PMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); PMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); PMC_CLASS_TABLE_DESC(nehalem_ex, IAP, nehalem_ex, iap); PMC_CLASS_TABLE_DESC(haswell, IAP, haswell, iap); PMC_CLASS_TABLE_DESC(haswell_xeon, IAP, haswell_xeon, iap); PMC_CLASS_TABLE_DESC(broadwell, IAP, broadwell, iap); PMC_CLASS_TABLE_DESC(broadwell_xeon, IAP, broadwell_xeon, iap); PMC_CLASS_TABLE_DESC(skylake, IAP, skylake, iap); PMC_CLASS_TABLE_DESC(skylake_xeon, IAP, skylake_xeon, iap); PMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap); PMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap); PMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap); PMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap); PMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap); PMC_CLASS_TABLE_DESC(westmere_ex, IAP, westmere_ex, iap); PMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf); PMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp); PMC_CLASS_TABLE_DESC(haswelluc, UCP, haswelluc, ucp); PMC_CLASS_TABLE_DESC(broadwelluc, UCP, broadwelluc, ucp); PMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp); PMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp); #endif #if defined(__i386__) PMC_CLASS_TABLE_DESC(k7, K7, k7, k7); #endif #if defined(__i386__) || defined(__amd64__) PMC_CLASS_TABLE_DESC(k8, K8, k8, k8); PMC_CLASS_TABLE_DESC(p4, P4, p4, p4); #endif #if defined(__i386__) PMC_CLASS_TABLE_DESC(p5, P5, p5, p5); PMC_CLASS_TABLE_DESC(p6, P6, p6, p6); #endif #if defined(__i386__) || defined(__amd64__) PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); #endif #if defined(__arm__) #if defined(__XSCALE__) PMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); #endif PMC_CLASS_TABLE_DESC(cortex_a8, ARMV7, cortex_a8, armv7); PMC_CLASS_TABLE_DESC(cortex_a9, ARMV7, cortex_a9, armv7); #endif #if defined(__aarch64__) PMC_CLASS_TABLE_DESC(cortex_a53, ARMV8, cortex_a53, arm64); PMC_CLASS_TABLE_DESC(cortex_a57, ARMV8, cortex_a57, arm64); #endif #if defined(__mips__) PMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips); PMC_CLASS_TABLE_DESC(mips74k, MIPS74K, mips74k, mips); PMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips); #endif /* __mips__ */ #if defined(__powerpc__) PMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc); PMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc); PMC_CLASS_TABLE_DESC(e500, E500, e500, powerpc); #endif static struct pmc_class_descr soft_class_table_descr = { .pm_evc_name = "SOFT-", .pm_evc_name_size = sizeof("SOFT-") - 1, .pm_evc_class = PMC_CLASS_SOFT, .pm_evc_event_table = NULL, .pm_evc_event_table_size = 0, .pm_evc_allocate_pmc = soft_allocate_pmc }; #undef PMC_CLASS_TABLE_DESC static const struct pmc_class_descr **pmc_class_table; #define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass static const enum pmc_class *pmc_mdep_class_list; static size_t pmc_mdep_class_list_size; /* * Mapping tables, mapping enumeration values to human readable * strings. */ static const char * pmc_capability_names[] = { #undef __PMC_CAP #define __PMC_CAP(N,V,D) #N , __PMC_CAPS() }; struct pmc_class_map { enum pmc_class pm_class; const char *pm_name; }; static const struct pmc_class_map pmc_class_names[] = { #undef __PMC_CLASS #define __PMC_CLASS(S,V,D) { .pm_class = PMC_CLASS_##S, .pm_name = #S } , __PMC_CLASSES() }; struct pmc_cputype_map { enum pmc_cputype pm_cputype; const char *pm_name; }; static const struct pmc_cputype_map pmc_cputype_names[] = { #undef __PMC_CPU #define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , __PMC_CPUS() }; static const char * pmc_disposition_names[] = { #undef __PMC_DISP #define __PMC_DISP(D) #D , __PMC_DISPOSITIONS() }; static const char * pmc_mode_names[] = { #undef __PMC_MODE #define __PMC_MODE(M,N) #M , __PMC_MODES() }; static const char * pmc_state_names[] = { #undef __PMC_STATE #define __PMC_STATE(S) #S , __PMC_STATES() }; /* * Filled in by pmc_init(). */ static int pmc_syscall = -1; static struct pmc_cpuinfo cpu_info; static struct pmc_op_getdyneventinfo soft_event_info; /* Event masks for events */ struct pmc_masks { const char *pm_name; const uint64_t pm_value; }; #define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } #define NULLMASK { .pm_name = NULL } #if defined(__amd64__) || defined(__i386__) static int pmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask) { const struct pmc_masks *pm; char *q, *r; int c; if (pmask == NULL) /* no mask keywords */ return (-1); q = strchr(p, '='); /* skip '=' */ if (*++q == '\0') /* no more data */ return (-1); c = 0; /* count of mask keywords seen */ while ((r = strsep(&q, "+")) != NULL) { for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); pm++) ; if (pm->pm_name == NULL) /* not found */ return (-1); *evmask |= pm->pm_value; c++; } return (c); } #endif #define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) #define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) #define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } #if defined(__i386__) /* * AMD K7 (Athlon) CPUs. */ static struct pmc_event_alias k7_aliases[] = { EV_ALIAS("branches", "k7-retired-branches"), EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), EV_ALIAS("cycles", "tsc"), EV_ALIAS("dc-misses", "k7-dc-misses"), EV_ALIAS("ic-misses", "k7-ic-misses"), EV_ALIAS("instructions", "k7-retired-instructions"), EV_ALIAS("interrupts", "k7-hardware-interrupts"), EV_ALIAS(NULL, NULL) }; #define K7_KW_COUNT "count" #define K7_KW_EDGE "edge" #define K7_KW_INV "inv" #define K7_KW_OS "os" #define K7_KW_UNITMASK "unitmask" #define K7_KW_USR "usr" static int k7_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { char *e, *p, *q; int c, has_unitmask; uint32_t count, unitmask; pmc_config->pm_md.pm_amd.pm_amd_config = 0; pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || pe == PMC_EV_K7_DC_WRITEBACKS) { has_unitmask = 1; unitmask = AMD_PMC_UNITMASK_MOESI; } else unitmask = has_unitmask = 0; while ((p = strsep(&ctrspec, ",")) != NULL) { if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') return (-1); pmc_config->pm_caps |= PMC_CAP_THRESHOLD; pmc_config->pm_md.pm_amd.pm_amd_config |= AMD_PMC_TO_COUNTER(count); } else if (KWMATCH(p, K7_KW_EDGE)) { pmc_config->pm_caps |= PMC_CAP_EDGE; } else if (KWMATCH(p, K7_KW_INV)) { pmc_config->pm_caps |= PMC_CAP_INVERT; } else if (KWMATCH(p, K7_KW_OS)) { pmc_config->pm_caps |= PMC_CAP_SYSTEM; } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { if (has_unitmask == 0) return (-1); unitmask = 0; q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ return (-1); while ((c = tolower(*q++)) != 0) if (c == 'm') unitmask |= AMD_PMC_UNITMASK_M; else if (c == 'o') unitmask |= AMD_PMC_UNITMASK_O; else if (c == 'e') unitmask |= AMD_PMC_UNITMASK_E; else if (c == 's') unitmask |= AMD_PMC_UNITMASK_S; else if (c == 'i') unitmask |= AMD_PMC_UNITMASK_I; else if (c == '+') continue; else return (-1); if (unitmask == 0) return (-1); } else if (KWMATCH(p, K7_KW_USR)) { pmc_config->pm_caps |= PMC_CAP_USER; } else return (-1); } if (has_unitmask) { pmc_config->pm_caps |= PMC_CAP_QUALIFIER; pmc_config->pm_md.pm_amd.pm_amd_config |= AMD_PMC_TO_UNITMASK(unitmask); } return (0); } #endif #if defined(__amd64__) || defined(__i386__) /* * Intel Core (Family 6, Model E) PMCs. */ static struct pmc_event_alias core_aliases[] = { EV_ALIAS("branches", "iap-br-instr-ret"), EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), EV_ALIAS("cycles", "tsc-tsc"), EV_ALIAS("ic-misses", "iap-icache-misses"), EV_ALIAS("instructions", "iap-instr-ret"), EV_ALIAS("interrupts", "iap-core-hw-int-rx"), EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), EV_ALIAS(NULL, NULL) }; /* * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) * and Atom (Family 6, model 1CH) PMCs. * * We map aliases to events on the fixed-function counters if these * are present. Note that not all CPUs in this family contain fixed-function * counters. */ static struct pmc_event_alias core2_aliases[] = { EV_ALIAS("branches", "iap-br-inst-retired.any"), EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), EV_ALIAS("cycles", "tsc-tsc"), EV_ALIAS("ic-misses", "iap-l1i-misses"), EV_ALIAS("instructions", "iaf-instr-retired.any"), EV_ALIAS("interrupts", "iap-hw-int-rcv"), EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), EV_ALIAS(NULL, NULL) }; static struct pmc_event_alias core2_aliases_without_iaf[] = { EV_ALIAS("branches", "iap-br-inst-retired.any"), EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), EV_ALIAS("cycles", "tsc-tsc"), EV_ALIAS("ic-misses", "iap-l1i-misses"), EV_ALIAS("instructions", "iap-inst-retired.any_p"), EV_ALIAS("interrupts", "iap-hw-int-rcv"), EV_ALIAS("unhalted-cycles", "iap-cpu-clk-unhalted.core_p"), EV_ALIAS(NULL, NULL) }; #define atom_aliases core2_aliases #define atom_aliases_without_iaf core2_aliases_without_iaf #define atom_silvermont_aliases core2_aliases #define atom_silvermont_aliases_without_iaf core2_aliases_without_iaf #define corei7_aliases core2_aliases #define corei7_aliases_without_iaf core2_aliases_without_iaf #define nehalem_ex_aliases core2_aliases #define nehalem_ex_aliases_without_iaf core2_aliases_without_iaf #define haswell_aliases core2_aliases #define haswell_aliases_without_iaf core2_aliases_without_iaf #define haswell_xeon_aliases core2_aliases #define haswell_xeon_aliases_without_iaf core2_aliases_without_iaf #define broadwell_aliases core2_aliases #define broadwell_aliases_without_iaf core2_aliases_without_iaf #define broadwell_xeon_aliases core2_aliases #define broadwell_xeon_aliases_without_iaf core2_aliases_without_iaf #define skylake_aliases core2_aliases #define skylake_aliases_without_iaf core2_aliases_without_iaf #define skylake_xeon_aliases core2_aliases #define skylake_xeon_aliases_without_iaf core2_aliases_without_iaf #define ivybridge_aliases core2_aliases #define ivybridge_aliases_without_iaf core2_aliases_without_iaf #define ivybridge_xeon_aliases core2_aliases #define ivybridge_xeon_aliases_without_iaf core2_aliases_without_iaf #define sandybridge_aliases core2_aliases #define sandybridge_aliases_without_iaf core2_aliases_without_iaf #define sandybridge_xeon_aliases core2_aliases #define sandybridge_xeon_aliases_without_iaf core2_aliases_without_iaf #define westmere_aliases core2_aliases #define westmere_aliases_without_iaf core2_aliases_without_iaf #define westmere_ex_aliases core2_aliases #define westmere_ex_aliases_without_iaf core2_aliases_without_iaf #define IAF_KW_OS "os" #define IAF_KW_USR "usr" #define IAF_KW_ANYTHREAD "anythread" /* * Parse an event specifier for Intel fixed function counters. */ static int iaf_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { char *p; (void) pe; pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; while ((p = strsep(&ctrspec, ",")) != NULL) { if (KWMATCH(p, IAF_KW_OS)) pmc_config->pm_caps |= PMC_CAP_SYSTEM; else if (KWMATCH(p, IAF_KW_USR)) pmc_config->pm_caps |= PMC_CAP_USER; else if (KWMATCH(p, IAF_KW_ANYTHREAD)) pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; else return (-1); } return (0); } /* * Core/Core2 support. */ #define IAP_KW_AGENT "agent" #define IAP_KW_ANYTHREAD "anythread" #define IAP_KW_CACHESTATE "cachestate" #define IAP_KW_CMASK "cmask" #define IAP_KW_CORE "core" #define IAP_KW_EDGE "edge" #define IAP_KW_INV "inv" #define IAP_KW_OS "os" #define IAP_KW_PREFETCH "prefetch" #define IAP_KW_SNOOPRESPONSE "snoopresponse" #define IAP_KW_SNOOPTYPE "snooptype" #define IAP_KW_TRANSITION "trans" #define IAP_KW_USR "usr" #define IAP_KW_RSP "rsp" static struct pmc_masks iap_core_mask[] = { PMCMASK(all, (0x3 << 14)), PMCMASK(this, (0x1 << 14)), NULLMASK }; static struct pmc_masks iap_agent_mask[] = { PMCMASK(this, 0), PMCMASK(any, (0x1 << 13)), NULLMASK }; static struct pmc_masks iap_prefetch_mask[] = { PMCMASK(both, (0x3 << 12)), PMCMASK(only, (0x1 << 12)), PMCMASK(exclude, 0), NULLMASK }; static struct pmc_masks iap_cachestate_mask[] = { PMCMASK(i, (1 << 8)), PMCMASK(s, (1 << 9)), PMCMASK(e, (1 << 10)), PMCMASK(m, (1 << 11)), NULLMASK }; static struct pmc_masks iap_snoopresponse_mask[] = { PMCMASK(clean, (1 << 8)), PMCMASK(hit, (1 << 9)), PMCMASK(hitm, (1 << 11)), NULLMASK }; static struct pmc_masks iap_snooptype_mask[] = { PMCMASK(cmp2s, (1 << 8)), PMCMASK(cmp2i, (1 << 9)), NULLMASK }; static struct pmc_masks iap_transition_mask[] = { PMCMASK(any, 0x00), PMCMASK(frequency, 0x10), NULLMASK }; static struct pmc_masks iap_rsp_mask_i7_wm[] = { PMCMASK(DMND_DATA_RD, (1 << 0)), PMCMASK(DMND_RFO, (1 << 1)), PMCMASK(DMND_IFETCH, (1 << 2)), PMCMASK(WB, (1 << 3)), PMCMASK(PF_DATA_RD, (1 << 4)), PMCMASK(PF_RFO, (1 << 5)), PMCMASK(PF_IFETCH, (1 << 6)), PMCMASK(OTHER, (1 << 7)), PMCMASK(UNCORE_HIT, (1 << 8)), PMCMASK(OTHER_CORE_HIT_SNP, (1 << 9)), PMCMASK(OTHER_CORE_HITM, (1 << 10)), PMCMASK(REMOTE_CACHE_FWD, (1 << 12)), PMCMASK(REMOTE_DRAM, (1 << 13)), PMCMASK(LOCAL_DRAM, (1 << 14)), PMCMASK(NON_DRAM, (1 << 15)), NULLMASK }; static struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = { PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), PMCMASK(REQ_DMND_RFO, (1ULL << 1)), PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), PMCMASK(REQ_WB, (1ULL << 3)), PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), PMCMASK(REQ_PF_RFO, (1ULL << 5)), PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), PMCMASK(REQ_PF_LLC_DATA_RD, (1ULL << 7)), PMCMASK(REQ_PF_LLC_RFO, (1ULL << 8)), PMCMASK(REQ_PF_LLC_IFETCH, (1ULL << 9)), PMCMASK(REQ_BUS_LOCKS, (1ULL << 10)), PMCMASK(REQ_STRM_ST, (1ULL << 11)), PMCMASK(REQ_OTHER, (1ULL << 15)), PMCMASK(RES_ANY, (1ULL << 16)), PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), PMCMASK(RES_NON_DRAM, (1ULL << 37)), NULLMASK }; /* Broadwell is defined to use the same mask as Haswell */ static struct pmc_masks iap_rsp_mask_haswell[] = { PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), PMCMASK(REQ_DMND_RFO, (1ULL << 1)), PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), PMCMASK(REQ_PF_RFO, (1ULL << 5)), PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), PMCMASK(REQ_OTHER, (1ULL << 15)), PMCMASK(RES_ANY, (1ULL << 16)), PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), /* * For processor type 06_45H 22 is L4_HIT_LOCAL_L4 * and 23, 24 and 25 are also defined. */ PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), PMCMASK(RES_NON_DRAM, (1ULL << 37)), NULLMASK }; static struct pmc_masks iap_rsp_mask_skylake[] = { PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), PMCMASK(REQ_DMND_RFO, (1ULL << 1)), PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), PMCMASK(REQ_PF_DATA_RD, (1ULL << 7)), PMCMASK(REQ_PF_RFO, (1ULL << 8)), PMCMASK(REQ_STRM_ST, (1ULL << 11)), PMCMASK(REQ_OTHER, (1ULL << 15)), PMCMASK(RES_ANY, (1ULL << 16)), PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), PMCMASK(RES_SUPPLIER_L4_HIT, (1ULL << 22)), PMCMASK(RES_SUPPLIER_DRAM, (1ULL << 26)), PMCMASK(RES_SUPPLIER_SPL_HIT, (1ULL << 30)), PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), PMCMASK(RES_NON_DRAM, (1ULL << 37)), NULLMASK }; static int iap_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { char *e, *p, *q; uint64_t cachestate, evmask, rsp; int count, n; pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | PMC_CAP_QUALIFIER); pmc_config->pm_md.pm_iap.pm_iap_config = 0; cachestate = evmask = rsp = 0; /* Parse additional modifiers if present */ while ((p = strsep(&ctrspec, ",")) != NULL) { n = 0; if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') return (-1); pmc_config->pm_caps |= PMC_CAP_THRESHOLD; pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_CMASK(count); } else if (KWMATCH(p, IAP_KW_EDGE)) { pmc_config->pm_caps |= PMC_CAP_EDGE; } else if (KWMATCH(p, IAP_KW_INV)) { pmc_config->pm_caps |= PMC_CAP_INVERT; } else if (KWMATCH(p, IAP_KW_OS)) { pmc_config->pm_caps |= PMC_CAP_SYSTEM; } else if (KWMATCH(p, IAP_KW_USR)) { pmc_config->pm_caps |= PMC_CAP_USER; } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; } else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) { n = pmc_parse_mask(iap_core_mask, p, &evmask); if (n != 1) return (-1); } else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) { n = pmc_parse_mask(iap_agent_mask, p, &evmask); if (n != 1) return (-1); } else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) { n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); if (n != 1) return (-1); } else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) { n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) { n = pmc_parse_mask(iap_transition_mask, p, &evmask); if (n != 1) return (-1); } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM_SILVERMONT || cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) { if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) { n = pmc_parse_mask(iap_snoopresponse_mask, p, &evmask); } else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) { n = pmc_parse_mask(iap_snooptype_mask, p, &evmask); } else return (-1); } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 || cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE || cpu_info.pm_cputype == PMC_CPU_INTEL_NEHALEM_EX || cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE_EX) { if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp); } else return (-1); } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE || cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON || cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE || cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON ) { if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp); } else return (-1); } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL || cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL_XEON) { if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp); } else return (-1); } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_BROADWELL || cpu_info.pm_cputype == PMC_CPU_INTEL_BROADWELL_XEON) { /* Broadwell is defined to use same mask as haswell */ if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp); } else return (-1); } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SKYLAKE || cpu_info.pm_cputype == PMC_CPU_INTEL_SKYLAKE_XEON) { if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { n = pmc_parse_mask(iap_rsp_mask_skylake, p, &rsp); } else return (-1); } else return (-1); if (n < 0) /* Parsing failed. */ return (-1); } pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; /* * If the event requires a 'cachestate' qualifier but was not * specified by the user, use a sensible default. */ switch (pe) { case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ case PMC_EV_IAP_EVENT_32H: /* Core */ case PMC_EV_IAP_EVENT_40H: /* Core */ case PMC_EV_IAP_EVENT_41H: /* Core */ case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ if (cachestate == 0) cachestate = (0xF << 8); break; case PMC_EV_IAP_EVENT_77H: /* Atom */ /* IAP_EVENT_77H only accepts a cachestate qualifier on the * Atom processor */ if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0) cachestate = (0xF << 8); break; default: break; } pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp; return (0); } /* * Intel Uncore. */ static int ucf_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { (void) pe; (void) ctrspec; pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0; return (0); } #define UCP_KW_CMASK "cmask" #define UCP_KW_EDGE "edge" #define UCP_KW_INV "inv" static int ucp_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { char *e, *p, *q; int count, n; (void) pe; pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | PMC_CAP_QUALIFIER); pmc_config->pm_md.pm_ucp.pm_ucp_config = 0; /* Parse additional modifiers if present */ while ((p = strsep(&ctrspec, ",")) != NULL) { n = 0; if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) { q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') return (-1); pmc_config->pm_caps |= PMC_CAP_THRESHOLD; pmc_config->pm_md.pm_ucp.pm_ucp_config |= UCP_CMASK(count); } else if (KWMATCH(p, UCP_KW_EDGE)) { pmc_config->pm_caps |= PMC_CAP_EDGE; } else if (KWMATCH(p, UCP_KW_INV)) { pmc_config->pm_caps |= PMC_CAP_INVERT; } else return (-1); if (n < 0) /* Parsing failed. */ return (-1); } return (0); } /* * AMD K8 PMCs. * * These are very similar to AMD K7 PMCs, but support more kinds of * events. */ static struct pmc_event_alias k8_aliases[] = { EV_ALIAS("branches", "k8-fr-retired-taken-branches"), EV_ALIAS("branch-mispredicts", "k8-fr-retired-taken-branches-mispredicted"), EV_ALIAS("cycles", "tsc"), EV_ALIAS("dc-misses", "k8-dc-miss"), EV_ALIAS("ic-misses", "k8-ic-miss"), EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), EV_ALIAS(NULL, NULL) }; #define __K8MASK(N,V) PMCMASK(N,(1 << (V))) /* * Parsing tables */ /* fp dispatched fpu ops */ static const struct pmc_masks k8_mask_fdfo[] = { __K8MASK(add-pipe-excluding-junk-ops, 0), __K8MASK(multiply-pipe-excluding-junk-ops, 1), __K8MASK(store-pipe-excluding-junk-ops, 2), __K8MASK(add-pipe-junk-ops, 3), __K8MASK(multiply-pipe-junk-ops, 4), __K8MASK(store-pipe-junk-ops, 5), NULLMASK }; /* ls segment register loads */ static const struct pmc_masks k8_mask_lsrl[] = { __K8MASK(es, 0), __K8MASK(cs, 1), __K8MASK(ss, 2), __K8MASK(ds, 3), __K8MASK(fs, 4), __K8MASK(gs, 5), __K8MASK(hs, 6), NULLMASK }; /* ls locked operation */ static const struct pmc_masks k8_mask_llo[] = { __K8MASK(locked-instructions, 0), __K8MASK(cycles-in-request, 1), __K8MASK(cycles-to-complete, 2), NULLMASK }; /* dc refill from {l2,system} and dc copyback */ static const struct pmc_masks k8_mask_dc[] = { __K8MASK(invalid, 0), __K8MASK(shared, 1), __K8MASK(exclusive, 2), __K8MASK(owner, 3), __K8MASK(modified, 4), NULLMASK }; /* dc one bit ecc error */ static const struct pmc_masks k8_mask_dobee[] = { __K8MASK(scrubber, 0), __K8MASK(piggyback, 1), NULLMASK }; /* dc dispatched prefetch instructions */ static const struct pmc_masks k8_mask_ddpi[] = { __K8MASK(load, 0), __K8MASK(store, 1), __K8MASK(nta, 2), NULLMASK }; /* dc dcache accesses by locks */ static const struct pmc_masks k8_mask_dabl[] = { __K8MASK(accesses, 0), __K8MASK(misses, 1), NULLMASK }; /* bu internal l2 request */ static const struct pmc_masks k8_mask_bilr[] = { __K8MASK(ic-fill, 0), __K8MASK(dc-fill, 1), __K8MASK(tlb-reload, 2), __K8MASK(tag-snoop, 3), __K8MASK(cancelled, 4), NULLMASK }; /* bu fill request l2 miss */ static const struct pmc_masks k8_mask_bfrlm[] = { __K8MASK(ic-fill, 0), __K8MASK(dc-fill, 1), __K8MASK(tlb-reload, 2), NULLMASK }; /* bu fill into l2 */ static const struct pmc_masks k8_mask_bfil[] = { __K8MASK(dirty-l2-victim, 0), __K8MASK(victim-from-l2, 1), NULLMASK }; /* fr retired fpu instructions */ static const struct pmc_masks k8_mask_frfi[] = { __K8MASK(x87, 0), __K8MASK(mmx-3dnow, 1), __K8MASK(packed-sse-sse2, 2), __K8MASK(scalar-sse-sse2, 3), NULLMASK }; /* fr retired fastpath double op instructions */ static const struct pmc_masks k8_mask_frfdoi[] = { __K8MASK(low-op-pos-0, 0), __K8MASK(low-op-pos-1, 1), __K8MASK(low-op-pos-2, 2), NULLMASK }; /* fr fpu exceptions */ static const struct pmc_masks k8_mask_ffe[] = { __K8MASK(x87-reclass-microfaults, 0), __K8MASK(sse-retype-microfaults, 1), __K8MASK(sse-reclass-microfaults, 2), __K8MASK(sse-and-x87-microtraps, 3), NULLMASK }; /* nb memory controller page access event */ static const struct pmc_masks k8_mask_nmcpae[] = { __K8MASK(page-hit, 0), __K8MASK(page-miss, 1), __K8MASK(page-conflict, 2), NULLMASK }; /* nb memory controller turnaround */ static const struct pmc_masks k8_mask_nmct[] = { __K8MASK(dimm-turnaround, 0), __K8MASK(read-to-write-turnaround, 1), __K8MASK(write-to-read-turnaround, 2), NULLMASK }; /* nb memory controller bypass saturation */ static const struct pmc_masks k8_mask_nmcbs[] = { __K8MASK(memory-controller-hi-pri-bypass, 0), __K8MASK(memory-controller-lo-pri-bypass, 1), __K8MASK(dram-controller-interface-bypass, 2), __K8MASK(dram-controller-queue-bypass, 3), NULLMASK }; /* nb sized commands */ static const struct pmc_masks k8_mask_nsc[] = { __K8MASK(nonpostwrszbyte, 0), __K8MASK(nonpostwrszdword, 1), __K8MASK(postwrszbyte, 2), __K8MASK(postwrszdword, 3), __K8MASK(rdszbyte, 4), __K8MASK(rdszdword, 5), __K8MASK(rdmodwr, 6), NULLMASK }; /* nb probe result */ static const struct pmc_masks k8_mask_npr[] = { __K8MASK(probe-miss, 0), __K8MASK(probe-hit, 1), __K8MASK(probe-hit-dirty-no-memory-cancel, 2), __K8MASK(probe-hit-dirty-with-memory-cancel, 3), NULLMASK }; /* nb hypertransport bus bandwidth */ static const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ __K8MASK(command, 0), __K8MASK(data, 1), __K8MASK(buffer-release, 2), __K8MASK(nop, 3), NULLMASK }; #undef __K8MASK #define K8_KW_COUNT "count" #define K8_KW_EDGE "edge" #define K8_KW_INV "inv" #define K8_KW_MASK "mask" #define K8_KW_OS "os" #define K8_KW_USR "usr" static int k8_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { char *e, *p, *q; int n; uint32_t count; uint64_t evmask; const struct pmc_masks *pm, *pmask; pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); pmc_config->pm_md.pm_amd.pm_amd_config = 0; pmask = NULL; evmask = 0; #define __K8SETMASK(M) pmask = k8_mask_##M /* setup parsing tables */ switch (pe) { case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: __K8SETMASK(fdfo); break; case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: __K8SETMASK(lsrl); break; case PMC_EV_K8_LS_LOCKED_OPERATION: __K8SETMASK(llo); break; case PMC_EV_K8_DC_REFILL_FROM_L2: case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: case PMC_EV_K8_DC_COPYBACK: __K8SETMASK(dc); break; case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: __K8SETMASK(dobee); break; case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: __K8SETMASK(ddpi); break; case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: __K8SETMASK(dabl); break; case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: __K8SETMASK(bilr); break; case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: __K8SETMASK(bfrlm); break; case PMC_EV_K8_BU_FILL_INTO_L2: __K8SETMASK(bfil); break; case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: __K8SETMASK(frfi); break; case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: __K8SETMASK(frfdoi); break; case PMC_EV_K8_FR_FPU_EXCEPTIONS: __K8SETMASK(ffe); break; case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: __K8SETMASK(nmcpae); break; case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: __K8SETMASK(nmct); break; case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: __K8SETMASK(nmcbs); break; case PMC_EV_K8_NB_SIZED_COMMANDS: __K8SETMASK(nsc); break; case PMC_EV_K8_NB_PROBE_RESULT: __K8SETMASK(npr); break; case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: __K8SETMASK(nhbb); break; default: break; /* no options defined */ } while ((p = strsep(&ctrspec, ",")) != NULL) { if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') return (-1); pmc_config->pm_caps |= PMC_CAP_THRESHOLD; pmc_config->pm_md.pm_amd.pm_amd_config |= AMD_PMC_TO_COUNTER(count); } else if (KWMATCH(p, K8_KW_EDGE)) { pmc_config->pm_caps |= PMC_CAP_EDGE; } else if (KWMATCH(p, K8_KW_INV)) { pmc_config->pm_caps |= PMC_CAP_INVERT; } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) return (-1); pmc_config->pm_caps |= PMC_CAP_QUALIFIER; } else if (KWMATCH(p, K8_KW_OS)) { pmc_config->pm_caps |= PMC_CAP_SYSTEM; } else if (KWMATCH(p, K8_KW_USR)) { pmc_config->pm_caps |= PMC_CAP_USER; } else return (-1); } /* other post processing */ switch (pe) { case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: case PMC_EV_K8_FR_FPU_EXCEPTIONS: /* XXX only available in rev B and later */ break; case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: /* XXX only available in rev C and later */ break; case PMC_EV_K8_LS_LOCKED_OPERATION: /* XXX CPU Rev A,B evmask is to be zero */ if (evmask & (evmask - 1)) /* > 1 bit set */ return (-1); if (evmask == 0) { evmask = 0x01; /* Rev C and later: #instrs */ pmc_config->pm_caps |= PMC_CAP_QUALIFIER; } break; default: if (evmask == 0 && pmask != NULL) { for (pm = pmask; pm->pm_name; pm++) evmask |= pm->pm_value; pmc_config->pm_caps |= PMC_CAP_QUALIFIER; } } if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) pmc_config->pm_md.pm_amd.pm_amd_config = AMD_PMC_TO_UNITMASK(evmask); return (0); } #endif #if defined(__amd64__) || defined(__i386__) /* * Intel P4 PMCs */ static struct pmc_event_alias p4_aliases[] = { EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), EV_ALIAS("cycles", "tsc"), EV_ALIAS("instructions", "p4-instr-retired,mask=nbogusntag+nbogustag"), EV_ALIAS("unhalted-cycles", "p4-global-power-events"), EV_ALIAS(NULL, NULL) }; #define P4_KW_ACTIVE "active" #define P4_KW_ACTIVE_ANY "any" #define P4_KW_ACTIVE_BOTH "both" #define P4_KW_ACTIVE_NONE "none" #define P4_KW_ACTIVE_SINGLE "single" #define P4_KW_BUSREQTYPE "busreqtype" #define P4_KW_CASCADE "cascade" #define P4_KW_EDGE "edge" #define P4_KW_INV "complement" #define P4_KW_OS "os" #define P4_KW_MASK "mask" #define P4_KW_PRECISE "precise" #define P4_KW_TAG "tag" #define P4_KW_THRESHOLD "threshold" #define P4_KW_USR "usr" #define __P4MASK(N,V) PMCMASK(N, (1 << (V))) static const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ __P4MASK(dd, 0), __P4MASK(db, 1), __P4MASK(di, 2), __P4MASK(bd, 3), __P4MASK(bb, 4), __P4MASK(bi, 5), __P4MASK(id, 6), __P4MASK(ib, 7), NULLMASK }; static const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ __P4MASK(tcmiss, 0), NULLMASK, }; static const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ __P4MASK(hit, 0), __P4MASK(miss, 1), __P4MASK(hit-uc, 2), NULLMASK }; static const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ __P4MASK(st-rb-full, 2), __P4MASK(64k-conf, 3), NULLMASK }; static const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ __P4MASK(lsc, 0), __P4MASK(ssc, 1), NULLMASK }; static const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ __P4MASK(split-ld, 1), NULLMASK }; static const struct pmc_masks p4_mask_spr[] = { /* store port replay */ __P4MASK(split-st, 1), NULLMASK }; static const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ __P4MASK(no-sta, 1), __P4MASK(no-std, 3), __P4MASK(partial-data, 4), __P4MASK(unalgn-addr, 5), NULLMASK }; static const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ __P4MASK(dtmiss, 0), __P4MASK(itmiss, 1), NULLMASK }; static const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ __P4MASK(rd-2ndl-hits, 0), __P4MASK(rd-2ndl-hite, 1), __P4MASK(rd-2ndl-hitm, 2), __P4MASK(rd-3rdl-hits, 3), __P4MASK(rd-3rdl-hite, 4), __P4MASK(rd-3rdl-hitm, 5), __P4MASK(rd-2ndl-miss, 8), __P4MASK(rd-3rdl-miss, 9), __P4MASK(wr-2ndl-miss, 10), NULLMASK }; static const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ __P4MASK(all-read, 5), __P4MASK(all-write, 6), __P4MASK(mem-uc, 7), __P4MASK(mem-wc, 8), __P4MASK(mem-wt, 9), __P4MASK(mem-wp, 10), __P4MASK(mem-wb, 11), __P4MASK(own, 13), __P4MASK(other, 14), __P4MASK(prefetch, 15), NULLMASK }; static const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ __P4MASK(all-read, 5), __P4MASK(all-write, 6), __P4MASK(mem-uc, 7), __P4MASK(mem-wc, 8), __P4MASK(mem-wt, 9), __P4MASK(mem-wp, 10), __P4MASK(mem-wb, 11), __P4MASK(own, 13), __P4MASK(other, 14), __P4MASK(prefetch, 15), NULLMASK }; static const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ __P4MASK(drdy-drv, 0), __P4MASK(drdy-own, 1), __P4MASK(drdy-other, 2), __P4MASK(dbsy-drv, 3), __P4MASK(dbsy-own, 4), __P4MASK(dbsy-other, 5), NULLMASK }; static const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ __P4MASK(req-type0, 0), __P4MASK(req-type1, 1), __P4MASK(req-len0, 2), __P4MASK(req-len1, 3), __P4MASK(req-io-type, 5), __P4MASK(req-lock-type, 6), __P4MASK(req-cache-type, 7), __P4MASK(req-split-type, 8), __P4MASK(req-dem-type, 9), __P4MASK(req-ord-type, 10), __P4MASK(mem-type0, 11), __P4MASK(mem-type1, 12), __P4MASK(mem-type2, 13), NULLMASK }; static const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ __P4MASK(all, 15), NULLMASK }; static const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ __P4MASK(all, 15), NULLMASK }; static const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ __P4MASK(all, 15), NULLMASK }; static const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ __P4MASK(all, 15), NULLMASK }; static const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ __P4MASK(all, 15), NULLMASK }; static const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ __P4MASK(all, 15), NULLMASK }; static const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ __P4MASK(all, 15), NULLMASK }; static const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ __P4MASK(all, 15), NULLMASK }; static const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ __P4MASK(allp0, 3), __P4MASK(allp2, 4), NULLMASK }; static const struct pmc_masks p4_mask_gpe[] = { /* global power events */ __P4MASK(running, 0), NULLMASK }; static const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ __P4MASK(cisc, 0), NULLMASK }; static const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ __P4MASK(from-tc-build, 0), __P4MASK(from-tc-deliver, 1), __P4MASK(from-rom, 2), NULLMASK }; static const struct pmc_masks p4_mask_rmbt[] = { /* retired mispred branch type */ __P4MASK(conditional, 1), __P4MASK(call, 2), __P4MASK(return, 3), __P4MASK(indirect, 4), NULLMASK }; static const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ __P4MASK(conditional, 1), __P4MASK(call, 2), __P4MASK(retired, 3), __P4MASK(indirect, 4), NULLMASK }; static const struct pmc_masks p4_mask_rs[] = { /* resource stall */ __P4MASK(sbfull, 5), NULLMASK }; static const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ __P4MASK(wcb-evicts, 0), __P4MASK(wcb-full-evict, 1), NULLMASK }; static const struct pmc_masks p4_mask_fee[] = { /* front end event */ __P4MASK(nbogus, 0), __P4MASK(bogus, 1), NULLMASK }; static const struct pmc_masks p4_mask_ee[] = { /* execution event */ __P4MASK(nbogus0, 0), __P4MASK(nbogus1, 1), __P4MASK(nbogus2, 2), __P4MASK(nbogus3, 3), __P4MASK(bogus0, 4), __P4MASK(bogus1, 5), __P4MASK(bogus2, 6), __P4MASK(bogus3, 7), NULLMASK }; static const struct pmc_masks p4_mask_re[] = { /* replay event */ __P4MASK(nbogus, 0), __P4MASK(bogus, 1), NULLMASK }; static const struct pmc_masks p4_mask_insret[] = { /* instr retired */ __P4MASK(nbogusntag, 0), __P4MASK(nbogustag, 1), __P4MASK(bogusntag, 2), __P4MASK(bogustag, 3), NULLMASK }; static const struct pmc_masks p4_mask_ur[] = { /* uops retired */ __P4MASK(nbogus, 0), __P4MASK(bogus, 1), NULLMASK }; static const struct pmc_masks p4_mask_ut[] = { /* uop type */ __P4MASK(tagloads, 1), __P4MASK(tagstores, 2), NULLMASK }; static const struct pmc_masks p4_mask_br[] = { /* branch retired */ __P4MASK(mmnp, 0), __P4MASK(mmnm, 1), __P4MASK(mmtp, 2), __P4MASK(mmtm, 3), NULLMASK }; static const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ __P4MASK(nbogus, 0), NULLMASK }; static const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ __P4MASK(fpsu, 0), __P4MASK(fpso, 1), __P4MASK(poao, 2), __P4MASK(poau, 3), __P4MASK(prea, 4), NULLMASK }; static const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ __P4MASK(clear, 0), __P4MASK(moclear, 2), __P4MASK(smclear, 3), NULLMASK }; /* P4 event parser */ static int p4_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { char *e, *p, *q; int count, has_tag, has_busreqtype, n; uint32_t cccractivemask; uint64_t evmask; const struct pmc_masks *pm, *pmask; pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; pmask = NULL; evmask = 0; cccractivemask = 0x3; has_tag = has_busreqtype = 0; #define __P4SETMASK(M) do { \ pmask = p4_mask_##M; \ } while (0) switch (pe) { case PMC_EV_P4_TC_DELIVER_MODE: __P4SETMASK(tcdm); break; case PMC_EV_P4_BPU_FETCH_REQUEST: __P4SETMASK(bfr); break; case PMC_EV_P4_ITLB_REFERENCE: __P4SETMASK(ir); break; case PMC_EV_P4_MEMORY_CANCEL: __P4SETMASK(memcan); break; case PMC_EV_P4_MEMORY_COMPLETE: __P4SETMASK(memcomp); break; case PMC_EV_P4_LOAD_PORT_REPLAY: __P4SETMASK(lpr); break; case PMC_EV_P4_STORE_PORT_REPLAY: __P4SETMASK(spr); break; case PMC_EV_P4_MOB_LOAD_REPLAY: __P4SETMASK(mlr); break; case PMC_EV_P4_PAGE_WALK_TYPE: __P4SETMASK(pwt); break; case PMC_EV_P4_BSQ_CACHE_REFERENCE: __P4SETMASK(bcr); break; case PMC_EV_P4_IOQ_ALLOCATION: __P4SETMASK(ia); has_busreqtype = 1; break; case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: __P4SETMASK(iae); has_busreqtype = 1; break; case PMC_EV_P4_FSB_DATA_ACTIVITY: __P4SETMASK(fda); break; case PMC_EV_P4_BSQ_ALLOCATION: __P4SETMASK(ba); break; case PMC_EV_P4_SSE_INPUT_ASSIST: __P4SETMASK(sia); break; case PMC_EV_P4_PACKED_SP_UOP: __P4SETMASK(psu); break; case PMC_EV_P4_PACKED_DP_UOP: __P4SETMASK(pdu); break; case PMC_EV_P4_SCALAR_SP_UOP: __P4SETMASK(ssu); break; case PMC_EV_P4_SCALAR_DP_UOP: __P4SETMASK(sdu); break; case PMC_EV_P4_64BIT_MMX_UOP: __P4SETMASK(64bmu); break; case PMC_EV_P4_128BIT_MMX_UOP: __P4SETMASK(128bmu); break; case PMC_EV_P4_X87_FP_UOP: __P4SETMASK(xfu); break; case PMC_EV_P4_X87_SIMD_MOVES_UOP: __P4SETMASK(xsmu); break; case PMC_EV_P4_GLOBAL_POWER_EVENTS: __P4SETMASK(gpe); break; case PMC_EV_P4_TC_MS_XFER: __P4SETMASK(tmx); break; case PMC_EV_P4_UOP_QUEUE_WRITES: __P4SETMASK(uqw); break; case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: __P4SETMASK(rmbt); break; case PMC_EV_P4_RETIRED_BRANCH_TYPE: __P4SETMASK(rbt); break; case PMC_EV_P4_RESOURCE_STALL: __P4SETMASK(rs); break; case PMC_EV_P4_WC_BUFFER: __P4SETMASK(wb); break; case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: case PMC_EV_P4_B2B_CYCLES: case PMC_EV_P4_BNR: case PMC_EV_P4_SNOOP: case PMC_EV_P4_RESPONSE: break; case PMC_EV_P4_FRONT_END_EVENT: __P4SETMASK(fee); break; case PMC_EV_P4_EXECUTION_EVENT: __P4SETMASK(ee); break; case PMC_EV_P4_REPLAY_EVENT: __P4SETMASK(re); break; case PMC_EV_P4_INSTR_RETIRED: __P4SETMASK(insret); break; case PMC_EV_P4_UOPS_RETIRED: __P4SETMASK(ur); break; case PMC_EV_P4_UOP_TYPE: __P4SETMASK(ut); break; case PMC_EV_P4_BRANCH_RETIRED: __P4SETMASK(br); break; case PMC_EV_P4_MISPRED_BRANCH_RETIRED: __P4SETMASK(mbr); break; case PMC_EV_P4_X87_ASSIST: __P4SETMASK(xa); break; case PMC_EV_P4_MACHINE_CLEAR: __P4SETMASK(machclr); break; default: return (-1); } /* process additional flags */ while ((p = strsep(&ctrspec, ",")) != NULL) { if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ return (-1); if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) cccractivemask = 0x0; else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) cccractivemask = 0x1; else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) cccractivemask = 0x2; else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) cccractivemask = 0x3; else return (-1); } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { if (has_busreqtype == 0) return (-1); q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') return (-1); evmask = (evmask & ~0x1F) | (count & 0x1F); } else if (KWMATCH(p, P4_KW_CASCADE)) pmc_config->pm_caps |= PMC_CAP_CASCADE; else if (KWMATCH(p, P4_KW_EDGE)) pmc_config->pm_caps |= PMC_CAP_EDGE; else if (KWMATCH(p, P4_KW_INV)) pmc_config->pm_caps |= PMC_CAP_INVERT; else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) return (-1); pmc_config->pm_caps |= PMC_CAP_QUALIFIER; } else if (KWMATCH(p, P4_KW_OS)) pmc_config->pm_caps |= PMC_CAP_SYSTEM; else if (KWMATCH(p, P4_KW_PRECISE)) pmc_config->pm_caps |= PMC_CAP_PRECISE; else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { if (has_tag == 0) return (-1); q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') return (-1); pmc_config->pm_caps |= PMC_CAP_TAGGING; pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= P4_ESCR_TO_TAG_VALUE(count); } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') return (-1); pmc_config->pm_caps |= PMC_CAP_THRESHOLD; pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= ~P4_CCCR_THRESHOLD_MASK; pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= P4_CCCR_TO_THRESHOLD(count); } else if (KWMATCH(p, P4_KW_USR)) pmc_config->pm_caps |= PMC_CAP_USER; else return (-1); } /* other post processing */ if (pe == PMC_EV_P4_IOQ_ALLOCATION || pe == PMC_EV_P4_FSB_DATA_ACTIVITY || pe == PMC_EV_P4_BSQ_ALLOCATION) pmc_config->pm_caps |= PMC_CAP_EDGE; /* fill in thread activity mask */ pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); if (evmask) pmc_config->pm_caps |= PMC_CAP_QUALIFIER; switch (pe) { case PMC_EV_P4_FSB_DATA_ACTIVITY: if ((evmask & 0x06) == 0x06 || (evmask & 0x18) == 0x18) return (-1); /* can't have own+other bits together */ if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ evmask = 0x1D; break; case PMC_EV_P4_MACHINE_CLEAR: /* only one bit is allowed to be set */ if ((evmask & (evmask - 1)) != 0) return (-1); if (evmask == 0) { evmask = 0x1; /* 'CLEAR' */ pmc_config->pm_caps |= PMC_CAP_QUALIFIER; } break; default: if (evmask == 0 && pmask) { for (pm = pmask; pm->pm_name; pm++) evmask |= pm->pm_value; pmc_config->pm_caps |= PMC_CAP_QUALIFIER; } } pmc_config->pm_md.pm_p4.pm_p4_escrconfig = P4_ESCR_TO_EVENT_MASK(evmask); return (0); } #endif #if defined(__i386__) /* * Pentium style PMCs */ static struct pmc_event_alias p5_aliases[] = { EV_ALIAS("branches", "p5-taken-branches"), EV_ALIAS("cycles", "tsc"), EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), EV_ALIAS("ic-misses", "p5-code-cache-miss"), EV_ALIAS("instructions", "p5-instructions-executed"), EV_ALIAS("interrupts", "p5-hardware-interrupts"), EV_ALIAS("unhalted-cycles", "p5-number-of-cycles-not-in-halt-state"), EV_ALIAS(NULL, NULL) }; static int p5_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ } /* * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, * and Pentium M CPUs. */ static struct pmc_event_alias p6_aliases[] = { EV_ALIAS("branches", "p6-br-inst-retired"), EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), EV_ALIAS("cycles", "tsc"), EV_ALIAS("dc-misses", "p6-dcu-lines-in"), EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), EV_ALIAS("instructions", "p6-inst-retired"), EV_ALIAS("interrupts", "p6-hw-int-rx"), EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), EV_ALIAS(NULL, NULL) }; #define P6_KW_CMASK "cmask" #define P6_KW_EDGE "edge" #define P6_KW_INV "inv" #define P6_KW_OS "os" #define P6_KW_UMASK "umask" #define P6_KW_USR "usr" static struct pmc_masks p6_mask_mesi[] = { PMCMASK(m, 0x01), PMCMASK(e, 0x02), PMCMASK(s, 0x04), PMCMASK(i, 0x08), NULLMASK }; static struct pmc_masks p6_mask_mesihw[] = { PMCMASK(m, 0x01), PMCMASK(e, 0x02), PMCMASK(s, 0x04), PMCMASK(i, 0x08), PMCMASK(nonhw, 0x00), PMCMASK(hw, 0x10), PMCMASK(both, 0x30), NULLMASK }; static struct pmc_masks p6_mask_hw[] = { PMCMASK(nonhw, 0x00), PMCMASK(hw, 0x10), PMCMASK(both, 0x30), NULLMASK }; static struct pmc_masks p6_mask_any[] = { PMCMASK(self, 0x00), PMCMASK(any, 0x20), NULLMASK }; static struct pmc_masks p6_mask_ekp[] = { PMCMASK(nta, 0x00), PMCMASK(t1, 0x01), PMCMASK(t2, 0x02), PMCMASK(wos, 0x03), NULLMASK }; static struct pmc_masks p6_mask_pps[] = { PMCMASK(packed-and-scalar, 0x00), PMCMASK(scalar, 0x01), NULLMASK }; static struct pmc_masks p6_mask_mite[] = { PMCMASK(packed-multiply, 0x01), PMCMASK(packed-shift, 0x02), PMCMASK(pack, 0x04), PMCMASK(unpack, 0x08), PMCMASK(packed-logical, 0x10), PMCMASK(packed-arithmetic, 0x20), NULLMASK }; static struct pmc_masks p6_mask_fmt[] = { PMCMASK(mmxtofp, 0x00), PMCMASK(fptommx, 0x01), NULLMASK }; static struct pmc_masks p6_mask_sr[] = { PMCMASK(es, 0x01), PMCMASK(ds, 0x02), PMCMASK(fs, 0x04), PMCMASK(gs, 0x08), NULLMASK }; static struct pmc_masks p6_mask_eet[] = { PMCMASK(all, 0x00), PMCMASK(freq, 0x02), NULLMASK }; static struct pmc_masks p6_mask_efur[] = { PMCMASK(all, 0x00), PMCMASK(loadop, 0x01), PMCMASK(stdsta, 0x02), NULLMASK }; static struct pmc_masks p6_mask_essir[] = { PMCMASK(sse-packed-single, 0x00), PMCMASK(sse-packed-single-scalar-single, 0x01), PMCMASK(sse2-packed-double, 0x02), PMCMASK(sse2-scalar-double, 0x03), NULLMASK }; static struct pmc_masks p6_mask_esscir[] = { PMCMASK(sse-packed-single, 0x00), PMCMASK(sse-scalar-single, 0x01), PMCMASK(sse2-packed-double, 0x02), PMCMASK(sse2-scalar-double, 0x03), NULLMASK }; /* P6 event parser */ static int p6_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { char *e, *p, *q; uint64_t evmask; int count, n; const struct pmc_masks *pm, *pmask; pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; evmask = 0; #define P6MASKSET(M) pmask = p6_mask_ ## M switch(pe) { case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; case PMC_EV_P6_BUS_DRDY_CLOCKS: case PMC_EV_P6_BUS_LOCK_CLOCKS: case PMC_EV_P6_BUS_TRAN_BRD: case PMC_EV_P6_BUS_TRAN_RFO: case PMC_EV_P6_BUS_TRANS_WB: case PMC_EV_P6_BUS_TRAN_IFETCH: case PMC_EV_P6_BUS_TRAN_INVAL: case PMC_EV_P6_BUS_TRAN_PWR: case PMC_EV_P6_BUS_TRANS_P: case PMC_EV_P6_BUS_TRANS_IO: case PMC_EV_P6_BUS_TRAN_DEF: case PMC_EV_P6_BUS_TRAN_BURST: case PMC_EV_P6_BUS_TRAN_ANY: case PMC_EV_P6_BUS_TRAN_MEM: P6MASKSET(any); break; case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: case PMC_EV_P6_EMON_KNI_PREF_MISS: P6MASKSET(ekp); break; case PMC_EV_P6_EMON_KNI_INST_RETIRED: case PMC_EV_P6_EMON_KNI_COMP_INST_RET: P6MASKSET(pps); break; case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: P6MASKSET(mite); break; case PMC_EV_P6_FP_MMX_TRANS: P6MASKSET(fmt); break; case PMC_EV_P6_SEG_RENAME_STALLS: case PMC_EV_P6_SEG_REG_RENAMES: P6MASKSET(sr); break; case PMC_EV_P6_EMON_EST_TRANS: P6MASKSET(eet); break; case PMC_EV_P6_EMON_FUSED_UOPS_RET: P6MASKSET(efur); break; case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: P6MASKSET(essir); break; case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: P6MASKSET(esscir); break; default: pmask = NULL; break; } /* Pentium M PMCs have a few events with different semantics */ if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { if (pe == PMC_EV_P6_L2_LD || pe == PMC_EV_P6_L2_LINES_IN || pe == PMC_EV_P6_L2_LINES_OUT) P6MASKSET(mesihw); else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) P6MASKSET(hw); } /* Parse additional modifiers if present */ while ((p = strsep(&ctrspec, ",")) != NULL) { if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') return (-1); pmc_config->pm_caps |= PMC_CAP_THRESHOLD; pmc_config->pm_md.pm_ppro.pm_ppro_config |= P6_EVSEL_TO_CMASK(count); } else if (KWMATCH(p, P6_KW_EDGE)) { pmc_config->pm_caps |= PMC_CAP_EDGE; } else if (KWMATCH(p, P6_KW_INV)) { pmc_config->pm_caps |= PMC_CAP_INVERT; } else if (KWMATCH(p, P6_KW_OS)) { pmc_config->pm_caps |= PMC_CAP_SYSTEM; } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { evmask = 0; if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) return (-1); if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || pe == PMC_EV_P6_BUS_LOCK_CLOCKS || pe == PMC_EV_P6_BUS_TRAN_BRD || pe == PMC_EV_P6_BUS_TRAN_RFO || pe == PMC_EV_P6_BUS_TRAN_IFETCH || pe == PMC_EV_P6_BUS_TRAN_INVAL || pe == PMC_EV_P6_BUS_TRAN_PWR || pe == PMC_EV_P6_BUS_TRAN_DEF || pe == PMC_EV_P6_BUS_TRAN_BURST || pe == PMC_EV_P6_BUS_TRAN_ANY || pe == PMC_EV_P6_BUS_TRAN_MEM || pe == PMC_EV_P6_BUS_TRANS_IO || pe == PMC_EV_P6_BUS_TRANS_P || pe == PMC_EV_P6_BUS_TRANS_WB || pe == PMC_EV_P6_EMON_EST_TRANS || pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || pe == PMC_EV_P6_EMON_KNI_PREF_MISS || pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || pe == PMC_EV_P6_FP_MMX_TRANS) && (n > 1)) /* Only one mask keyword is allowed. */ return (-1); pmc_config->pm_caps |= PMC_CAP_QUALIFIER; } else if (KWMATCH(p, P6_KW_USR)) { pmc_config->pm_caps |= PMC_CAP_USER; } else return (-1); } /* post processing */ switch (pe) { /* * The following events default to an evmask of 0 */ /* default => 'self' */ case PMC_EV_P6_BUS_DRDY_CLOCKS: case PMC_EV_P6_BUS_LOCK_CLOCKS: case PMC_EV_P6_BUS_TRAN_BRD: case PMC_EV_P6_BUS_TRAN_RFO: case PMC_EV_P6_BUS_TRANS_WB: case PMC_EV_P6_BUS_TRAN_IFETCH: case PMC_EV_P6_BUS_TRAN_INVAL: case PMC_EV_P6_BUS_TRAN_PWR: case PMC_EV_P6_BUS_TRANS_P: case PMC_EV_P6_BUS_TRANS_IO: case PMC_EV_P6_BUS_TRAN_DEF: case PMC_EV_P6_BUS_TRAN_BURST: case PMC_EV_P6_BUS_TRAN_ANY: case PMC_EV_P6_BUS_TRAN_MEM: /* default => 'nta' */ case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: case PMC_EV_P6_EMON_KNI_PREF_MISS: /* default => 'packed and scalar' */ case PMC_EV_P6_EMON_KNI_INST_RETIRED: case PMC_EV_P6_EMON_KNI_COMP_INST_RET: /* default => 'mmx to fp transitions' */ case PMC_EV_P6_FP_MMX_TRANS: /* default => 'SSE Packed Single' */ case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: /* default => 'all fused micro-ops' */ case PMC_EV_P6_EMON_FUSED_UOPS_RET: /* default => 'all transitions' */ case PMC_EV_P6_EMON_EST_TRANS: break; case PMC_EV_P6_MMX_UOPS_EXEC: evmask = 0x0F; /* only value allowed */ break; default: /* * For all other events, set the default event mask * to a logical OR of all the allowed event mask bits. */ if (evmask == 0 && pmask) { for (pm = pmask; pm->pm_name; pm++) evmask |= pm->pm_value; pmc_config->pm_caps |= PMC_CAP_QUALIFIER; } break; } if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) pmc_config->pm_md.pm_ppro.pm_ppro_config |= P6_EVSEL_TO_UMASK(evmask); return (0); } #endif #if defined(__i386__) || defined(__amd64__) static int tsc_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { if (pe != PMC_EV_TSC_TSC) return (-1); /* TSC events must be unqualified. */ if (ctrspec && *ctrspec != '\0') return (-1); pmc_config->pm_md.pm_amd.pm_amd_config = 0; pmc_config->pm_caps |= PMC_CAP_READ; return (0); } #endif static struct pmc_event_alias generic_aliases[] = { EV_ALIAS("instructions", "SOFT-CLOCK.HARD"), EV_ALIAS(NULL, NULL) }; static int soft_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { (void)ctrspec; (void)pmc_config; if ((int)pe < PMC_EV_SOFT_FIRST || (int)pe > PMC_EV_SOFT_LAST) return (-1); pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); return (0); } #if defined(__arm__) #if defined(__XSCALE__) static struct pmc_event_alias xscale_aliases[] = { EV_ALIAS("branches", "BRANCH_RETIRED"), EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), EV_ALIAS("dc-misses", "DC_MISS"), EV_ALIAS("ic-misses", "IC_MISS"), EV_ALIAS("instructions", "INSTR_RETIRED"), EV_ALIAS(NULL, NULL) }; static int xscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, struct pmc_op_pmcallocate *pmc_config __unused) { switch (pe) { default: break; } return (0); } #endif static struct pmc_event_alias cortex_a8_aliases[] = { EV_ALIAS("dc-misses", "L1_DCACHE_REFILL"), EV_ALIAS("ic-misses", "L1_ICACHE_REFILL"), EV_ALIAS("instructions", "INSTR_EXECUTED"), EV_ALIAS(NULL, NULL) }; static struct pmc_event_alias cortex_a9_aliases[] = { EV_ALIAS("dc-misses", "L1_DCACHE_REFILL"), EV_ALIAS("ic-misses", "L1_ICACHE_REFILL"), EV_ALIAS("instructions", "INSTR_EXECUTED"), EV_ALIAS(NULL, NULL) }; static int armv7_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, struct pmc_op_pmcallocate *pmc_config __unused) { switch (pe) { default: break; } return (0); } #endif #if defined(__aarch64__) static struct pmc_event_alias cortex_a53_aliases[] = { EV_ALIAS(NULL, NULL) }; static struct pmc_event_alias cortex_a57_aliases[] = { EV_ALIAS(NULL, NULL) }; static int arm64_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, struct pmc_op_pmcallocate *pmc_config __unused) { switch (pe) { default: break; } return (0); } #endif #if defined(__mips__) static struct pmc_event_alias mips24k_aliases[] = { EV_ALIAS("instructions", "INSTR_EXECUTED"), EV_ALIAS("branches", "BRANCH_COMPLETED"), EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), EV_ALIAS(NULL, NULL) }; static struct pmc_event_alias mips74k_aliases[] = { EV_ALIAS("instructions", "INSTR_EXECUTED"), EV_ALIAS("branches", "BRANCH_INSNS"), EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCH_INSNS"), EV_ALIAS(NULL, NULL) }; static struct pmc_event_alias octeon_aliases[] = { EV_ALIAS("instructions", "RET"), EV_ALIAS("branches", "BR"), EV_ALIAS("branch-mispredicts", "BRMIS"), EV_ALIAS(NULL, NULL) }; #define MIPS_KW_OS "os" #define MIPS_KW_USR "usr" #define MIPS_KW_ANYTHREAD "anythread" static int mips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, struct pmc_op_pmcallocate *pmc_config __unused) { char *p; (void) pe; pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); while ((p = strsep(&ctrspec, ",")) != NULL) { if (KWMATCH(p, MIPS_KW_OS)) pmc_config->pm_caps |= PMC_CAP_SYSTEM; else if (KWMATCH(p, MIPS_KW_USR)) pmc_config->pm_caps |= PMC_CAP_USER; else if (KWMATCH(p, MIPS_KW_ANYTHREAD)) pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); else return (-1); } return (0); } #endif /* __mips__ */ #if defined(__powerpc__) static struct pmc_event_alias ppc7450_aliases[] = { EV_ALIAS("instructions", "INSTR_COMPLETED"), EV_ALIAS("branches", "BRANCHES_COMPLETED"), EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCHES"), EV_ALIAS(NULL, NULL) }; static struct pmc_event_alias ppc970_aliases[] = { EV_ALIAS("instructions", "INSTR_COMPLETED"), EV_ALIAS("cycles", "CYCLES"), EV_ALIAS(NULL, NULL) }; static struct pmc_event_alias e500_aliases[] = { EV_ALIAS("instructions", "INSTR_COMPLETED"), EV_ALIAS("cycles", "CYCLES"), EV_ALIAS(NULL, NULL) }; #define POWERPC_KW_OS "os" #define POWERPC_KW_USR "usr" #define POWERPC_KW_ANYTHREAD "anythread" static int powerpc_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, struct pmc_op_pmcallocate *pmc_config __unused) { char *p; (void) pe; pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); while ((p = strsep(&ctrspec, ",")) != NULL) { if (KWMATCH(p, POWERPC_KW_OS)) pmc_config->pm_caps |= PMC_CAP_SYSTEM; else if (KWMATCH(p, POWERPC_KW_USR)) pmc_config->pm_caps |= PMC_CAP_USER; else if (KWMATCH(p, POWERPC_KW_ANYTHREAD)) pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); else return (-1); } return (0); } #endif /* __powerpc__ */ /* * Match an event name `name' with its canonical form. * * Matches are case insensitive and spaces, periods, underscores and * hyphen characters are considered to match each other. * * Returns 1 for a match, 0 otherwise. */ static int pmc_match_event_name(const char *name, const char *canonicalname) { int cc, nc; const unsigned char *c, *n; c = (const unsigned char *) canonicalname; n = (const unsigned char *) name; for (; (nc = *n) && (cc = *c); n++, c++) { if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') && (cc == ' ' || cc == '_' || cc == '-' || cc == '.')) continue; if (toupper(nc) == toupper(cc)) continue; return (0); } if (*n == '\0' && *c == '\0') return (1); return (0); } /* * Match an event name against all the event named supported by a * PMC class. * * Returns an event descriptor pointer on match or NULL otherwise. */ static const struct pmc_event_descr * pmc_match_event_class(const char *name, const struct pmc_class_descr *pcd) { size_t n; const struct pmc_event_descr *ev; ev = pcd->pm_evc_event_table; for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++) if (pmc_match_event_name(name, ev->pm_ev_name)) return (ev); return (NULL); } static int pmc_mdep_is_compatible_class(enum pmc_class pc) { size_t n; for (n = 0; n < pmc_mdep_class_list_size; n++) if (pmc_mdep_class_list[n] == pc) return (1); return (0); } /* * API entry points */ int pmc_allocate(const char *ctrspec, enum pmc_mode mode, uint32_t flags, int cpu, pmc_id_t *pmcid) { size_t n; int retval; char *r, *spec_copy; const char *ctrname; const struct pmc_event_descr *ev; const struct pmc_event_alias *alias; struct pmc_op_pmcallocate pmc_config; const struct pmc_class_descr *pcd; spec_copy = NULL; retval = -1; if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && mode != PMC_MODE_SC && mode != PMC_MODE_TC) { - errno = EINVAL; - goto out; + return (EINVAL); + } + bzero(&pmc_config, sizeof(pmc_config)); + pmc_config.pm_cpu = cpu; + pmc_config.pm_mode = mode; + pmc_config.pm_flags = flags; + if (PMC_IS_SAMPLING_MODE(mode)) + pmc_config.pm_caps |= PMC_CAP_INTERRUPT; + /* + * Can we pull this straight from the pmu table? + */ + r = spec_copy = strdup(ctrspec); + ctrname = strsep(&r, ","); + if (pmc_pmu_pmcallocate(ctrname, &pmc_config) == 0) { + if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) + return (errno); + *pmcid = pmc_config.pm_pmcid; + return (0); + } else { + free(spec_copy); + spec_copy = NULL; } /* replace an event alias with the canonical event specifier */ if (pmc_mdep_event_aliases) for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++) if (!strcasecmp(ctrspec, alias->pm_alias)) { spec_copy = strdup(alias->pm_spec); break; } if (spec_copy == NULL) spec_copy = strdup(ctrspec); r = spec_copy; ctrname = strsep(&r, ","); /* * If a explicit class prefix was given by the user, restrict the * search for the event to the specified PMC class. */ ev = NULL; for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) { pcd = pmc_class_table[n]; if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) && strncasecmp(ctrname, pcd->pm_evc_name, pcd->pm_evc_name_size) == 0) { if ((ev = pmc_match_event_class(ctrname + pcd->pm_evc_name_size, pcd)) == NULL) { errno = EINVAL; goto out; } break; } } /* * Otherwise, search for this event in all compatible PMC * classes. */ for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) { pcd = pmc_class_table[n]; if (pmc_mdep_is_compatible_class(pcd->pm_evc_class)) ev = pmc_match_event_class(ctrname, pcd); } if (ev == NULL) { errno = EINVAL; goto out; } - bzero(&pmc_config, sizeof(pmc_config)); pmc_config.pm_ev = ev->pm_ev_code; pmc_config.pm_class = pcd->pm_evc_class; - pmc_config.pm_cpu = cpu; - pmc_config.pm_mode = mode; - pmc_config.pm_flags = flags; - - if (PMC_IS_SAMPLING_MODE(mode)) - pmc_config.pm_caps |= PMC_CAP_INTERRUPT; if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) { errno = EINVAL; goto out; } if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) goto out; *pmcid = pmc_config.pm_pmcid; retval = 0; out: if (spec_copy) free(spec_copy); return (retval); } int pmc_attach(pmc_id_t pmc, pid_t pid) { struct pmc_op_pmcattach pmc_attach_args; pmc_attach_args.pm_pmc = pmc; pmc_attach_args.pm_pid = pid; return (PMC_CALL(PMCATTACH, &pmc_attach_args)); } int pmc_capabilities(pmc_id_t pmcid, uint32_t *caps) { unsigned int i; enum pmc_class cl; cl = PMC_ID_TO_CLASS(pmcid); for (i = 0; i < cpu_info.pm_nclass; i++) if (cpu_info.pm_classes[i].pm_class == cl) { *caps = cpu_info.pm_classes[i].pm_caps; return (0); } errno = EINVAL; return (-1); } int pmc_configure_logfile(int fd) { struct pmc_op_configurelog cla; cla.pm_logfd = fd; if (PMC_CALL(CONFIGURELOG, &cla) < 0) return (-1); return (0); } int pmc_cpuinfo(const struct pmc_cpuinfo **pci) { if (pmc_syscall == -1) { errno = ENXIO; return (-1); } *pci = &cpu_info; return (0); } int pmc_detach(pmc_id_t pmc, pid_t pid) { struct pmc_op_pmcattach pmc_detach_args; pmc_detach_args.pm_pmc = pmc; pmc_detach_args.pm_pid = pid; return (PMC_CALL(PMCDETACH, &pmc_detach_args)); } int pmc_disable(int cpu, int pmc) { struct pmc_op_pmcadmin ssa; ssa.pm_cpu = cpu; ssa.pm_pmc = pmc; ssa.pm_state = PMC_STATE_DISABLED; return (PMC_CALL(PMCADMIN, &ssa)); } int pmc_enable(int cpu, int pmc) { struct pmc_op_pmcadmin ssa; ssa.pm_cpu = cpu; ssa.pm_pmc = pmc; ssa.pm_state = PMC_STATE_FREE; return (PMC_CALL(PMCADMIN, &ssa)); } /* * Return a list of events known to a given PMC class. 'cl' is the * PMC class identifier, 'eventnames' is the returned list of 'const * char *' pointers pointing to the names of the events. 'nevents' is * the number of event name pointers returned. * * The space for 'eventnames' is allocated using malloc(3). The caller * is responsible for freeing this space when done. */ int pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, int *nevents) { int count; const char **names; const struct pmc_event_descr *ev; switch (cl) { case PMC_CLASS_IAF: ev = iaf_event_table; count = PMC_EVENT_TABLE_SIZE(iaf); break; case PMC_CLASS_IAP: /* * Return the most appropriate set of event name * spellings for the current CPU. */ switch (cpu_info.pm_cputype) { default: case PMC_CPU_INTEL_ATOM: ev = atom_event_table; count = PMC_EVENT_TABLE_SIZE(atom); break; case PMC_CPU_INTEL_ATOM_SILVERMONT: ev = atom_silvermont_event_table; count = PMC_EVENT_TABLE_SIZE(atom_silvermont); break; case PMC_CPU_INTEL_CORE: ev = core_event_table; count = PMC_EVENT_TABLE_SIZE(core); break; case PMC_CPU_INTEL_CORE2: case PMC_CPU_INTEL_CORE2EXTREME: ev = core2_event_table; count = PMC_EVENT_TABLE_SIZE(core2); break; case PMC_CPU_INTEL_COREI7: ev = corei7_event_table; count = PMC_EVENT_TABLE_SIZE(corei7); break; case PMC_CPU_INTEL_NEHALEM_EX: ev = nehalem_ex_event_table; count = PMC_EVENT_TABLE_SIZE(nehalem_ex); break; case PMC_CPU_INTEL_HASWELL: ev = haswell_event_table; count = PMC_EVENT_TABLE_SIZE(haswell); break; case PMC_CPU_INTEL_HASWELL_XEON: ev = haswell_xeon_event_table; count = PMC_EVENT_TABLE_SIZE(haswell_xeon); break; case PMC_CPU_INTEL_BROADWELL: ev = broadwell_event_table; count = PMC_EVENT_TABLE_SIZE(broadwell); break; case PMC_CPU_INTEL_BROADWELL_XEON: ev = broadwell_xeon_event_table; count = PMC_EVENT_TABLE_SIZE(broadwell_xeon); break; case PMC_CPU_INTEL_SKYLAKE: ev = skylake_event_table; count = PMC_EVENT_TABLE_SIZE(skylake); break; case PMC_CPU_INTEL_SKYLAKE_XEON: ev = skylake_xeon_event_table; count = PMC_EVENT_TABLE_SIZE(skylake_xeon); break; case PMC_CPU_INTEL_IVYBRIDGE: ev = ivybridge_event_table; count = PMC_EVENT_TABLE_SIZE(ivybridge); break; case PMC_CPU_INTEL_IVYBRIDGE_XEON: ev = ivybridge_xeon_event_table; count = PMC_EVENT_TABLE_SIZE(ivybridge_xeon); break; case PMC_CPU_INTEL_SANDYBRIDGE: ev = sandybridge_event_table; count = PMC_EVENT_TABLE_SIZE(sandybridge); break; case PMC_CPU_INTEL_SANDYBRIDGE_XEON: ev = sandybridge_xeon_event_table; count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon); break; case PMC_CPU_INTEL_WESTMERE: ev = westmere_event_table; count = PMC_EVENT_TABLE_SIZE(westmere); break; case PMC_CPU_INTEL_WESTMERE_EX: ev = westmere_ex_event_table; count = PMC_EVENT_TABLE_SIZE(westmere_ex); break; } break; case PMC_CLASS_UCF: ev = ucf_event_table; count = PMC_EVENT_TABLE_SIZE(ucf); break; case PMC_CLASS_UCP: /* * Return the most appropriate set of event name * spellings for the current CPU. */ switch (cpu_info.pm_cputype) { default: case PMC_CPU_INTEL_COREI7: ev = corei7uc_event_table; count = PMC_EVENT_TABLE_SIZE(corei7uc); break; case PMC_CPU_INTEL_HASWELL: ev = haswelluc_event_table; count = PMC_EVENT_TABLE_SIZE(haswelluc); break; case PMC_CPU_INTEL_BROADWELL: ev = broadwelluc_event_table; count = PMC_EVENT_TABLE_SIZE(broadwelluc); break; case PMC_CPU_INTEL_SANDYBRIDGE: ev = sandybridgeuc_event_table; count = PMC_EVENT_TABLE_SIZE(sandybridgeuc); break; case PMC_CPU_INTEL_WESTMERE: ev = westmereuc_event_table; count = PMC_EVENT_TABLE_SIZE(westmereuc); break; } break; case PMC_CLASS_TSC: ev = tsc_event_table; count = PMC_EVENT_TABLE_SIZE(tsc); break; case PMC_CLASS_K7: ev = k7_event_table; count = PMC_EVENT_TABLE_SIZE(k7); break; case PMC_CLASS_K8: ev = k8_event_table; count = PMC_EVENT_TABLE_SIZE(k8); break; case PMC_CLASS_P4: ev = p4_event_table; count = PMC_EVENT_TABLE_SIZE(p4); break; case PMC_CLASS_P5: ev = p5_event_table; count = PMC_EVENT_TABLE_SIZE(p5); break; case PMC_CLASS_P6: ev = p6_event_table; count = PMC_EVENT_TABLE_SIZE(p6); break; case PMC_CLASS_XSCALE: ev = xscale_event_table; count = PMC_EVENT_TABLE_SIZE(xscale); break; case PMC_CLASS_ARMV7: switch (cpu_info.pm_cputype) { default: case PMC_CPU_ARMV7_CORTEX_A8: ev = cortex_a8_event_table; count = PMC_EVENT_TABLE_SIZE(cortex_a8); break; case PMC_CPU_ARMV7_CORTEX_A9: ev = cortex_a9_event_table; count = PMC_EVENT_TABLE_SIZE(cortex_a9); break; } break; case PMC_CLASS_ARMV8: switch (cpu_info.pm_cputype) { default: case PMC_CPU_ARMV8_CORTEX_A53: ev = cortex_a53_event_table; count = PMC_EVENT_TABLE_SIZE(cortex_a53); break; case PMC_CPU_ARMV8_CORTEX_A57: ev = cortex_a57_event_table; count = PMC_EVENT_TABLE_SIZE(cortex_a57); break; } break; case PMC_CLASS_MIPS24K: ev = mips24k_event_table; count = PMC_EVENT_TABLE_SIZE(mips24k); break; case PMC_CLASS_MIPS74K: ev = mips74k_event_table; count = PMC_EVENT_TABLE_SIZE(mips74k); break; case PMC_CLASS_OCTEON: ev = octeon_event_table; count = PMC_EVENT_TABLE_SIZE(octeon); break; case PMC_CLASS_PPC7450: ev = ppc7450_event_table; count = PMC_EVENT_TABLE_SIZE(ppc7450); break; case PMC_CLASS_PPC970: ev = ppc970_event_table; count = PMC_EVENT_TABLE_SIZE(ppc970); break; case PMC_CLASS_E500: ev = e500_event_table; count = PMC_EVENT_TABLE_SIZE(e500); break; case PMC_CLASS_SOFT: ev = soft_event_table; count = soft_event_info.pm_nevent; break; default: errno = EINVAL; return (-1); } if ((names = malloc(count * sizeof(const char *))) == NULL) return (-1); *eventnames = names; *nevents = count; for (;count--; ev++, names++) *names = ev->pm_ev_name; return (0); } int pmc_flush_logfile(void) { return (PMC_CALL(FLUSHLOG,0)); } int pmc_close_logfile(void) { return (PMC_CALL(CLOSELOG,0)); } int pmc_get_driver_stats(struct pmc_driverstats *ds) { struct pmc_op_getdriverstats gms; if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) return (-1); /* copy out fields in the current userland<->library interface */ ds->pm_intr_ignored = gms.pm_intr_ignored; ds->pm_intr_processed = gms.pm_intr_processed; ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; ds->pm_syscalls = gms.pm_syscalls; ds->pm_syscall_errors = gms.pm_syscall_errors; ds->pm_buffer_requests = gms.pm_buffer_requests; ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; ds->pm_log_sweeps = gms.pm_log_sweeps; return (0); } int pmc_get_msr(pmc_id_t pmc, uint32_t *msr) { struct pmc_op_getmsr gm; gm.pm_pmcid = pmc; if (PMC_CALL(PMCGETMSR, &gm) < 0) return (-1); *msr = gm.pm_msr; return (0); } int pmc_init(void) { int error, pmc_mod_id; unsigned int n; uint32_t abi_version; struct module_stat pmc_modstat; struct pmc_op_getcpuinfo op_cpu_info; #if defined(__amd64__) || defined(__i386__) int cpu_has_iaf_counters; unsigned int t; #endif if (pmc_syscall != -1) /* already inited */ return (0); /* retrieve the system call number from the KLD */ if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) return (-1); pmc_modstat.version = sizeof(struct module_stat); if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) return (-1); pmc_syscall = pmc_modstat.data.intval; /* check the kernel module's ABI against our compiled-in version */ abi_version = PMC_VERSION; if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) return (pmc_syscall = -1); /* ignore patch & minor numbers for the comparison */ if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { errno = EPROGMISMATCH; return (pmc_syscall = -1); } if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) return (pmc_syscall = -1); cpu_info.pm_cputype = op_cpu_info.pm_cputype; cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; cpu_info.pm_npmc = op_cpu_info.pm_npmc; cpu_info.pm_nclass = op_cpu_info.pm_nclass; for (n = 0; n < cpu_info.pm_nclass; n++) memcpy(&cpu_info.pm_classes[n], &op_cpu_info.pm_classes[n], sizeof(cpu_info.pm_classes[n])); pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE * sizeof(struct pmc_class_descr *)); if (pmc_class_table == NULL) return (-1); for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) pmc_class_table[n] = NULL; /* * Get soft events list. */ soft_event_info.pm_class = PMC_CLASS_SOFT; if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0) return (pmc_syscall = -1); /* Map soft events to static list. */ for (n = 0; n < soft_event_info.pm_nevent; n++) { soft_event_table[n].pm_ev_name = soft_event_info.pm_events[n].pm_ev_name; soft_event_table[n].pm_ev_code = soft_event_info.pm_events[n].pm_ev_code; } soft_class_table_descr.pm_evc_event_table_size = \ soft_event_info.pm_nevent; soft_class_table_descr.pm_evc_event_table = \ soft_event_table; /* * Fill in the class table. */ n = 0; /* Fill soft events information. */ pmc_class_table[n++] = &soft_class_table_descr; #if defined(__amd64__) || defined(__i386__) if (cpu_info.pm_cputype != PMC_CPU_GENERIC) pmc_class_table[n++] = &tsc_class_table_descr; /* * Check if this CPU has fixed function counters. */ cpu_has_iaf_counters = 0; for (t = 0; t < cpu_info.pm_nclass; t++) if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF && cpu_info.pm_classes[t].pm_num > 0) cpu_has_iaf_counters = 1; #endif #define PMC_MDEP_INIT(C) do { \ pmc_mdep_event_aliases = C##_aliases; \ pmc_mdep_class_list = C##_pmc_classes; \ pmc_mdep_class_list_size = \ PMC_TABLE_SIZE(C##_pmc_classes); \ } while (0) #define PMC_MDEP_INIT_INTEL_V2(C) do { \ PMC_MDEP_INIT(C); \ pmc_class_table[n++] = &iaf_class_table_descr; \ if (!cpu_has_iaf_counters) \ pmc_mdep_event_aliases = \ C##_aliases_without_iaf; \ pmc_class_table[n] = &C##_class_table_descr; \ } while (0) /* Configure the event name parser. */ switch (cpu_info.pm_cputype) { #if defined(__i386__) case PMC_CPU_AMD_K7: PMC_MDEP_INIT(k7); pmc_class_table[n] = &k7_class_table_descr; break; case PMC_CPU_INTEL_P5: PMC_MDEP_INIT(p5); pmc_class_table[n] = &p5_class_table_descr; break; case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ case PMC_CPU_INTEL_PII: /* similar PMCs. */ case PMC_CPU_INTEL_PIII: case PMC_CPU_INTEL_PM: PMC_MDEP_INIT(p6); pmc_class_table[n] = &p6_class_table_descr; break; #endif #if defined(__amd64__) || defined(__i386__) case PMC_CPU_AMD_K8: PMC_MDEP_INIT(k8); pmc_class_table[n] = &k8_class_table_descr; break; case PMC_CPU_INTEL_ATOM: PMC_MDEP_INIT_INTEL_V2(atom); break; case PMC_CPU_INTEL_ATOM_SILVERMONT: PMC_MDEP_INIT_INTEL_V2(atom_silvermont); break; case PMC_CPU_INTEL_CORE: PMC_MDEP_INIT(core); pmc_class_table[n] = &core_class_table_descr; break; case PMC_CPU_INTEL_CORE2: case PMC_CPU_INTEL_CORE2EXTREME: PMC_MDEP_INIT_INTEL_V2(core2); break; case PMC_CPU_INTEL_COREI7: pmc_class_table[n++] = &ucf_class_table_descr; pmc_class_table[n++] = &corei7uc_class_table_descr; PMC_MDEP_INIT_INTEL_V2(corei7); break; case PMC_CPU_INTEL_NEHALEM_EX: PMC_MDEP_INIT_INTEL_V2(nehalem_ex); break; case PMC_CPU_INTEL_HASWELL: pmc_class_table[n++] = &ucf_class_table_descr; pmc_class_table[n++] = &haswelluc_class_table_descr; PMC_MDEP_INIT_INTEL_V2(haswell); break; case PMC_CPU_INTEL_HASWELL_XEON: PMC_MDEP_INIT_INTEL_V2(haswell_xeon); break; case PMC_CPU_INTEL_BROADWELL: pmc_class_table[n++] = &ucf_class_table_descr; pmc_class_table[n++] = &broadwelluc_class_table_descr; PMC_MDEP_INIT_INTEL_V2(broadwell); break; case PMC_CPU_INTEL_BROADWELL_XEON: PMC_MDEP_INIT_INTEL_V2(broadwell_xeon); break; case PMC_CPU_INTEL_SKYLAKE: PMC_MDEP_INIT_INTEL_V2(skylake); break; case PMC_CPU_INTEL_SKYLAKE_XEON: PMC_MDEP_INIT_INTEL_V2(skylake_xeon); break; case PMC_CPU_INTEL_IVYBRIDGE: PMC_MDEP_INIT_INTEL_V2(ivybridge); break; case PMC_CPU_INTEL_IVYBRIDGE_XEON: PMC_MDEP_INIT_INTEL_V2(ivybridge_xeon); break; case PMC_CPU_INTEL_SANDYBRIDGE: pmc_class_table[n++] = &ucf_class_table_descr; pmc_class_table[n++] = &sandybridgeuc_class_table_descr; PMC_MDEP_INIT_INTEL_V2(sandybridge); break; case PMC_CPU_INTEL_SANDYBRIDGE_XEON: PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon); break; case PMC_CPU_INTEL_WESTMERE: pmc_class_table[n++] = &ucf_class_table_descr; pmc_class_table[n++] = &westmereuc_class_table_descr; PMC_MDEP_INIT_INTEL_V2(westmere); break; case PMC_CPU_INTEL_WESTMERE_EX: PMC_MDEP_INIT_INTEL_V2(westmere_ex); break; case PMC_CPU_INTEL_PIV: PMC_MDEP_INIT(p4); pmc_class_table[n] = &p4_class_table_descr; break; #endif case PMC_CPU_GENERIC: PMC_MDEP_INIT(generic); break; #if defined(__arm__) #if defined(__XSCALE__) case PMC_CPU_INTEL_XSCALE: PMC_MDEP_INIT(xscale); pmc_class_table[n] = &xscale_class_table_descr; break; #endif case PMC_CPU_ARMV7_CORTEX_A8: PMC_MDEP_INIT(cortex_a8); pmc_class_table[n] = &cortex_a8_class_table_descr; break; case PMC_CPU_ARMV7_CORTEX_A9: PMC_MDEP_INIT(cortex_a9); pmc_class_table[n] = &cortex_a9_class_table_descr; break; #endif #if defined(__aarch64__) case PMC_CPU_ARMV8_CORTEX_A53: PMC_MDEP_INIT(cortex_a53); pmc_class_table[n] = &cortex_a53_class_table_descr; break; case PMC_CPU_ARMV8_CORTEX_A57: PMC_MDEP_INIT(cortex_a57); pmc_class_table[n] = &cortex_a57_class_table_descr; break; #endif #if defined(__mips__) case PMC_CPU_MIPS_24K: PMC_MDEP_INIT(mips24k); pmc_class_table[n] = &mips24k_class_table_descr; break; case PMC_CPU_MIPS_74K: PMC_MDEP_INIT(mips74k); pmc_class_table[n] = &mips74k_class_table_descr; break; case PMC_CPU_MIPS_OCTEON: PMC_MDEP_INIT(octeon); pmc_class_table[n] = &octeon_class_table_descr; break; #endif /* __mips__ */ #if defined(__powerpc__) case PMC_CPU_PPC_7450: PMC_MDEP_INIT(ppc7450); pmc_class_table[n] = &ppc7450_class_table_descr; break; case PMC_CPU_PPC_970: PMC_MDEP_INIT(ppc970); pmc_class_table[n] = &ppc970_class_table_descr; break; case PMC_CPU_PPC_E500: PMC_MDEP_INIT(e500); pmc_class_table[n] = &e500_class_table_descr; break; #endif default: /* * Some kind of CPU this version of the library knows nothing * about. This shouldn't happen since the abi version check * should have caught this. */ errno = ENXIO; return (pmc_syscall = -1); } return (0); } const char * pmc_name_of_capability(enum pmc_caps cap) { int i; /* * 'cap' should have a single bit set and should be in * range. */ if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || cap > PMC_CAP_LAST) { errno = EINVAL; return (NULL); } i = ffs(cap); return (pmc_capability_names[i - 1]); } const char * pmc_name_of_class(enum pmc_class pc) { size_t n; for (n = 0; n < PMC_TABLE_SIZE(pmc_class_names); n++) if (pc == pmc_class_names[n].pm_class) return (pmc_class_names[n].pm_name); errno = EINVAL; return (NULL); } const char * pmc_name_of_cputype(enum pmc_cputype cp) { size_t n; for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++) if (cp == pmc_cputype_names[n].pm_cputype) return (pmc_cputype_names[n].pm_name); errno = EINVAL; return (NULL); } const char * pmc_name_of_disposition(enum pmc_disp pd) { if ((int) pd >= PMC_DISP_FIRST && pd <= PMC_DISP_LAST) return (pmc_disposition_names[pd]); errno = EINVAL; return (NULL); } const char * _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) { const struct pmc_event_descr *ev, *evfence; ev = evfence = NULL; if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) { ev = iaf_event_table; evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf); } else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) { switch (cpu) { case PMC_CPU_INTEL_ATOM: ev = atom_event_table; evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom); break; case PMC_CPU_INTEL_ATOM_SILVERMONT: ev = atom_silvermont_event_table; evfence = atom_silvermont_event_table + PMC_EVENT_TABLE_SIZE(atom_silvermont); break; case PMC_CPU_INTEL_CORE: ev = core_event_table; evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core); break; case PMC_CPU_INTEL_CORE2: case PMC_CPU_INTEL_CORE2EXTREME: ev = core2_event_table; evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2); break; case PMC_CPU_INTEL_COREI7: ev = corei7_event_table; evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7); break; case PMC_CPU_INTEL_NEHALEM_EX: ev = nehalem_ex_event_table; evfence = nehalem_ex_event_table + PMC_EVENT_TABLE_SIZE(nehalem_ex); break; case PMC_CPU_INTEL_HASWELL: ev = haswell_event_table; evfence = haswell_event_table + PMC_EVENT_TABLE_SIZE(haswell); break; case PMC_CPU_INTEL_HASWELL_XEON: ev = haswell_xeon_event_table; evfence = haswell_xeon_event_table + PMC_EVENT_TABLE_SIZE(haswell_xeon); break; case PMC_CPU_INTEL_BROADWELL: ev = broadwell_event_table; evfence = broadwell_event_table + PMC_EVENT_TABLE_SIZE(broadwell); break; case PMC_CPU_INTEL_BROADWELL_XEON: ev = broadwell_xeon_event_table; evfence = broadwell_xeon_event_table + PMC_EVENT_TABLE_SIZE(broadwell_xeon); break; case PMC_CPU_INTEL_SKYLAKE: ev = skylake_event_table; evfence = skylake_event_table + PMC_EVENT_TABLE_SIZE(skylake); break; case PMC_CPU_INTEL_SKYLAKE_XEON: ev = skylake_xeon_event_table; evfence = skylake_xeon_event_table + PMC_EVENT_TABLE_SIZE(skylake_xeon); break; case PMC_CPU_INTEL_IVYBRIDGE: ev = ivybridge_event_table; evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge); break; case PMC_CPU_INTEL_IVYBRIDGE_XEON: ev = ivybridge_xeon_event_table; evfence = ivybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(ivybridge_xeon); break; case PMC_CPU_INTEL_SANDYBRIDGE: ev = sandybridge_event_table; evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge); break; case PMC_CPU_INTEL_SANDYBRIDGE_XEON: ev = sandybridge_xeon_event_table; evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon); break; case PMC_CPU_INTEL_WESTMERE: ev = westmere_event_table; evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere); break; case PMC_CPU_INTEL_WESTMERE_EX: ev = westmere_ex_event_table; evfence = westmere_ex_event_table + PMC_EVENT_TABLE_SIZE(westmere_ex); break; default: /* Unknown CPU type. */ break; } } else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) { ev = ucf_event_table; evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf); } else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) { switch (cpu) { case PMC_CPU_INTEL_COREI7: ev = corei7uc_event_table; evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc); break; case PMC_CPU_INTEL_SANDYBRIDGE: ev = sandybridgeuc_event_table; evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc); break; case PMC_CPU_INTEL_WESTMERE: ev = westmereuc_event_table; evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc); break; default: /* Unknown CPU type. */ break; } } else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) { ev = k7_event_table; evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7); } else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { ev = k8_event_table; evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); } else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) { ev = p4_event_table; evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4); } else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) { ev = p5_event_table; evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5); } else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) { ev = p6_event_table; evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6); } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { ev = xscale_event_table; evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); } else if (pe >= PMC_EV_ARMV7_FIRST && pe <= PMC_EV_ARMV7_LAST) { switch (cpu) { case PMC_CPU_ARMV7_CORTEX_A8: ev = cortex_a8_event_table; evfence = cortex_a8_event_table + PMC_EVENT_TABLE_SIZE(cortex_a8); break; case PMC_CPU_ARMV7_CORTEX_A9: ev = cortex_a9_event_table; evfence = cortex_a9_event_table + PMC_EVENT_TABLE_SIZE(cortex_a9); break; default: /* Unknown CPU type. */ break; } } else if (pe >= PMC_EV_ARMV8_FIRST && pe <= PMC_EV_ARMV8_LAST) { switch (cpu) { case PMC_CPU_ARMV8_CORTEX_A53: ev = cortex_a53_event_table; evfence = cortex_a53_event_table + PMC_EVENT_TABLE_SIZE(cortex_a53); break; case PMC_CPU_ARMV8_CORTEX_A57: ev = cortex_a57_event_table; evfence = cortex_a57_event_table + PMC_EVENT_TABLE_SIZE(cortex_a57); break; default: /* Unknown CPU type. */ break; } } else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) { ev = mips24k_event_table; evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k); } else if (pe >= PMC_EV_MIPS74K_FIRST && pe <= PMC_EV_MIPS74K_LAST) { ev = mips74k_event_table; evfence = mips74k_event_table + PMC_EVENT_TABLE_SIZE(mips74k); } else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) { ev = octeon_event_table; evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon); } else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) { ev = ppc7450_event_table; evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450); } else if (pe >= PMC_EV_PPC970_FIRST && pe <= PMC_EV_PPC970_LAST) { ev = ppc970_event_table; evfence = ppc970_event_table + PMC_EVENT_TABLE_SIZE(ppc970); } else if (pe >= PMC_EV_E500_FIRST && pe <= PMC_EV_E500_LAST) { ev = e500_event_table; evfence = e500_event_table + PMC_EVENT_TABLE_SIZE(e500); } else if (pe == PMC_EV_TSC_TSC) { ev = tsc_event_table; evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); } else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) { ev = soft_event_table; evfence = soft_event_table + soft_event_info.pm_nevent; } for (; ev != evfence; ev++) if (pe == ev->pm_ev_code) return (ev->pm_ev_name); return (NULL); } const char * pmc_name_of_event(enum pmc_event pe) { const char *n; if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL) return (n); errno = EINVAL; return (NULL); } const char * pmc_name_of_mode(enum pmc_mode pm) { if ((int) pm >= PMC_MODE_FIRST && pm <= PMC_MODE_LAST) return (pmc_mode_names[pm]); errno = EINVAL; return (NULL); } const char * pmc_name_of_state(enum pmc_state ps) { if ((int) ps >= PMC_STATE_FIRST && ps <= PMC_STATE_LAST) return (pmc_state_names[ps]); errno = EINVAL; return (NULL); } int pmc_ncpu(void) { if (pmc_syscall == -1) { errno = ENXIO; return (-1); } return (cpu_info.pm_ncpu); } int pmc_npmc(int cpu) { if (pmc_syscall == -1) { errno = ENXIO; return (-1); } if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { errno = EINVAL; return (-1); } return (cpu_info.pm_npmc); } int pmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) { int nbytes, npmc; struct pmc_op_getpmcinfo *pmci; if ((npmc = pmc_npmc(cpu)) < 0) return (-1); nbytes = sizeof(struct pmc_op_getpmcinfo) + npmc * sizeof(struct pmc_info); if ((pmci = calloc(1, nbytes)) == NULL) return (-1); pmci->pm_cpu = cpu; if (PMC_CALL(GETPMCINFO, pmci) < 0) { free(pmci); return (-1); } /* kernel<->library, library<->userland interfaces are identical */ *ppmci = (struct pmc_pmcinfo *) pmci; return (0); } int pmc_read(pmc_id_t pmc, pmc_value_t *value) { struct pmc_op_pmcrw pmc_read_op; pmc_read_op.pm_pmcid = pmc; pmc_read_op.pm_flags = PMC_F_OLDVALUE; pmc_read_op.pm_value = -1; if (PMC_CALL(PMCRW, &pmc_read_op) < 0) return (-1); *value = pmc_read_op.pm_value; return (0); } int pmc_release(pmc_id_t pmc) { struct pmc_op_simple pmc_release_args; pmc_release_args.pm_pmcid = pmc; return (PMC_CALL(PMCRELEASE, &pmc_release_args)); } int pmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) { struct pmc_op_pmcrw pmc_rw_op; pmc_rw_op.pm_pmcid = pmc; pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; pmc_rw_op.pm_value = newvalue; if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) return (-1); *oldvaluep = pmc_rw_op.pm_value; return (0); } int pmc_set(pmc_id_t pmc, pmc_value_t value) { struct pmc_op_pmcsetcount sc; sc.pm_pmcid = pmc; sc.pm_count = value; if (PMC_CALL(PMCSETCOUNT, &sc) < 0) return (-1); return (0); } int pmc_start(pmc_id_t pmc) { struct pmc_op_simple pmc_start_args; pmc_start_args.pm_pmcid = pmc; return (PMC_CALL(PMCSTART, &pmc_start_args)); } int pmc_stop(pmc_id_t pmc) { struct pmc_op_simple pmc_stop_args; pmc_stop_args.pm_pmcid = pmc; return (PMC_CALL(PMCSTOP, &pmc_stop_args)); } int pmc_width(pmc_id_t pmcid, uint32_t *width) { unsigned int i; enum pmc_class cl; cl = PMC_ID_TO_CLASS(pmcid); for (i = 0; i < cpu_info.pm_nclass; i++) if (cpu_info.pm_classes[i].pm_class == cl) { *width = cpu_info.pm_classes[i].pm_width; return (0); } errno = EINVAL; return (-1); } int pmc_write(pmc_id_t pmc, pmc_value_t value) { struct pmc_op_pmcrw pmc_write_op; pmc_write_op.pm_pmcid = pmc; pmc_write_op.pm_flags = PMC_F_NEWVALUE; pmc_write_op.pm_value = value; return (PMC_CALL(PMCRW, &pmc_write_op)); } int pmc_writelog(uint32_t userdata) { struct pmc_op_writelog wl; wl.pm_userdata = userdata; return (PMC_CALL(WRITELOG, &wl)); } diff --git a/lib/libpmc/libpmc_pmu_util.c b/lib/libpmc/libpmc_pmu_util.c new file mode 100644 index 000000000000..c2ac3b9e931a --- /dev/null +++ b/lib/libpmc/libpmc_pmu_util.c @@ -0,0 +1,333 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018, Matthew Macy + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pmu-events/pmu-events.h" + +#if defined(__amd64__) +struct pmu_alias { + const char *pa_alias; + const char *pa_name; +}; +static struct pmu_alias pmu_alias_table[] = { + { "UNHALTED_CORE_CYCLES", "CPU_CLK_UNHALTED.THREAD_P_ANY"}, + { "UNHALTED-CORE-CYCLES", "CPU_CLK_UNHALTED.THREAD_P_ANY"}, + { "LLC_MISSES", "LONGEST_LAT_CACHE.MISS"}, + { "LLC-MISSES", "LONGEST_LAT_CACHE.MISS"}, + { "LLC_REFERENCE", "LONGEST_LAT_CACHE.REFERENCE"}, + { "LLC-REFERENCE", "LONGEST_LAT_CACHE.REFERENCE"}, + { "LLC_MISS_RHITM", "mem_load_l3_miss_retired.remote_hitm"}, + { "LLC-MISS-RHITM", "mem_load_l3_miss_retired.remote_hitm"}, + { "RESOURCE_STALL", "RESOURCE_STALLS.ANY"}, + { "RESOURCE_STALLS_ANY", "RESOURCE_STALLS.ANY"}, + { "BRANCH_INSTRUCTION_RETIRED", "BR_INST_RETIRED.ALL_BRANCHES"}, + { "BRANCH-INSTRUCTION-RETIRED", "BR_INST_RETIRED.ALL_BRANCHES"}, + { "BRANCH_MISSES_RETIRED", "BR_MISP_RETIRED.ALL_BRANCHES"}, + { "BRANCH-MISSES-RETIRED", "BR_MISP_RETIRED.ALL_BRANCHES"}, + { NULL, NULL }, +}; + +static const char * +pmu_alias_get(const char *name) +{ + struct pmu_alias *pa; + + for (pa = pmu_alias_table; pa->pa_alias != NULL; pa++) + if (strcasecmp(name, pa->pa_alias) == 0) + return (pa->pa_name); + return (name); +} + +struct pmu_event_desc { + uint64_t ped_period; + uint64_t ped_offcore_rsp; + uint32_t ped_event; + uint32_t ped_frontend; + uint32_t ped_ldlat; + uint32_t ped_config1; + uint8_t ped_umask; + uint8_t ped_cmask; + uint8_t ped_any; + uint8_t ped_inv; + uint8_t ped_edge; + uint8_t ped_fc_mask; + uint8_t ped_ch_mask; +}; + +static const struct pmu_events_map * +pmu_events_map_get(void) +{ + size_t s; + char buf[64]; + const struct pmu_events_map *pme; + + if (sysctlbyname("kern.hwpmc.cpuid", (void *)NULL, &s, + (void *)NULL, 0) == -1) + return (NULL); + if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, + (void *)NULL, 0) == -1) + return (NULL); + for (pme = pmu_events_map; pme->cpuid != NULL; pme++) + if (strcmp(buf, pme->cpuid) == 0) + return (pme); + return (NULL); +} + +static const struct pmu_event * +pmu_event_get(const char *event_name, int *idx) +{ + const struct pmu_events_map *pme; + const struct pmu_event *pe; + int i; + + if ((pme = pmu_events_map_get()) == NULL) + return (NULL); + for (i = 0, pe = pme->table; pe->name || pe->desc || pe->event; pe++, i++) { + if (pe->name == NULL) + continue; + if (strcasecmp(pe->name, event_name) == 0) { + if (idx) + *idx = i; + return (pe); + } + } + return (NULL); +} + +const char * +pmu_event_get_by_idx(int idx) +{ + const struct pmu_events_map *pme; + const struct pmu_event *pe; + int i; + + if ((pme = pmu_events_map_get()) == NULL) + return (NULL); + for (i = 0, pe = pme->table; (pe->name || pe->desc || pe->event) && i < idx; pe++, i++) + ; + return (pe->name); +} + +static int +pmu_parse_event(struct pmu_event_desc *ped, const char *eventin) +{ + char *event; + char *kvp, *key, *value; + char *debug; + + if ((event = strdup(eventin)) == NULL) + return (ENOMEM); + bzero(ped, sizeof(*ped)); + while ((kvp = strsep(&event, ",")) != NULL) { + key = strsep(&kvp, "="); + if (key == NULL) + abort(); + value = kvp; + if (strcmp(key, "umask") == 0) + ped->ped_umask = strtol(value, NULL, 16); + else if (strcmp(key, "event") == 0) + ped->ped_event = strtol(value, NULL, 16); + else if (strcmp(key, "period") == 0) + ped->ped_period = strtol(value, NULL, 10); + else if (strcmp(key, "offcore_rsp") == 0) + ped->ped_offcore_rsp = strtol(value, NULL, 16); + else if (strcmp(key, "any") == 0) + ped->ped_any = strtol(value, NULL, 10); + else if (strcmp(key, "cmask") == 0) + ped->ped_cmask = strtol(value, NULL, 10); + else if (strcmp(key, "inv") == 0) + ped->ped_inv = strtol(value, NULL, 10); + else if (strcmp(key, "edge") == 0) + ped->ped_edge = strtol(value, NULL, 10); + else if (strcmp(key, "frontend") == 0) + ped->ped_frontend = strtol(value, NULL, 16); + else if (strcmp(key, "ldlat") == 0) + ped->ped_ldlat = strtol(value, NULL, 16); + else if (strcmp(key, "fc_mask") == 0) + ped->ped_fc_mask = strtol(value, NULL, 16); + else if (strcmp(key, "ch_mask") == 0) + ped->ped_ch_mask = strtol(value, NULL, 16); + else if (strcmp(key, "config1") == 0) + ped->ped_config1 = strtol(value, NULL, 16); + else { + debug = getenv("PMUDEBUG"); + if (debug != NULL && strcmp(debug, "true") == 0 && value != NULL) + printf("unrecognized kvpair: %s:%s\n", key, value); + } + } + free(event); + return (0); +} + +uint64_t +pmc_pmu_sample_rate_get(const char *event_name) +{ + const struct pmu_event *pe; + struct pmu_event_desc ped; + + event_name = pmu_alias_get(event_name); + if ((pe = pmu_event_get(event_name, NULL)) == NULL) + return (DEFAULT_SAMPLE_COUNT); + if (pe->alias && (pe = pmu_event_get(pe->alias, NULL)) == NULL) + return (DEFAULT_SAMPLE_COUNT); + if (pe->event == NULL) + return (DEFAULT_SAMPLE_COUNT); + if (pmu_parse_event(&ped, pe->event)) + return (DEFAULT_SAMPLE_COUNT); + return (ped.ped_period); +} + +int +pmc_pmu_enabled(void) +{ + + return (pmu_events_map_get() != NULL); +} + +void +pmc_pmu_print_counters(void) +{ + const struct pmu_events_map *pme; + const struct pmu_event *pe; + struct pmu_event_desc ped; + char *debug; + int do_debug; + + debug = getenv("PMUDEBUG"); + do_debug = 0; + + if (debug != NULL && strcmp(debug, "true") == 0) + do_debug = 1; + if ((pme = pmu_events_map_get()) == NULL) + return; + for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { + if (pe->name == NULL) + continue; + printf("\t%s\n", pe->name); + if (do_debug) + pmu_parse_event(&ped, pe->event); + } +} + +void +pmc_pmu_print_counter_desc(const char *ev) +{ + const struct pmu_events_map *pme; + const struct pmu_event *pe; + + if ((pme = pmu_events_map_get()) == NULL) + return; + for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { + if (pe->name == NULL) + continue; + if (strcasestr(pe->name, ev) != NULL && + pe->desc != NULL) + printf("%s:\t%s\n", pe->name, pe->desc); + } +} + +void +pmc_pmu_print_counter_desc_long(const char *ev) +{ + const struct pmu_events_map *pme; + const struct pmu_event *pe; + + if ((pme = pmu_events_map_get()) == NULL) + return; + for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { + if (pe->name == NULL) + continue; + if (strcasestr(pe->name, ev) != NULL) { + if (pe->long_desc != NULL) + printf("%s:\n%s\n", pe->name, pe->long_desc); + else if (pe->desc != NULL) + printf("%s:\t%s\n", pe->name, pe->desc); + } + } +} + +int +pmc_pmu_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm) +{ + const struct pmu_event *pe; + struct pmu_event_desc ped; + struct pmc_md_iap_op_pmcallocate *iap; + int idx; + + iap = &pm->pm_md.pm_iap; + bzero(iap, sizeof(*iap)); + event_name = pmu_alias_get(event_name); + if ((pe = pmu_event_get(event_name, &idx)) == NULL) + return (ENOENT); + if (pe->alias && (pe = pmu_event_get(pe->alias, &idx)) == NULL) + return (ENOENT); + if (pe->event == NULL) + return (ENOENT); + if (pmu_parse_event(&ped, pe->event)) + return (ENOENT); + + pm->pm_class = PMC_CLASS_IAP; + pm->pm_ev = idx; + iap->pm_iap_config |= IAP_EVSEL(ped.ped_event); + iap->pm_iap_config |= IAP_UMASK(ped.ped_umask); + iap->pm_iap_config |= IAP_CMASK(ped.ped_cmask); + iap->pm_iap_rsp = ped.ped_offcore_rsp; + + iap->pm_iap_config |= (IAP_USR | IAP_OS); + if (ped.ped_edge) + iap->pm_iap_config |= IAP_EDGE; + if (ped.ped_any) + iap->pm_iap_config |= IAP_ANY; + if (ped.ped_inv) + iap->pm_iap_config |= IAP_EDGE; + if (pm->pm_caps & PMC_CAP_INTERRUPT) + iap->pm_iap_config |= IAP_INT; + return (0); +} + +#else +uint64_t pmc_pmu_sample_rate_get(const char *event_name __unused) { return (DEFAULT_SAMPLE_COUNT); } +void pmc_pmu_print_counters(void) {} +void pmc_pmu_print_counter_desc(const char *e __unused) {} +void pmc_pmu_print_counter_desc_long(const char *e __unused) {} +int pmc_pmu_enabled(void) { return (0); } +int pmc_pmu_pmcallocate(const char *e __unused, struct pmc_op_pmcallocate *p __unused) { return (EOPNOTSUPP); } +const char *pmu_event_get_by_idx(int idx __unused) { return (NULL); } + +#endif diff --git a/lib/libpmc/pmc.h b/lib/libpmc/pmc.h index 5e4b89e4ea05..3a72930b9e1d 100644 --- a/lib/libpmc/pmc.h +++ b/lib/libpmc/pmc.h @@ -1,117 +1,125 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2003,2004 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _PMC_H_ #define _PMC_H_ #include #include #include /* * Driver statistics. */ struct pmc_driverstats { unsigned int pm_intr_ignored; /* #interrupts ignored */ unsigned int pm_intr_processed; /* #interrupts processed */ unsigned int pm_intr_bufferfull; /* #interrupts with ENOSPC */ unsigned int pm_syscalls; /* #syscalls */ unsigned int pm_syscall_errors; /* #syscalls with errors */ unsigned int pm_buffer_requests; /* #buffer requests */ unsigned int pm_buffer_requests_failed; /* #failed buffer requests */ unsigned int pm_log_sweeps; /* #sample buffer processing passes */ }; /* * CPU information. */ struct pmc_cpuinfo { enum pmc_cputype pm_cputype; /* the kind of CPU */ uint32_t pm_ncpu; /* number of CPUs */ uint32_t pm_npmc; /* #PMCs per CPU */ uint32_t pm_nclass; /* #classes of PMCs */ struct pmc_classinfo pm_classes[PMC_CLASS_MAX]; }; /* * Current PMC state. */ struct pmc_pmcinfo { int32_t pm_cpu; /* CPU number */ struct pmc_info pm_pmcs[]; /* NPMC structs */ }; /* * Prototypes */ __BEGIN_DECLS int pmc_allocate(const char *_ctrspec, enum pmc_mode _mode, uint32_t _flags, int _cpu, pmc_id_t *_pmcid); int pmc_attach(pmc_id_t _pmcid, pid_t _pid); int pmc_capabilities(pmc_id_t _pmc, uint32_t *_caps); int pmc_configure_logfile(int _fd); int pmc_flush_logfile(void); int pmc_close_logfile(void); int pmc_detach(pmc_id_t _pmcid, pid_t _pid); int pmc_disable(int _cpu, int _pmc); int pmc_enable(int _cpu, int _pmc); int pmc_get_driver_stats(struct pmc_driverstats *_gms); int pmc_get_msr(pmc_id_t _pmc, uint32_t *_msr); int pmc_init(void); int pmc_read(pmc_id_t _pmc, pmc_value_t *_value); int pmc_release(pmc_id_t _pmc); int pmc_rw(pmc_id_t _pmc, pmc_value_t _newvalue, pmc_value_t *_oldvalue); int pmc_set(pmc_id_t _pmc, pmc_value_t _value); int pmc_start(pmc_id_t _pmc); int pmc_stop(pmc_id_t _pmc); int pmc_width(pmc_id_t _pmc, uint32_t *_width); int pmc_write(pmc_id_t _pmc, pmc_value_t _value); int pmc_writelog(uint32_t _udata); int pmc_ncpu(void); int pmc_npmc(int _cpu); int pmc_cpuinfo(const struct pmc_cpuinfo **_cpu_info); int pmc_pmcinfo(int _cpu, struct pmc_pmcinfo **_pmc_info); const char *pmc_name_of_capability(enum pmc_caps _c); const char *pmc_name_of_class(enum pmc_class _pc); const char *pmc_name_of_cputype(enum pmc_cputype _cp); const char *pmc_name_of_disposition(enum pmc_disp _pd); const char *pmc_name_of_event(enum pmc_event _pe); const char *pmc_name_of_mode(enum pmc_mode _pm); const char *pmc_name_of_state(enum pmc_state _ps); int pmc_event_names_of_class(enum pmc_class _cl, const char ***_eventnames, int *_nevents); + +int pmc_pmu_enabled(void); +void pmc_pmu_print_counters(void); +void pmc_pmu_print_counter_desc(const char *); +void pmc_pmu_print_counter_desc_long(const char *); +uint64_t pmc_pmu_sample_rate_get(const char *); +int pmc_pmu_pmcallocate(const char *, struct pmc_op_pmcallocate *); +const char *pmu_event_get_by_idx(int idx); __END_DECLS #endif diff --git a/lib/libpmc/pmclog.3 b/lib/libpmc/pmclog.3 index 91c7222da7f2..d60e97085831 100644 --- a/lib/libpmc/pmclog.3 +++ b/lib/libpmc/pmclog.3 @@ -1,320 +1,321 @@ .\" Copyright (c) 2005-2006 Joseph Koshy. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd March 26, 2006 .Dt PMCLOG 3 .Os .Sh NAME .Nm pmclog_open , .Nm pmclog_close , .Nm pmclog_read , .Nm pmclog_feed .Nd parse event log data generated by .Xr hwpmc 4 .Sh LIBRARY .Lb libpmc .Sh SYNOPSIS .In pmclog.h .Ft "void *" .Fn pmclog_open "int fd" .Ft void .Fn pmclog_close "void *cookie" .Ft int .Fn pmclog_read "void *cookie" "struct pmclog_ev *ev" .Ft int .Fn pmclog_feed "void *cookie" "char *data" "int len" .Sh DESCRIPTION These functions provide a way for application programs to extract events from an event stream generated by .Xr hwpmc 4 . .Pp A new event log parser is allocated using .Fn pmclog_open . Argument .Fa fd may be a file descriptor opened for reading if the event stream is present in a file, or the constant .Dv PMCLOG_FD_NONE for an event stream present in memory. This function returns a cookie that is passed into the other functions in this API set. .Pp Function .Fn pmclog_read returns the next available event in the event stream associated with argument .Fa cookie . Argument .Fa ev points to an event descriptor that which will contain the result of a successfully parsed event. .Pp An event descriptor returned by .Fn pmclog_read has the following structure: .Bd -literal struct pmclog_ev { enum pmclog_state pl_state; /* parser state after 'get_event()' */ off_t pl_offset; /* byte offset in stream */ size_t pl_count; /* count of records so far */ struct timespec pl_ts; /* log entry timestamp */ enum pmclog_type pl_type; /* log entry kind */ union { /* log entry data */ + struct pmclog_ev_callchain pl_cc; struct pmclog_ev_closelog pl_cl; struct pmclog_ev_dropnotify pl_d; struct pmclog_ev_initialize pl_i; struct pmclog_ev_map_in pl_mi; struct pmclog_ev_map_out pl_mo; - struct pmclog_ev_pcsample pl_s; struct pmclog_ev_pmcallocate pl_a; + struct pmclog_ev_pmcallocatedyn pl_ad; struct pmclog_ev_pmcattach pl_t; struct pmclog_ev_pmcdetach pl_d; struct pmclog_ev_proccsw pl_c; struct pmclog_ev_procexec pl_x; struct pmclog_ev_procexit pl_e; struct pmclog_ev_procfork pl_f; struct pmclog_ev_sysexit pl_e; struct pmclog_ev_userdata pl_u; } pl_u; }; .Ed .Pp The current state of the parser is recorded in .Va pl_state . This field can take on the following values: .Bl -tag -width ".Dv PMCLOG_REQUIRE_DATA" .It Dv PMCLOG_EOF (For file based parsers only) An end-of-file condition was encountered on the configured file descriptor. .It Dv PMCLOG_ERROR An error occurred during parsing. .It Dv PMCLOG_OK A complete event record was read into .Fa *ev . .It Dv PMCLOG_REQUIRE_DATA There was insufficient data in the event stream to assemble a complete event record. For memory based parsers, more data can be fed to the parser using function .Fn pmclog_feed . For file based parsers, function .Fn pmclog_read may be retried when data is available on the configured file descriptor. .El .Pp The rest of the event structure is valid only if field .Va pl_state contains .Dv PMCLOG_OK . Field .Va pl_offset contains the offset of the current record in the byte stream. Field .Va pl_count contains the serial number of this event. Field .Va pl_ts contains a timestamp with the system time when the event occurred. Field .Va pl_type denotes the kind of the event returned in argument .Fa *ev and is one of the following: .Bl -tag -width ".Dv PMCLOG_TYPE_PMCALLOCATE" .It Dv PMCLOG_TYPE_CLOSELOG A marker indicating a successful close of a log file. This record will be the last record of a log file. .It Dv PMCLOG_TYPE_DROPNOTIFY A marker indicating that .Xr hwpmc 4 had to drop data due to a resource constraint. .It Dv PMCLOG_TYPE_INITIALIZE An initialization record. This is the first record in a log file. .It Dv PMCLOG_TYPE_MAP_IN A record describing the introduction of a mapping to an executable object by a .Xr kldload 2 or .Xr mmap 2 system call. .It Dv PMCLOG_TYPE_MAP_OUT A record describing the removal of a mapping to an executable object by a .Xr kldunload 2 or .Xr munmap 2 system call. .It Dv PMCLOG_TYPE_PCSAMPLE A record containing an instruction pointer sample. .It Dv PMCLOG_TYPE_PMCALLOCATE A record describing a PMC allocation operation. .It Dv PMCLOG_TYPE_PMCATTACH A record describing a PMC attach operation. .It Dv PMCLOG_TYPE_PMCDETACH A record describing a PMC detach operation. .It Dv PMCLOG_TYPE_PROCCSW A record describing a PMC reading at the time of a process context switch. .It Dv PMCLOG_TYPE_PROCEXEC A record describing an .Xr execve 2 by a target process. .It Dv PMCLOG_TYPE_PROCEXIT A record describing the accumulated PMC reading for a process at the time of .Xr _exit 2 . .It Dv PMCLOG_TYPE_PROCFORK A record describing a .Xr fork 2 by a target process. .It Dv PMCLOG_TYPE_SYSEXIT A record describing a process exit, sent to processes owning system-wide sampling PMCs. .It Dv PMCLOG_TYPE_USERDATA A record containing user data. .El .Pp Function .Fn pmclog_feed is used with parsers configured to parse memory based event streams. It is intended to be called when function .Fn pmclog_read indicates the need for more data by a returning .Dv PMCLOG_REQUIRE_DATA in field .Va pl_state of its event structure argument. Argument .Fa data points to the start of a memory buffer containing fresh event data. Argument .Fa len indicates the number of data bytes available. The memory range .Bq Fa data , Fa data No + Fa len must remain valid till the next time .Fn pmclog_read returns an error. It is an error to use .Fn pmclog_feed on a parser configured to parse file data. .Pp Function .Fn pmclog_close releases the internal state allocated by a prior call to .Fn pmclog_open . .Sh RETURN VALUES Function .Fn pmclog_open will return a .No non- Ns Dv NULL value if successful or .Dv NULL otherwise. .Pp Function .Fn pmclog_read will return 0 in case a complete event record was successfully read, or will return \-1 and will set the .Va pl_state field of the event record to the appropriate code in case of an error. .Pp Function .Fn pmclog_feed will return 0 on success or \-1 in case of failure. .Sh EXAMPLES A template for using the log file parsing API is shown below in pseudocode: .Bd -literal void *parser; /* cookie */ struct pmclog_ev ev; /* parsed event */ int fd; /* file descriptor */ fd = open(filename, O_RDONLY); /* open log file */ parser = pmclog_open(fd); /* initialize parser */ if (parser == NULL) --handle an out of memory error--; /* read and parse data */ while (pmclog_read(parser, &ev) == 0) { assert(ev.pl_state == PMCLOG_OK); /* process the event */ switch (ev.pl_type) { case PMCLOG_TYPE_ALLOCATE: --process a pmc allocation record-- break; case PMCLOG_TYPE_PROCCSW: --process a thread context switch record-- break; - case PMCLOG_TYPE_PCSAMPLE: - --process a PC sample-- + case PMCLOG_TYPE_CALLCHAIN: + --process a callchain sample-- break; --and so on-- } } /* examine parser state */ switch (ev.pl_state) { case PMCLOG_EOF: --normal termination-- break; case PMCLOG_ERROR: --look at errno here-- break; case PMCLOG_REQUIRE_DATA: --arrange for more data to be available for parsing-- break; default: assert(0); /*NOTREACHED*/ } pmclog_close(parser); /* cleanup */ .Ed .Sh ERRORS A call to .Fn pmclog_init_parser may fail with any of the errors returned by .Xr malloc 3 . .Pp A call to .Fn pmclog_read for a file based parser may fail with any of the errors returned by .Xr read 2 . .Sh SEE ALSO .Xr read 2 , .Xr malloc 3 , .Xr pmc 3 , .Xr hwpmc 4 , .Xr pmcstat 8 .Sh HISTORY The .Nm pmclog API .Ud It first appeared in .Fx 6.0 . diff --git a/lib/libpmc/pmclog.c b/lib/libpmc/pmclog.c index dd91a68d864f..8e0504b290f2 100644 --- a/lib/libpmc/pmclog.c +++ b/lib/libpmc/pmclog.c @@ -1,591 +1,595 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2007 Joseph Koshy * Copyright (c) 2007 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by A. Joseph Koshy under * sponsorship from the FreeBSD Foundation and Google, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include "libpmcinternal.h" #define PMCLOG_BUFFER_SIZE 4096 /* * API NOTES * * The pmclog(3) API is oriented towards parsing an event stream in * "realtime", i.e., from an data source that may or may not preserve * record boundaries -- for example when the data source is elsewhere * on a network. The API allows data to be fed into the parser zero * or more bytes at a time. * * The state for a log file parser is maintained in a 'struct * pmclog_parse_state'. Parser invocations are done by calling * 'pmclog_read()'; this function will inform the caller when a * complete event is parsed. * * The parser first assembles a complete log file event in an internal * work area (see "ps_saved" below). Once a complete log file event * is read, the parser then parses it and converts it to an event * descriptor usable by the client. We could possibly avoid this two * step process by directly parsing the input log to set fields in the * event record. However the parser's state machine would get * insanely complicated, and this code is unlikely to be used in * performance critical paths. */ enum pmclog_parser_state { PL_STATE_NEW_RECORD, /* in-between records */ PL_STATE_EXPECTING_HEADER, /* header being read */ PL_STATE_PARTIAL_RECORD, /* header present but not the record */ PL_STATE_ERROR /* parsing error encountered */ }; struct pmclog_parse_state { enum pmclog_parser_state ps_state; enum pmc_cputype ps_arch; /* log file architecture */ uint32_t ps_version; /* hwpmc version */ int ps_initialized; /* whether initialized */ int ps_count; /* count of records processed */ off_t ps_offset; /* stream byte offset */ union pmclog_entry ps_saved; /* saved partial log entry */ int ps_svcount; /* #bytes saved */ int ps_fd; /* active fd or -1 */ char *ps_buffer; /* scratch buffer if fd != -1 */ char *ps_data; /* current parse pointer */ size_t ps_len; /* length of buffered data */ }; #define PMCLOG_HEADER_FROM_SAVED_STATE(PS) \ (* ((uint32_t *) &(PS)->ps_saved)) #define PMCLOG_INITIALIZE_READER(LE,A) LE = (uint32_t *) &(A) #define PMCLOG_READ32(LE,V) do { \ (V) = *(LE)++; \ } while (0) #define PMCLOG_READ64(LE,V) do { \ uint64_t _v; \ _v = (uint64_t) *(LE)++; \ _v |= ((uint64_t) *(LE)++) << 32; \ (V) = _v; \ } while (0) #define PMCLOG_READSTRING(LE,DST,LEN) strlcpy((DST), (char *) (LE), (LEN)) /* * Assemble a log record from '*len' octets starting from address '*data'. * Update 'data' and 'len' to reflect the number of bytes consumed. * * '*data' is potentially an unaligned address and '*len' octets may * not be enough to complete a event record. */ static enum pmclog_parser_state pmclog_get_record(struct pmclog_parse_state *ps, char **data, ssize_t *len) { int avail, copylen, recordsize, used; uint32_t h; const int HEADERSIZE = sizeof(uint32_t); char *src, *dst; if ((avail = *len) <= 0) return (ps->ps_state = PL_STATE_ERROR); src = *data; h = used = 0; if (ps->ps_state == PL_STATE_NEW_RECORD) ps->ps_svcount = 0; dst = (char *) &ps->ps_saved + ps->ps_svcount; switch (ps->ps_state) { case PL_STATE_NEW_RECORD: /* * Transitions: * * Case A: avail < headersize * -> 'expecting header' * * Case B: avail >= headersize * B.1: avail < recordsize * -> 'partial record' * B.2: avail >= recordsize * -> 'new record' */ copylen = avail < HEADERSIZE ? avail : HEADERSIZE; bcopy(src, dst, copylen); ps->ps_svcount = used = copylen; if (copylen < HEADERSIZE) { ps->ps_state = PL_STATE_EXPECTING_HEADER; goto done; } src += copylen; dst += copylen; h = PMCLOG_HEADER_FROM_SAVED_STATE(ps); recordsize = PMCLOG_HEADER_TO_LENGTH(h); if (recordsize <= 0) goto error; if (recordsize <= avail) { /* full record available */ bcopy(src, dst, recordsize - copylen); ps->ps_svcount = used = recordsize; goto done; } /* header + a partial record is available */ bcopy(src, dst, avail - copylen); ps->ps_svcount = used = avail; ps->ps_state = PL_STATE_PARTIAL_RECORD; break; case PL_STATE_EXPECTING_HEADER: /* * Transitions: * * Case C: avail+saved < headersize * -> 'expecting header' * * Case D: avail+saved >= headersize * D.1: avail+saved < recordsize * -> 'partial record' * D.2: avail+saved >= recordsize * -> 'new record' * (see PARTIAL_RECORD handling below) */ if (avail + ps->ps_svcount < HEADERSIZE) { bcopy(src, dst, avail); ps->ps_svcount += avail; used = avail; break; } used = copylen = HEADERSIZE - ps->ps_svcount; bcopy(src, dst, copylen); src += copylen; dst += copylen; avail -= copylen; ps->ps_svcount += copylen; /*FALLTHROUGH*/ case PL_STATE_PARTIAL_RECORD: /* * Transitions: * * Case E: avail+saved < recordsize * -> 'partial record' * * Case F: avail+saved >= recordsize * -> 'new record' */ h = PMCLOG_HEADER_FROM_SAVED_STATE(ps); recordsize = PMCLOG_HEADER_TO_LENGTH(h); if (recordsize <= 0) goto error; if (avail + ps->ps_svcount < recordsize) { copylen = avail; ps->ps_state = PL_STATE_PARTIAL_RECORD; } else { copylen = recordsize - ps->ps_svcount; ps->ps_state = PL_STATE_NEW_RECORD; } bcopy(src, dst, copylen); ps->ps_svcount += copylen; used += copylen; break; default: goto error; } done: *data += used; *len -= used; return ps->ps_state; error: ps->ps_state = PL_STATE_ERROR; return ps->ps_state; } /* * Get an event from the stream pointed to by '*data'. '*len' * indicates the number of bytes available to parse. Arguments * '*data' and '*len' are updated to indicate the number of bytes * consumed. */ static int pmclog_get_event(void *cookie, char **data, ssize_t *len, struct pmclog_ev *ev) { int evlen, pathlen; - uint32_t h, *le, npc; + uint32_t h, *le, npc, noop; enum pmclog_parser_state e; struct pmclog_parse_state *ps; ps = (struct pmclog_parse_state *) cookie; assert(ps->ps_state != PL_STATE_ERROR); if ((e = pmclog_get_record(ps,data,len)) == PL_STATE_ERROR) { ev->pl_state = PMCLOG_ERROR; + printf("state error\n"); return -1; } if (e != PL_STATE_NEW_RECORD) { ev->pl_state = PMCLOG_REQUIRE_DATA; return -1; } PMCLOG_INITIALIZE_READER(le, ps->ps_saved); PMCLOG_READ32(le,h); if (!PMCLOG_HEADER_CHECK_MAGIC(h)) { + printf("bad magic\n"); ps->ps_state = PL_STATE_ERROR; ev->pl_state = PMCLOG_ERROR; return -1; } /* copy out the time stamp */ PMCLOG_READ32(le,ev->pl_ts.tv_sec); PMCLOG_READ32(le,ev->pl_ts.tv_nsec); evlen = PMCLOG_HEADER_TO_LENGTH(h); #define PMCLOG_GET_PATHLEN(P,E,TYPE) do { \ (P) = (E) - offsetof(struct TYPE, pl_pathname); \ if ((P) > PATH_MAX || (P) < 0) \ goto error; \ } while (0) #define PMCLOG_GET_CALLCHAIN_SIZE(SZ,E) do { \ (SZ) = ((E) - offsetof(struct pmclog_callchain, pl_pc)) \ / sizeof(uintfptr_t); \ } while (0); switch (ev->pl_type = PMCLOG_HEADER_TO_TYPE(h)) { case PMCLOG_TYPE_CALLCHAIN: PMCLOG_READ32(le,ev->pl_u.pl_cc.pl_pid); PMCLOG_READ32(le,ev->pl_u.pl_cc.pl_tid); PMCLOG_READ32(le,ev->pl_u.pl_cc.pl_pmcid); PMCLOG_READ32(le,ev->pl_u.pl_cc.pl_cpuflags); PMCLOG_READ32(le,ev->pl_u.pl_cc.pl_cpuflags2); PMCLOG_GET_CALLCHAIN_SIZE(ev->pl_u.pl_cc.pl_npc,evlen); for (npc = 0; npc < ev->pl_u.pl_cc.pl_npc; npc++) PMCLOG_READADDR(le,ev->pl_u.pl_cc.pl_pc[npc]); for (;npc < PMC_CALLCHAIN_DEPTH_MAX; npc++) ev->pl_u.pl_cc.pl_pc[npc] = (uintfptr_t) 0; break; case PMCLOG_TYPE_CLOSELOG: ev->pl_state = PMCLOG_EOF; return (-1); case PMCLOG_TYPE_DROPNOTIFY: /* nothing to do */ break; case PMCLOG_TYPE_INITIALIZE: PMCLOG_READ32(le,ev->pl_u.pl_i.pl_version); PMCLOG_READ32(le,ev->pl_u.pl_i.pl_arch); ps->ps_version = ev->pl_u.pl_i.pl_version; ps->ps_arch = ev->pl_u.pl_i.pl_arch; ps->ps_initialized = 1; break; case PMCLOG_TYPE_MAP_IN: PMCLOG_GET_PATHLEN(pathlen,evlen,pmclog_map_in); PMCLOG_READ32(le,ev->pl_u.pl_mi.pl_pid); PMCLOG_READADDR(le,ev->pl_u.pl_mi.pl_start); PMCLOG_READSTRING(le, ev->pl_u.pl_mi.pl_pathname, pathlen); break; case PMCLOG_TYPE_MAP_OUT: PMCLOG_READ32(le,ev->pl_u.pl_mo.pl_pid); PMCLOG_READADDR(le,ev->pl_u.pl_mo.pl_start); PMCLOG_READADDR(le,ev->pl_u.pl_mo.pl_end); break; - case PMCLOG_TYPE_PCSAMPLE: - PMCLOG_READ32(le,ev->pl_u.pl_s.pl_pid); - PMCLOG_READADDR(le,ev->pl_u.pl_s.pl_pc); - PMCLOG_READ32(le,ev->pl_u.pl_s.pl_pmcid); - PMCLOG_READ32(le,ev->pl_u.pl_s.pl_usermode); - PMCLOG_READ32(le,ev->pl_u.pl_s.pl_tid); - break; case PMCLOG_TYPE_PMCALLOCATE: PMCLOG_READ32(le,ev->pl_u.pl_a.pl_pmcid); PMCLOG_READ32(le,ev->pl_u.pl_a.pl_event); PMCLOG_READ32(le,ev->pl_u.pl_a.pl_flags); - if ((ev->pl_u.pl_a.pl_evname = + PMCLOG_READ32(le,noop); + ev->pl_u.pl_a.pl_evname = pmu_event_get_by_idx(ev->pl_u.pl_a.pl_event); + if (ev->pl_u.pl_a.pl_evname != NULL) + break; + else if ((ev->pl_u.pl_a.pl_evname = _pmc_name_of_event(ev->pl_u.pl_a.pl_event, ps->ps_arch)) - == NULL) + == NULL) { + printf("unknown event\n"); goto error; + } break; case PMCLOG_TYPE_PMCALLOCATEDYN: PMCLOG_READ32(le,ev->pl_u.pl_ad.pl_pmcid); PMCLOG_READ32(le,ev->pl_u.pl_ad.pl_event); PMCLOG_READ32(le,ev->pl_u.pl_ad.pl_flags); PMCLOG_READSTRING(le,ev->pl_u.pl_ad.pl_evname,PMC_NAME_MAX); break; case PMCLOG_TYPE_PMCATTACH: PMCLOG_GET_PATHLEN(pathlen,evlen,pmclog_pmcattach); PMCLOG_READ32(le,ev->pl_u.pl_t.pl_pmcid); PMCLOG_READ32(le,ev->pl_u.pl_t.pl_pid); PMCLOG_READSTRING(le,ev->pl_u.pl_t.pl_pathname,pathlen); break; case PMCLOG_TYPE_PMCDETACH: PMCLOG_READ32(le,ev->pl_u.pl_d.pl_pmcid); PMCLOG_READ32(le,ev->pl_u.pl_d.pl_pid); break; case PMCLOG_TYPE_PROCCSW: PMCLOG_READ32(le,ev->pl_u.pl_c.pl_pmcid); PMCLOG_READ64(le,ev->pl_u.pl_c.pl_value); PMCLOG_READ32(le,ev->pl_u.pl_c.pl_pid); PMCLOG_READ32(le,ev->pl_u.pl_c.pl_tid); break; case PMCLOG_TYPE_PROCEXEC: PMCLOG_GET_PATHLEN(pathlen,evlen,pmclog_procexec); PMCLOG_READ32(le,ev->pl_u.pl_x.pl_pid); - PMCLOG_READADDR(le,ev->pl_u.pl_x.pl_entryaddr); PMCLOG_READ32(le,ev->pl_u.pl_x.pl_pmcid); + PMCLOG_READ32(le,noop); + PMCLOG_READADDR(le,ev->pl_u.pl_x.pl_entryaddr); PMCLOG_READSTRING(le,ev->pl_u.pl_x.pl_pathname,pathlen); break; case PMCLOG_TYPE_PROCEXIT: PMCLOG_READ32(le,ev->pl_u.pl_e.pl_pmcid); - PMCLOG_READ64(le,ev->pl_u.pl_e.pl_value); PMCLOG_READ32(le,ev->pl_u.pl_e.pl_pid); + PMCLOG_READ32(le,noop); + PMCLOG_READ64(le,ev->pl_u.pl_e.pl_value); break; case PMCLOG_TYPE_PROCFORK: PMCLOG_READ32(le,ev->pl_u.pl_f.pl_oldpid); PMCLOG_READ32(le,ev->pl_u.pl_f.pl_newpid); break; case PMCLOG_TYPE_SYSEXIT: PMCLOG_READ32(le,ev->pl_u.pl_se.pl_pid); break; case PMCLOG_TYPE_USERDATA: PMCLOG_READ32(le,ev->pl_u.pl_u.pl_userdata); break; default: /* unknown record type */ ps->ps_state = PL_STATE_ERROR; ev->pl_state = PMCLOG_ERROR; return (-1); } ev->pl_offset = (ps->ps_offset += evlen); ev->pl_count = (ps->ps_count += 1); ev->pl_state = PMCLOG_OK; return 0; error: ev->pl_state = PMCLOG_ERROR; ps->ps_state = PL_STATE_ERROR; return -1; } /* * Extract and return the next event from the byte stream. * * Returns 0 and sets the event's state to PMCLOG_OK in case an event * was successfully parsed. Otherwise this function returns -1 and * sets the event's state to one of PMCLOG_REQUIRE_DATA (if more data * is needed) or PMCLOG_EOF (if an EOF was seen) or PMCLOG_ERROR if * a parse error was encountered. */ int pmclog_read(void *cookie, struct pmclog_ev *ev) { int retval; ssize_t nread; struct pmclog_parse_state *ps; ps = (struct pmclog_parse_state *) cookie; if (ps->ps_state == PL_STATE_ERROR) { ev->pl_state = PMCLOG_ERROR; return -1; } /* * If there isn't enough data left for a new event try and get * more data. */ if (ps->ps_len == 0) { ev->pl_state = PMCLOG_REQUIRE_DATA; /* * If we have a valid file descriptor to read from, attempt * to read from that. This read may return with an error, * (which may be EAGAIN or other recoverable error), or * can return EOF. */ if (ps->ps_fd != PMCLOG_FD_NONE) { refill: nread = read(ps->ps_fd, ps->ps_buffer, PMCLOG_BUFFER_SIZE); if (nread <= 0) { if (nread == 0) ev->pl_state = PMCLOG_EOF; else if (errno != EAGAIN) /* not restartable */ ev->pl_state = PMCLOG_ERROR; return -1; } ps->ps_len = nread; ps->ps_data = ps->ps_buffer; - } else + } else { return -1; + } } assert(ps->ps_len > 0); /* Retrieve one event from the byte stream. */ retval = pmclog_get_event(ps, &ps->ps_data, &ps->ps_len, ev); - /* * If we need more data and we have a configured fd, try read * from it. */ if (retval < 0 && ev->pl_state == PMCLOG_REQUIRE_DATA && ps->ps_fd != -1) { assert(ps->ps_len == 0); goto refill; } return retval; } /* * Feed data to a memory based parser. * * The memory area pointed to by 'data' needs to be valid till the * next error return from pmclog_next_event(). */ int pmclog_feed(void *cookie, char *data, int len) { struct pmclog_parse_state *ps; ps = (struct pmclog_parse_state *) cookie; if (len < 0 || /* invalid length */ ps->ps_buffer || /* called for a file parser */ ps->ps_len != 0) /* unnecessary call */ return -1; ps->ps_data = data; ps->ps_len = len; return 0; } /* * Allocate and initialize parser state. */ void * pmclog_open(int fd) { struct pmclog_parse_state *ps; if ((ps = (struct pmclog_parse_state *) malloc(sizeof(*ps))) == NULL) return NULL; ps->ps_state = PL_STATE_NEW_RECORD; ps->ps_arch = -1; ps->ps_initialized = 0; ps->ps_count = 0; ps->ps_offset = (off_t) 0; bzero(&ps->ps_saved, sizeof(ps->ps_saved)); ps->ps_svcount = 0; ps->ps_fd = fd; ps->ps_data = NULL; ps->ps_buffer = NULL; ps->ps_len = 0; /* allocate space for a work area */ if (ps->ps_fd != PMCLOG_FD_NONE) { if ((ps->ps_buffer = malloc(PMCLOG_BUFFER_SIZE)) == NULL) { free(ps); return NULL; } } return ps; } /* * Free up parser state. */ void pmclog_close(void *cookie) { struct pmclog_parse_state *ps; ps = (struct pmclog_parse_state *) cookie; if (ps->ps_buffer) free(ps->ps_buffer); free(ps); } diff --git a/lib/libpmc/pmclog.h b/lib/libpmc/pmclog.h index 9f748b77d69a..a6b4d84a1104 100644 --- a/lib/libpmc/pmclog.h +++ b/lib/libpmc/pmclog.h @@ -1,185 +1,184 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2007 Joseph Koshy * Copyright (c) 2007 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by A. Joseph Koshy under * sponsorship from the FreeBSD Foundation and Google, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _PMCLOG_H_ #define _PMCLOG_H_ #include #include enum pmclog_state { PMCLOG_OK, PMCLOG_EOF, PMCLOG_REQUIRE_DATA, PMCLOG_ERROR }; struct pmclog_ev_callchain { uint32_t pl_pid; uint32_t pl_tid; uint32_t pl_pmcid; uint32_t pl_cpuflags; uint32_t pl_cpuflags2; uint32_t pl_npc; uintfptr_t pl_pc[PMC_CALLCHAIN_DEPTH_MAX]; }; struct pmclog_ev_dropnotify { }; struct pmclog_ev_closelog { }; struct pmclog_ev_initialize { uint32_t pl_version; uint32_t pl_arch; }; struct pmclog_ev_map_in { pid_t pl_pid; uintfptr_t pl_start; char pl_pathname[PATH_MAX]; }; struct pmclog_ev_map_out { pid_t pl_pid; uintfptr_t pl_start; uintfptr_t pl_end; }; struct pmclog_ev_pcsample { uintfptr_t pl_pc; pid_t pl_pid; pid_t pl_tid; pmc_id_t pl_pmcid; uint32_t pl_flags; uint32_t pl_usermode; }; struct pmclog_ev_pmcallocate { uint32_t pl_event; const char * pl_evname; uint32_t pl_flags; pmc_id_t pl_pmcid; }; struct pmclog_ev_pmcallocatedyn { uint32_t pl_event; char pl_evname[PMC_NAME_MAX]; uint32_t pl_flags; pmc_id_t pl_pmcid; }; struct pmclog_ev_pmcattach { pmc_id_t pl_pmcid; pid_t pl_pid; char pl_pathname[PATH_MAX]; }; struct pmclog_ev_pmcdetach { pmc_id_t pl_pmcid; pid_t pl_pid; }; struct pmclog_ev_proccsw { pid_t pl_pid; pid_t pl_tid; pmc_id_t pl_pmcid; pmc_value_t pl_value; }; struct pmclog_ev_procexec { pid_t pl_pid; pmc_id_t pl_pmcid; uintfptr_t pl_entryaddr; char pl_pathname[PATH_MAX]; }; struct pmclog_ev_procexit { uint32_t pl_pid; pmc_id_t pl_pmcid; pmc_value_t pl_value; }; struct pmclog_ev_procfork { pid_t pl_oldpid; pid_t pl_newpid; }; struct pmclog_ev_sysexit { pid_t pl_pid; }; struct pmclog_ev_userdata { uint32_t pl_userdata; }; struct pmclog_ev { enum pmclog_state pl_state; /* state after 'get_event()' */ off_t pl_offset; /* byte offset in stream */ size_t pl_count; /* count of records so far */ struct timespec pl_ts; /* log entry timestamp */ enum pmclog_type pl_type; /* type of log entry */ union { /* log entry data */ struct pmclog_ev_callchain pl_cc; struct pmclog_ev_closelog pl_cl; struct pmclog_ev_dropnotify pl_dn; struct pmclog_ev_initialize pl_i; struct pmclog_ev_map_in pl_mi; struct pmclog_ev_map_out pl_mo; - struct pmclog_ev_pcsample pl_s; struct pmclog_ev_pmcallocate pl_a; struct pmclog_ev_pmcallocatedyn pl_ad; struct pmclog_ev_pmcattach pl_t; struct pmclog_ev_pmcdetach pl_d; struct pmclog_ev_proccsw pl_c; struct pmclog_ev_procexec pl_x; struct pmclog_ev_procexit pl_e; struct pmclog_ev_procfork pl_f; struct pmclog_ev_sysexit pl_se; struct pmclog_ev_userdata pl_u; } pl_u; }; #define PMCLOG_FD_NONE (-1) __BEGIN_DECLS void *pmclog_open(int _fd); int pmclog_feed(void *_cookie, char *_data, int _len); int pmclog_read(void *_cookie, struct pmclog_ev *_ev); void pmclog_close(void *_cookie); __END_DECLS #endif diff --git a/lib/libpmcstat/pmu-events/Makefile b/lib/libpmc/pmu-events/Makefile similarity index 100% rename from lib/libpmcstat/pmu-events/Makefile rename to lib/libpmc/pmu-events/Makefile diff --git a/lib/libpmcstat/pmu-events/README b/lib/libpmc/pmu-events/README similarity index 100% rename from lib/libpmcstat/pmu-events/README rename to lib/libpmc/pmu-events/README diff --git a/lib/libpmcstat/pmu-events/arch/arm64/arm/cortex-a53/branch.json b/lib/libpmc/pmu-events/arch/arm64/arm/cortex-a53/branch.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/arm64/arm/cortex-a53/branch.json rename to lib/libpmc/pmu-events/arch/arm64/arm/cortex-a53/branch.json diff --git a/lib/libpmcstat/pmu-events/arch/arm64/arm/cortex-a53/bus.json b/lib/libpmc/pmu-events/arch/arm64/arm/cortex-a53/bus.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/arm64/arm/cortex-a53/bus.json rename to lib/libpmc/pmu-events/arch/arm64/arm/cortex-a53/bus.json diff --git a/lib/libpmcstat/pmu-events/arch/arm64/arm/cortex-a53/cache.json b/lib/libpmc/pmu-events/arch/arm64/arm/cortex-a53/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/arm64/arm/cortex-a53/cache.json rename to lib/libpmc/pmu-events/arch/arm64/arm/cortex-a53/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/arm64/arm/cortex-a53/memory.json b/lib/libpmc/pmu-events/arch/arm64/arm/cortex-a53/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/arm64/arm/cortex-a53/memory.json rename to lib/libpmc/pmu-events/arch/arm64/arm/cortex-a53/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/arm64/arm/cortex-a53/other.json b/lib/libpmc/pmu-events/arch/arm64/arm/cortex-a53/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/arm64/arm/cortex-a53/other.json rename to lib/libpmc/pmu-events/arch/arm64/arm/cortex-a53/other.json diff --git a/lib/libpmcstat/pmu-events/arch/arm64/arm/cortex-a53/pipeline.json b/lib/libpmc/pmu-events/arch/arm64/arm/cortex-a53/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/arm64/arm/cortex-a53/pipeline.json rename to lib/libpmc/pmu-events/arch/arm64/arm/cortex-a53/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/arm64/armv8-recommended.json b/lib/libpmc/pmu-events/arch/arm64/armv8-recommended.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/arm64/armv8-recommended.json rename to lib/libpmc/pmu-events/arch/arm64/armv8-recommended.json diff --git a/lib/libpmcstat/pmu-events/arch/arm64/cavium/thunderx2/core-imp-def.json b/lib/libpmc/pmu-events/arch/arm64/cavium/thunderx2/core-imp-def.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/arm64/cavium/thunderx2/core-imp-def.json rename to lib/libpmc/pmu-events/arch/arm64/cavium/thunderx2/core-imp-def.json diff --git a/lib/libpmcstat/pmu-events/arch/arm64/hisilicon/hip08/core-imp-def.json b/lib/libpmc/pmu-events/arch/arm64/hisilicon/hip08/core-imp-def.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/arm64/hisilicon/hip08/core-imp-def.json rename to lib/libpmc/pmu-events/arch/arm64/hisilicon/hip08/core-imp-def.json diff --git a/lib/libpmcstat/pmu-events/arch/arm64/mapfile.csv b/lib/libpmc/pmu-events/arch/arm64/mapfile.csv similarity index 100% rename from lib/libpmcstat/pmu-events/arch/arm64/mapfile.csv rename to lib/libpmc/pmu-events/arch/arm64/mapfile.csv diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/mapfile.csv b/lib/libpmc/pmu-events/arch/powerpc/mapfile.csv similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/mapfile.csv rename to lib/libpmc/pmu-events/arch/powerpc/mapfile.csv diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power8/cache.json b/lib/libpmc/pmu-events/arch/powerpc/power8/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power8/cache.json rename to lib/libpmc/pmu-events/arch/powerpc/power8/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power8/floating-point.json b/lib/libpmc/pmu-events/arch/powerpc/power8/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power8/floating-point.json rename to lib/libpmc/pmu-events/arch/powerpc/power8/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power8/frontend.json b/lib/libpmc/pmu-events/arch/powerpc/power8/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power8/frontend.json rename to lib/libpmc/pmu-events/arch/powerpc/power8/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power8/marked.json b/lib/libpmc/pmu-events/arch/powerpc/power8/marked.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power8/marked.json rename to lib/libpmc/pmu-events/arch/powerpc/power8/marked.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power8/memory.json b/lib/libpmc/pmu-events/arch/powerpc/power8/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power8/memory.json rename to lib/libpmc/pmu-events/arch/powerpc/power8/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power8/other.json b/lib/libpmc/pmu-events/arch/powerpc/power8/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power8/other.json rename to lib/libpmc/pmu-events/arch/powerpc/power8/other.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power8/pipeline.json b/lib/libpmc/pmu-events/arch/powerpc/power8/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power8/pipeline.json rename to lib/libpmc/pmu-events/arch/powerpc/power8/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power8/pmc.json b/lib/libpmc/pmu-events/arch/powerpc/power8/pmc.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power8/pmc.json rename to lib/libpmc/pmu-events/arch/powerpc/power8/pmc.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power8/translation.json b/lib/libpmc/pmu-events/arch/powerpc/power8/translation.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power8/translation.json rename to lib/libpmc/pmu-events/arch/powerpc/power8/translation.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power9/cache.json b/lib/libpmc/pmu-events/arch/powerpc/power9/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power9/cache.json rename to lib/libpmc/pmu-events/arch/powerpc/power9/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power9/floating-point.json b/lib/libpmc/pmu-events/arch/powerpc/power9/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power9/floating-point.json rename to lib/libpmc/pmu-events/arch/powerpc/power9/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power9/frontend.json b/lib/libpmc/pmu-events/arch/powerpc/power9/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power9/frontend.json rename to lib/libpmc/pmu-events/arch/powerpc/power9/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power9/marked.json b/lib/libpmc/pmu-events/arch/powerpc/power9/marked.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power9/marked.json rename to lib/libpmc/pmu-events/arch/powerpc/power9/marked.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power9/memory.json b/lib/libpmc/pmu-events/arch/powerpc/power9/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power9/memory.json rename to lib/libpmc/pmu-events/arch/powerpc/power9/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power9/other.json b/lib/libpmc/pmu-events/arch/powerpc/power9/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power9/other.json rename to lib/libpmc/pmu-events/arch/powerpc/power9/other.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power9/pipeline.json b/lib/libpmc/pmu-events/arch/powerpc/power9/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power9/pipeline.json rename to lib/libpmc/pmu-events/arch/powerpc/power9/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power9/pmc.json b/lib/libpmc/pmu-events/arch/powerpc/power9/pmc.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power9/pmc.json rename to lib/libpmc/pmu-events/arch/powerpc/power9/pmc.json diff --git a/lib/libpmcstat/pmu-events/arch/powerpc/power9/translation.json b/lib/libpmc/pmu-events/arch/powerpc/power9/translation.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/powerpc/power9/translation.json rename to lib/libpmc/pmu-events/arch/powerpc/power9/translation.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_z10/basic.json b/lib/libpmc/pmu-events/arch/s390/cf_z10/basic.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_z10/basic.json rename to lib/libpmc/pmu-events/arch/s390/cf_z10/basic.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_z10/crypto.json b/lib/libpmc/pmu-events/arch/s390/cf_z10/crypto.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_z10/crypto.json rename to lib/libpmc/pmu-events/arch/s390/cf_z10/crypto.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_z10/extended.json b/lib/libpmc/pmu-events/arch/s390/cf_z10/extended.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_z10/extended.json rename to lib/libpmc/pmu-events/arch/s390/cf_z10/extended.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_z13/basic.json b/lib/libpmc/pmu-events/arch/s390/cf_z13/basic.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_z13/basic.json rename to lib/libpmc/pmu-events/arch/s390/cf_z13/basic.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_z13/crypto.json b/lib/libpmc/pmu-events/arch/s390/cf_z13/crypto.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_z13/crypto.json rename to lib/libpmc/pmu-events/arch/s390/cf_z13/crypto.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_z13/extended.json b/lib/libpmc/pmu-events/arch/s390/cf_z13/extended.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_z13/extended.json rename to lib/libpmc/pmu-events/arch/s390/cf_z13/extended.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_z14/basic.json b/lib/libpmc/pmu-events/arch/s390/cf_z14/basic.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_z14/basic.json rename to lib/libpmc/pmu-events/arch/s390/cf_z14/basic.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_z14/crypto.json b/lib/libpmc/pmu-events/arch/s390/cf_z14/crypto.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_z14/crypto.json rename to lib/libpmc/pmu-events/arch/s390/cf_z14/crypto.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_z14/extended.json b/lib/libpmc/pmu-events/arch/s390/cf_z14/extended.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_z14/extended.json rename to lib/libpmc/pmu-events/arch/s390/cf_z14/extended.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_z196/basic.json b/lib/libpmc/pmu-events/arch/s390/cf_z196/basic.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_z196/basic.json rename to lib/libpmc/pmu-events/arch/s390/cf_z196/basic.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_z196/crypto.json b/lib/libpmc/pmu-events/arch/s390/cf_z196/crypto.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_z196/crypto.json rename to lib/libpmc/pmu-events/arch/s390/cf_z196/crypto.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_z196/extended.json b/lib/libpmc/pmu-events/arch/s390/cf_z196/extended.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_z196/extended.json rename to lib/libpmc/pmu-events/arch/s390/cf_z196/extended.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_zec12/basic.json b/lib/libpmc/pmu-events/arch/s390/cf_zec12/basic.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_zec12/basic.json rename to lib/libpmc/pmu-events/arch/s390/cf_zec12/basic.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_zec12/crypto.json b/lib/libpmc/pmu-events/arch/s390/cf_zec12/crypto.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_zec12/crypto.json rename to lib/libpmc/pmu-events/arch/s390/cf_zec12/crypto.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/cf_zec12/extended.json b/lib/libpmc/pmu-events/arch/s390/cf_zec12/extended.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/cf_zec12/extended.json rename to lib/libpmc/pmu-events/arch/s390/cf_zec12/extended.json diff --git a/lib/libpmcstat/pmu-events/arch/s390/mapfile.csv b/lib/libpmc/pmu-events/arch/s390/mapfile.csv similarity index 100% rename from lib/libpmcstat/pmu-events/arch/s390/mapfile.csv rename to lib/libpmc/pmu-events/arch/s390/mapfile.csv diff --git a/lib/libpmcstat/pmu-events/arch/x86/bonnell/cache.json b/lib/libpmc/pmu-events/arch/x86/bonnell/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/bonnell/cache.json rename to lib/libpmc/pmu-events/arch/x86/bonnell/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/bonnell/floating-point.json b/lib/libpmc/pmu-events/arch/x86/bonnell/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/bonnell/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/bonnell/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/bonnell/frontend.json b/lib/libpmc/pmu-events/arch/x86/bonnell/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/bonnell/frontend.json rename to lib/libpmc/pmu-events/arch/x86/bonnell/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/bonnell/memory.json b/lib/libpmc/pmu-events/arch/x86/bonnell/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/bonnell/memory.json rename to lib/libpmc/pmu-events/arch/x86/bonnell/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/bonnell/other.json b/lib/libpmc/pmu-events/arch/x86/bonnell/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/bonnell/other.json rename to lib/libpmc/pmu-events/arch/x86/bonnell/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/bonnell/pipeline.json b/lib/libpmc/pmu-events/arch/x86/bonnell/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/bonnell/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/bonnell/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/bonnell/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/bonnell/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/bonnell/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/bonnell/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwell/bdw-metrics.json b/lib/libpmc/pmu-events/arch/x86/broadwell/bdw-metrics.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwell/bdw-metrics.json rename to lib/libpmc/pmu-events/arch/x86/broadwell/bdw-metrics.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwell/cache.json b/lib/libpmc/pmu-events/arch/x86/broadwell/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwell/cache.json rename to lib/libpmc/pmu-events/arch/x86/broadwell/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwell/floating-point.json b/lib/libpmc/pmu-events/arch/x86/broadwell/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwell/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/broadwell/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwell/frontend.json b/lib/libpmc/pmu-events/arch/x86/broadwell/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwell/frontend.json rename to lib/libpmc/pmu-events/arch/x86/broadwell/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwell/memory.json b/lib/libpmc/pmu-events/arch/x86/broadwell/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwell/memory.json rename to lib/libpmc/pmu-events/arch/x86/broadwell/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwell/other.json b/lib/libpmc/pmu-events/arch/x86/broadwell/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwell/other.json rename to lib/libpmc/pmu-events/arch/x86/broadwell/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwell/pipeline.json b/lib/libpmc/pmu-events/arch/x86/broadwell/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwell/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/broadwell/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwell/uncore.json b/lib/libpmc/pmu-events/arch/x86/broadwell/uncore.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwell/uncore.json rename to lib/libpmc/pmu-events/arch/x86/broadwell/uncore.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwell/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/broadwell/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwell/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/broadwell/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellde/bdwde-metrics.json b/lib/libpmc/pmu-events/arch/x86/broadwellde/bdwde-metrics.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellde/bdwde-metrics.json rename to lib/libpmc/pmu-events/arch/x86/broadwellde/bdwde-metrics.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellde/cache.json b/lib/libpmc/pmu-events/arch/x86/broadwellde/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellde/cache.json rename to lib/libpmc/pmu-events/arch/x86/broadwellde/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellde/floating-point.json b/lib/libpmc/pmu-events/arch/x86/broadwellde/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellde/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/broadwellde/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellde/frontend.json b/lib/libpmc/pmu-events/arch/x86/broadwellde/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellde/frontend.json rename to lib/libpmc/pmu-events/arch/x86/broadwellde/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellde/memory.json b/lib/libpmc/pmu-events/arch/x86/broadwellde/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellde/memory.json rename to lib/libpmc/pmu-events/arch/x86/broadwellde/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellde/other.json b/lib/libpmc/pmu-events/arch/x86/broadwellde/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellde/other.json rename to lib/libpmc/pmu-events/arch/x86/broadwellde/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellde/pipeline.json b/lib/libpmc/pmu-events/arch/x86/broadwellde/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellde/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/broadwellde/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellde/uncore-cache.json b/lib/libpmc/pmu-events/arch/x86/broadwellde/uncore-cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellde/uncore-cache.json rename to lib/libpmc/pmu-events/arch/x86/broadwellde/uncore-cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellde/uncore-memory.json b/lib/libpmc/pmu-events/arch/x86/broadwellde/uncore-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellde/uncore-memory.json rename to lib/libpmc/pmu-events/arch/x86/broadwellde/uncore-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellde/uncore-power.json b/lib/libpmc/pmu-events/arch/x86/broadwellde/uncore-power.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellde/uncore-power.json rename to lib/libpmc/pmu-events/arch/x86/broadwellde/uncore-power.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellde/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/broadwellde/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellde/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/broadwellde/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellx/bdx-metrics.json b/lib/libpmc/pmu-events/arch/x86/broadwellx/bdx-metrics.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellx/bdx-metrics.json rename to lib/libpmc/pmu-events/arch/x86/broadwellx/bdx-metrics.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellx/cache.json b/lib/libpmc/pmu-events/arch/x86/broadwellx/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellx/cache.json rename to lib/libpmc/pmu-events/arch/x86/broadwellx/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellx/floating-point.json b/lib/libpmc/pmu-events/arch/x86/broadwellx/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellx/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/broadwellx/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellx/frontend.json b/lib/libpmc/pmu-events/arch/x86/broadwellx/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellx/frontend.json rename to lib/libpmc/pmu-events/arch/x86/broadwellx/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellx/memory.json b/lib/libpmc/pmu-events/arch/x86/broadwellx/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellx/memory.json rename to lib/libpmc/pmu-events/arch/x86/broadwellx/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellx/other.json b/lib/libpmc/pmu-events/arch/x86/broadwellx/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellx/other.json rename to lib/libpmc/pmu-events/arch/x86/broadwellx/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellx/pipeline.json b/lib/libpmc/pmu-events/arch/x86/broadwellx/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellx/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/broadwellx/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellx/uncore-cache.json b/lib/libpmc/pmu-events/arch/x86/broadwellx/uncore-cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellx/uncore-cache.json rename to lib/libpmc/pmu-events/arch/x86/broadwellx/uncore-cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellx/uncore-interconnect.json b/lib/libpmc/pmu-events/arch/x86/broadwellx/uncore-interconnect.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellx/uncore-interconnect.json rename to lib/libpmc/pmu-events/arch/x86/broadwellx/uncore-interconnect.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellx/uncore-memory.json b/lib/libpmc/pmu-events/arch/x86/broadwellx/uncore-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellx/uncore-memory.json rename to lib/libpmc/pmu-events/arch/x86/broadwellx/uncore-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellx/uncore-power.json b/lib/libpmc/pmu-events/arch/x86/broadwellx/uncore-power.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellx/uncore-power.json rename to lib/libpmc/pmu-events/arch/x86/broadwellx/uncore-power.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/broadwellx/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/broadwellx/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/broadwellx/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/broadwellx/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/goldmont/cache.json b/lib/libpmc/pmu-events/arch/x86/goldmont/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/goldmont/cache.json rename to lib/libpmc/pmu-events/arch/x86/goldmont/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/goldmont/frontend.json b/lib/libpmc/pmu-events/arch/x86/goldmont/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/goldmont/frontend.json rename to lib/libpmc/pmu-events/arch/x86/goldmont/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/goldmont/memory.json b/lib/libpmc/pmu-events/arch/x86/goldmont/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/goldmont/memory.json rename to lib/libpmc/pmu-events/arch/x86/goldmont/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/goldmont/other.json b/lib/libpmc/pmu-events/arch/x86/goldmont/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/goldmont/other.json rename to lib/libpmc/pmu-events/arch/x86/goldmont/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/goldmont/pipeline.json b/lib/libpmc/pmu-events/arch/x86/goldmont/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/goldmont/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/goldmont/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/goldmont/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/goldmont/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/goldmont/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/goldmont/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/goldmontplus/cache.json b/lib/libpmc/pmu-events/arch/x86/goldmontplus/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/goldmontplus/cache.json rename to lib/libpmc/pmu-events/arch/x86/goldmontplus/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/goldmontplus/frontend.json b/lib/libpmc/pmu-events/arch/x86/goldmontplus/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/goldmontplus/frontend.json rename to lib/libpmc/pmu-events/arch/x86/goldmontplus/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/goldmontplus/memory.json b/lib/libpmc/pmu-events/arch/x86/goldmontplus/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/goldmontplus/memory.json rename to lib/libpmc/pmu-events/arch/x86/goldmontplus/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/goldmontplus/other.json b/lib/libpmc/pmu-events/arch/x86/goldmontplus/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/goldmontplus/other.json rename to lib/libpmc/pmu-events/arch/x86/goldmontplus/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/goldmontplus/pipeline.json b/lib/libpmc/pmu-events/arch/x86/goldmontplus/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/goldmontplus/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/goldmontplus/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/goldmontplus/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/goldmontplus/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/goldmontplus/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/goldmontplus/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswell/cache.json b/lib/libpmc/pmu-events/arch/x86/haswell/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswell/cache.json rename to lib/libpmc/pmu-events/arch/x86/haswell/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswell/floating-point.json b/lib/libpmc/pmu-events/arch/x86/haswell/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswell/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/haswell/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswell/frontend.json b/lib/libpmc/pmu-events/arch/x86/haswell/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswell/frontend.json rename to lib/libpmc/pmu-events/arch/x86/haswell/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswell/hsw-metrics.json b/lib/libpmc/pmu-events/arch/x86/haswell/hsw-metrics.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswell/hsw-metrics.json rename to lib/libpmc/pmu-events/arch/x86/haswell/hsw-metrics.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswell/memory.json b/lib/libpmc/pmu-events/arch/x86/haswell/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswell/memory.json rename to lib/libpmc/pmu-events/arch/x86/haswell/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswell/other.json b/lib/libpmc/pmu-events/arch/x86/haswell/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswell/other.json rename to lib/libpmc/pmu-events/arch/x86/haswell/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswell/pipeline.json b/lib/libpmc/pmu-events/arch/x86/haswell/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswell/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/haswell/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswell/uncore.json b/lib/libpmc/pmu-events/arch/x86/haswell/uncore.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswell/uncore.json rename to lib/libpmc/pmu-events/arch/x86/haswell/uncore.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswell/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/haswell/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswell/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/haswell/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswellx/cache.json b/lib/libpmc/pmu-events/arch/x86/haswellx/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswellx/cache.json rename to lib/libpmc/pmu-events/arch/x86/haswellx/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswellx/floating-point.json b/lib/libpmc/pmu-events/arch/x86/haswellx/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswellx/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/haswellx/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswellx/frontend.json b/lib/libpmc/pmu-events/arch/x86/haswellx/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswellx/frontend.json rename to lib/libpmc/pmu-events/arch/x86/haswellx/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswellx/hsx-metrics.json b/lib/libpmc/pmu-events/arch/x86/haswellx/hsx-metrics.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswellx/hsx-metrics.json rename to lib/libpmc/pmu-events/arch/x86/haswellx/hsx-metrics.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswellx/memory.json b/lib/libpmc/pmu-events/arch/x86/haswellx/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswellx/memory.json rename to lib/libpmc/pmu-events/arch/x86/haswellx/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswellx/other.json b/lib/libpmc/pmu-events/arch/x86/haswellx/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswellx/other.json rename to lib/libpmc/pmu-events/arch/x86/haswellx/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswellx/pipeline.json b/lib/libpmc/pmu-events/arch/x86/haswellx/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswellx/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/haswellx/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswellx/uncore-cache.json b/lib/libpmc/pmu-events/arch/x86/haswellx/uncore-cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswellx/uncore-cache.json rename to lib/libpmc/pmu-events/arch/x86/haswellx/uncore-cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswellx/uncore-interconnect.json b/lib/libpmc/pmu-events/arch/x86/haswellx/uncore-interconnect.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswellx/uncore-interconnect.json rename to lib/libpmc/pmu-events/arch/x86/haswellx/uncore-interconnect.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswellx/uncore-memory.json b/lib/libpmc/pmu-events/arch/x86/haswellx/uncore-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswellx/uncore-memory.json rename to lib/libpmc/pmu-events/arch/x86/haswellx/uncore-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswellx/uncore-power.json b/lib/libpmc/pmu-events/arch/x86/haswellx/uncore-power.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswellx/uncore-power.json rename to lib/libpmc/pmu-events/arch/x86/haswellx/uncore-power.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/haswellx/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/haswellx/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/haswellx/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/haswellx/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivybridge/cache.json b/lib/libpmc/pmu-events/arch/x86/ivybridge/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivybridge/cache.json rename to lib/libpmc/pmu-events/arch/x86/ivybridge/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivybridge/floating-point.json b/lib/libpmc/pmu-events/arch/x86/ivybridge/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivybridge/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/ivybridge/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivybridge/frontend.json b/lib/libpmc/pmu-events/arch/x86/ivybridge/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivybridge/frontend.json rename to lib/libpmc/pmu-events/arch/x86/ivybridge/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivybridge/ivb-metrics.json b/lib/libpmc/pmu-events/arch/x86/ivybridge/ivb-metrics.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivybridge/ivb-metrics.json rename to lib/libpmc/pmu-events/arch/x86/ivybridge/ivb-metrics.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivybridge/memory.json b/lib/libpmc/pmu-events/arch/x86/ivybridge/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivybridge/memory.json rename to lib/libpmc/pmu-events/arch/x86/ivybridge/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivybridge/other.json b/lib/libpmc/pmu-events/arch/x86/ivybridge/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivybridge/other.json rename to lib/libpmc/pmu-events/arch/x86/ivybridge/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivybridge/pipeline.json b/lib/libpmc/pmu-events/arch/x86/ivybridge/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivybridge/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/ivybridge/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivybridge/uncore.json b/lib/libpmc/pmu-events/arch/x86/ivybridge/uncore.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivybridge/uncore.json rename to lib/libpmc/pmu-events/arch/x86/ivybridge/uncore.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivybridge/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/ivybridge/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivybridge/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/ivybridge/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivytown/cache.json b/lib/libpmc/pmu-events/arch/x86/ivytown/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivytown/cache.json rename to lib/libpmc/pmu-events/arch/x86/ivytown/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivytown/floating-point.json b/lib/libpmc/pmu-events/arch/x86/ivytown/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivytown/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/ivytown/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivytown/frontend.json b/lib/libpmc/pmu-events/arch/x86/ivytown/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivytown/frontend.json rename to lib/libpmc/pmu-events/arch/x86/ivytown/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivytown/ivt-metrics.json b/lib/libpmc/pmu-events/arch/x86/ivytown/ivt-metrics.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivytown/ivt-metrics.json rename to lib/libpmc/pmu-events/arch/x86/ivytown/ivt-metrics.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivytown/memory.json b/lib/libpmc/pmu-events/arch/x86/ivytown/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivytown/memory.json rename to lib/libpmc/pmu-events/arch/x86/ivytown/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivytown/other.json b/lib/libpmc/pmu-events/arch/x86/ivytown/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivytown/other.json rename to lib/libpmc/pmu-events/arch/x86/ivytown/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivytown/pipeline.json b/lib/libpmc/pmu-events/arch/x86/ivytown/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivytown/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/ivytown/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivytown/uncore-cache.json b/lib/libpmc/pmu-events/arch/x86/ivytown/uncore-cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivytown/uncore-cache.json rename to lib/libpmc/pmu-events/arch/x86/ivytown/uncore-cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivytown/uncore-interconnect.json b/lib/libpmc/pmu-events/arch/x86/ivytown/uncore-interconnect.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivytown/uncore-interconnect.json rename to lib/libpmc/pmu-events/arch/x86/ivytown/uncore-interconnect.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivytown/uncore-memory.json b/lib/libpmc/pmu-events/arch/x86/ivytown/uncore-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivytown/uncore-memory.json rename to lib/libpmc/pmu-events/arch/x86/ivytown/uncore-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivytown/uncore-power.json b/lib/libpmc/pmu-events/arch/x86/ivytown/uncore-power.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivytown/uncore-power.json rename to lib/libpmc/pmu-events/arch/x86/ivytown/uncore-power.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/ivytown/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/ivytown/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/ivytown/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/ivytown/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/jaketown/cache.json b/lib/libpmc/pmu-events/arch/x86/jaketown/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/jaketown/cache.json rename to lib/libpmc/pmu-events/arch/x86/jaketown/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/jaketown/floating-point.json b/lib/libpmc/pmu-events/arch/x86/jaketown/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/jaketown/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/jaketown/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/jaketown/frontend.json b/lib/libpmc/pmu-events/arch/x86/jaketown/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/jaketown/frontend.json rename to lib/libpmc/pmu-events/arch/x86/jaketown/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/jaketown/jkt-metrics.json b/lib/libpmc/pmu-events/arch/x86/jaketown/jkt-metrics.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/jaketown/jkt-metrics.json rename to lib/libpmc/pmu-events/arch/x86/jaketown/jkt-metrics.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/jaketown/memory.json b/lib/libpmc/pmu-events/arch/x86/jaketown/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/jaketown/memory.json rename to lib/libpmc/pmu-events/arch/x86/jaketown/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/jaketown/other.json b/lib/libpmc/pmu-events/arch/x86/jaketown/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/jaketown/other.json rename to lib/libpmc/pmu-events/arch/x86/jaketown/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/jaketown/pipeline.json b/lib/libpmc/pmu-events/arch/x86/jaketown/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/jaketown/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/jaketown/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/jaketown/uncore-cache.json b/lib/libpmc/pmu-events/arch/x86/jaketown/uncore-cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/jaketown/uncore-cache.json rename to lib/libpmc/pmu-events/arch/x86/jaketown/uncore-cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/jaketown/uncore-interconnect.json b/lib/libpmc/pmu-events/arch/x86/jaketown/uncore-interconnect.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/jaketown/uncore-interconnect.json rename to lib/libpmc/pmu-events/arch/x86/jaketown/uncore-interconnect.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/jaketown/uncore-memory.json b/lib/libpmc/pmu-events/arch/x86/jaketown/uncore-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/jaketown/uncore-memory.json rename to lib/libpmc/pmu-events/arch/x86/jaketown/uncore-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/jaketown/uncore-power.json b/lib/libpmc/pmu-events/arch/x86/jaketown/uncore-power.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/jaketown/uncore-power.json rename to lib/libpmc/pmu-events/arch/x86/jaketown/uncore-power.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/jaketown/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/jaketown/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/jaketown/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/jaketown/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/knightslanding/cache.json b/lib/libpmc/pmu-events/arch/x86/knightslanding/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/knightslanding/cache.json rename to lib/libpmc/pmu-events/arch/x86/knightslanding/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/knightslanding/frontend.json b/lib/libpmc/pmu-events/arch/x86/knightslanding/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/knightslanding/frontend.json rename to lib/libpmc/pmu-events/arch/x86/knightslanding/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/knightslanding/memory.json b/lib/libpmc/pmu-events/arch/x86/knightslanding/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/knightslanding/memory.json rename to lib/libpmc/pmu-events/arch/x86/knightslanding/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/knightslanding/pipeline.json b/lib/libpmc/pmu-events/arch/x86/knightslanding/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/knightslanding/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/knightslanding/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/knightslanding/uncore-memory.json b/lib/libpmc/pmu-events/arch/x86/knightslanding/uncore-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/knightslanding/uncore-memory.json rename to lib/libpmc/pmu-events/arch/x86/knightslanding/uncore-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/knightslanding/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/knightslanding/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/knightslanding/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/knightslanding/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/mapfile.csv b/lib/libpmc/pmu-events/arch/x86/mapfile.csv similarity index 89% rename from lib/libpmcstat/pmu-events/arch/x86/mapfile.csv rename to lib/libpmc/pmu-events/arch/x86/mapfile.csv index 93656f2fd53a..fe1a2c47cabf 100644 --- a/lib/libpmcstat/pmu-events/arch/x86/mapfile.csv +++ b/lib/libpmc/pmu-events/arch/x86/mapfile.csv @@ -1,35 +1,38 @@ Family-model,Version,Filename,EventType GenuineIntel-6-56,v5,broadwellde,core GenuineIntel-6-3D,v17,broadwell,core GenuineIntel-6-47,v17,broadwell,core GenuineIntel-6-4F,v10,broadwellx,core GenuineIntel-6-1C,v4,bonnell,core GenuineIntel-6-26,v4,bonnell,core GenuineIntel-6-27,v4,bonnell,core GenuineIntel-6-36,v4,bonnell,core GenuineIntel-6-35,v4,bonnell,core GenuineIntel-6-5C,v8,goldmont,core GenuineIntel-6-7A,v1,goldmontplus,core GenuineIntel-6-3C,v24,haswell,core GenuineIntel-6-45,v24,haswell,core GenuineIntel-6-46,v24,haswell,core GenuineIntel-6-3F,v17,haswellx,core GenuineIntel-6-3A,v18,ivybridge,core GenuineIntel-6-3E,v19,ivytown,core GenuineIntel-6-2D,v20,jaketown,core GenuineIntel-6-57,v9,knightslanding,core GenuineIntel-6-85,v9,knightslanding,core GenuineIntel-6-1E,v2,nehalemep,core GenuineIntel-6-1F,v2,nehalemep,core GenuineIntel-6-1A,v2,nehalemep,core GenuineIntel-6-2E,v2,nehalemex,core -GenuineIntel-6-[4589]E,v24,skylake,core +GenuineIntel-6-4E,v24,skylake,core +GenuineIntel-6-5E,v24,skylake,core +GenuineIntel-6-8E,v24,skylake,core +GenuineIntel-6-9E,v24,skylake,core GenuineIntel-6-37,v13,silvermont,core GenuineIntel-6-4D,v13,silvermont,core GenuineIntel-6-4C,v13,silvermont,core GenuineIntel-6-2A,v15,sandybridge,core GenuineIntel-6-2C,v2,westmereep-dp,core GenuineIntel-6-2C,v2,westmereep-dp,core GenuineIntel-6-25,v2,westmereep-sp,core GenuineIntel-6-2F,v2,westmereex,core GenuineIntel-6-55,v1,skylakex,core diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemep/cache.json b/lib/libpmc/pmu-events/arch/x86/nehalemep/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemep/cache.json rename to lib/libpmc/pmu-events/arch/x86/nehalemep/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemep/floating-point.json b/lib/libpmc/pmu-events/arch/x86/nehalemep/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemep/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/nehalemep/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemep/frontend.json b/lib/libpmc/pmu-events/arch/x86/nehalemep/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemep/frontend.json rename to lib/libpmc/pmu-events/arch/x86/nehalemep/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemep/memory.json b/lib/libpmc/pmu-events/arch/x86/nehalemep/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemep/memory.json rename to lib/libpmc/pmu-events/arch/x86/nehalemep/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemep/other.json b/lib/libpmc/pmu-events/arch/x86/nehalemep/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemep/other.json rename to lib/libpmc/pmu-events/arch/x86/nehalemep/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemep/pipeline.json b/lib/libpmc/pmu-events/arch/x86/nehalemep/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemep/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/nehalemep/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemep/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/nehalemep/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemep/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/nehalemep/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemex/cache.json b/lib/libpmc/pmu-events/arch/x86/nehalemex/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemex/cache.json rename to lib/libpmc/pmu-events/arch/x86/nehalemex/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemex/floating-point.json b/lib/libpmc/pmu-events/arch/x86/nehalemex/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemex/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/nehalemex/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemex/frontend.json b/lib/libpmc/pmu-events/arch/x86/nehalemex/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemex/frontend.json rename to lib/libpmc/pmu-events/arch/x86/nehalemex/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemex/memory.json b/lib/libpmc/pmu-events/arch/x86/nehalemex/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemex/memory.json rename to lib/libpmc/pmu-events/arch/x86/nehalemex/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemex/other.json b/lib/libpmc/pmu-events/arch/x86/nehalemex/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemex/other.json rename to lib/libpmc/pmu-events/arch/x86/nehalemex/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemex/pipeline.json b/lib/libpmc/pmu-events/arch/x86/nehalemex/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemex/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/nehalemex/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/nehalemex/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/nehalemex/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/nehalemex/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/nehalemex/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/sandybridge/cache.json b/lib/libpmc/pmu-events/arch/x86/sandybridge/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/sandybridge/cache.json rename to lib/libpmc/pmu-events/arch/x86/sandybridge/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/sandybridge/floating-point.json b/lib/libpmc/pmu-events/arch/x86/sandybridge/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/sandybridge/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/sandybridge/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/sandybridge/frontend.json b/lib/libpmc/pmu-events/arch/x86/sandybridge/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/sandybridge/frontend.json rename to lib/libpmc/pmu-events/arch/x86/sandybridge/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/sandybridge/memory.json b/lib/libpmc/pmu-events/arch/x86/sandybridge/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/sandybridge/memory.json rename to lib/libpmc/pmu-events/arch/x86/sandybridge/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/sandybridge/other.json b/lib/libpmc/pmu-events/arch/x86/sandybridge/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/sandybridge/other.json rename to lib/libpmc/pmu-events/arch/x86/sandybridge/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/sandybridge/pipeline.json b/lib/libpmc/pmu-events/arch/x86/sandybridge/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/sandybridge/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/sandybridge/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/sandybridge/snb-metrics.json b/lib/libpmc/pmu-events/arch/x86/sandybridge/snb-metrics.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/sandybridge/snb-metrics.json rename to lib/libpmc/pmu-events/arch/x86/sandybridge/snb-metrics.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/sandybridge/uncore.json b/lib/libpmc/pmu-events/arch/x86/sandybridge/uncore.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/sandybridge/uncore.json rename to lib/libpmc/pmu-events/arch/x86/sandybridge/uncore.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/sandybridge/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/sandybridge/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/sandybridge/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/sandybridge/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/silvermont/cache.json b/lib/libpmc/pmu-events/arch/x86/silvermont/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/silvermont/cache.json rename to lib/libpmc/pmu-events/arch/x86/silvermont/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/silvermont/frontend.json b/lib/libpmc/pmu-events/arch/x86/silvermont/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/silvermont/frontend.json rename to lib/libpmc/pmu-events/arch/x86/silvermont/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/silvermont/memory.json b/lib/libpmc/pmu-events/arch/x86/silvermont/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/silvermont/memory.json rename to lib/libpmc/pmu-events/arch/x86/silvermont/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/silvermont/pipeline.json b/lib/libpmc/pmu-events/arch/x86/silvermont/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/silvermont/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/silvermont/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/silvermont/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/silvermont/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/silvermont/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/silvermont/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylake/cache.json b/lib/libpmc/pmu-events/arch/x86/skylake/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylake/cache.json rename to lib/libpmc/pmu-events/arch/x86/skylake/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylake/floating-point.json b/lib/libpmc/pmu-events/arch/x86/skylake/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylake/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/skylake/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylake/frontend.json b/lib/libpmc/pmu-events/arch/x86/skylake/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylake/frontend.json rename to lib/libpmc/pmu-events/arch/x86/skylake/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylake/memory.json b/lib/libpmc/pmu-events/arch/x86/skylake/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylake/memory.json rename to lib/libpmc/pmu-events/arch/x86/skylake/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylake/other.json b/lib/libpmc/pmu-events/arch/x86/skylake/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylake/other.json rename to lib/libpmc/pmu-events/arch/x86/skylake/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylake/pipeline.json b/lib/libpmc/pmu-events/arch/x86/skylake/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylake/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/skylake/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylake/skl-metrics.json b/lib/libpmc/pmu-events/arch/x86/skylake/skl-metrics.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylake/skl-metrics.json rename to lib/libpmc/pmu-events/arch/x86/skylake/skl-metrics.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylake/uncore.json b/lib/libpmc/pmu-events/arch/x86/skylake/uncore.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylake/uncore.json rename to lib/libpmc/pmu-events/arch/x86/skylake/uncore.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylake/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/skylake/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylake/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/skylake/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylakex/cache.json b/lib/libpmc/pmu-events/arch/x86/skylakex/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylakex/cache.json rename to lib/libpmc/pmu-events/arch/x86/skylakex/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylakex/floating-point.json b/lib/libpmc/pmu-events/arch/x86/skylakex/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylakex/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/skylakex/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylakex/frontend.json b/lib/libpmc/pmu-events/arch/x86/skylakex/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylakex/frontend.json rename to lib/libpmc/pmu-events/arch/x86/skylakex/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylakex/memory.json b/lib/libpmc/pmu-events/arch/x86/skylakex/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylakex/memory.json rename to lib/libpmc/pmu-events/arch/x86/skylakex/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylakex/other.json b/lib/libpmc/pmu-events/arch/x86/skylakex/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylakex/other.json rename to lib/libpmc/pmu-events/arch/x86/skylakex/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylakex/pipeline.json b/lib/libpmc/pmu-events/arch/x86/skylakex/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylakex/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/skylakex/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylakex/skx-metrics.json b/lib/libpmc/pmu-events/arch/x86/skylakex/skx-metrics.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylakex/skx-metrics.json rename to lib/libpmc/pmu-events/arch/x86/skylakex/skx-metrics.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylakex/uncore-memory.json b/lib/libpmc/pmu-events/arch/x86/skylakex/uncore-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylakex/uncore-memory.json rename to lib/libpmc/pmu-events/arch/x86/skylakex/uncore-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylakex/uncore-other.json b/lib/libpmc/pmu-events/arch/x86/skylakex/uncore-other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylakex/uncore-other.json rename to lib/libpmc/pmu-events/arch/x86/skylakex/uncore-other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/skylakex/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/skylakex/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/skylakex/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/skylakex/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/cache.json b/lib/libpmc/pmu-events/arch/x86/westmereep-dp/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/cache.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-dp/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/floating-point.json b/lib/libpmc/pmu-events/arch/x86/westmereep-dp/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-dp/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/frontend.json b/lib/libpmc/pmu-events/arch/x86/westmereep-dp/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/frontend.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-dp/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/memory.json b/lib/libpmc/pmu-events/arch/x86/westmereep-dp/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/memory.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-dp/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/other.json b/lib/libpmc/pmu-events/arch/x86/westmereep-dp/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/other.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-dp/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/pipeline.json b/lib/libpmc/pmu-events/arch/x86/westmereep-dp/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-dp/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/westmereep-dp/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-dp/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-dp/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/cache.json b/lib/libpmc/pmu-events/arch/x86/westmereep-sp/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/cache.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-sp/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/floating-point.json b/lib/libpmc/pmu-events/arch/x86/westmereep-sp/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-sp/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/frontend.json b/lib/libpmc/pmu-events/arch/x86/westmereep-sp/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/frontend.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-sp/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/memory.json b/lib/libpmc/pmu-events/arch/x86/westmereep-sp/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/memory.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-sp/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/other.json b/lib/libpmc/pmu-events/arch/x86/westmereep-sp/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/other.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-sp/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/pipeline.json b/lib/libpmc/pmu-events/arch/x86/westmereep-sp/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-sp/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/westmereep-sp/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereep-sp/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/westmereep-sp/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereex/cache.json b/lib/libpmc/pmu-events/arch/x86/westmereex/cache.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereex/cache.json rename to lib/libpmc/pmu-events/arch/x86/westmereex/cache.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereex/floating-point.json b/lib/libpmc/pmu-events/arch/x86/westmereex/floating-point.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereex/floating-point.json rename to lib/libpmc/pmu-events/arch/x86/westmereex/floating-point.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereex/frontend.json b/lib/libpmc/pmu-events/arch/x86/westmereex/frontend.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereex/frontend.json rename to lib/libpmc/pmu-events/arch/x86/westmereex/frontend.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereex/memory.json b/lib/libpmc/pmu-events/arch/x86/westmereex/memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereex/memory.json rename to lib/libpmc/pmu-events/arch/x86/westmereex/memory.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereex/other.json b/lib/libpmc/pmu-events/arch/x86/westmereex/other.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereex/other.json rename to lib/libpmc/pmu-events/arch/x86/westmereex/other.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereex/pipeline.json b/lib/libpmc/pmu-events/arch/x86/westmereex/pipeline.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereex/pipeline.json rename to lib/libpmc/pmu-events/arch/x86/westmereex/pipeline.json diff --git a/lib/libpmcstat/pmu-events/arch/x86/westmereex/virtual-memory.json b/lib/libpmc/pmu-events/arch/x86/westmereex/virtual-memory.json similarity index 100% rename from lib/libpmcstat/pmu-events/arch/x86/westmereex/virtual-memory.json rename to lib/libpmc/pmu-events/arch/x86/westmereex/virtual-memory.json diff --git a/lib/libpmcstat/pmu-events/jevents.c b/lib/libpmc/pmu-events/jevents.c similarity index 100% rename from lib/libpmcstat/pmu-events/jevents.c rename to lib/libpmc/pmu-events/jevents.c diff --git a/lib/libpmcstat/pmu-events/jevents.h b/lib/libpmc/pmu-events/jevents.h similarity index 100% rename from lib/libpmcstat/pmu-events/jevents.h rename to lib/libpmc/pmu-events/jevents.h diff --git a/lib/libpmcstat/pmu-events/jsmn.c b/lib/libpmc/pmu-events/jsmn.c similarity index 100% rename from lib/libpmcstat/pmu-events/jsmn.c rename to lib/libpmc/pmu-events/jsmn.c diff --git a/lib/libpmcstat/pmu-events/jsmn.h b/lib/libpmc/pmu-events/jsmn.h similarity index 100% rename from lib/libpmcstat/pmu-events/jsmn.h rename to lib/libpmc/pmu-events/jsmn.h diff --git a/lib/libpmcstat/pmu-events/json.c b/lib/libpmc/pmu-events/json.c similarity index 100% rename from lib/libpmcstat/pmu-events/json.c rename to lib/libpmc/pmu-events/json.c diff --git a/lib/libpmcstat/pmu-events/json.h b/lib/libpmc/pmu-events/json.h similarity index 100% rename from lib/libpmcstat/pmu-events/json.h rename to lib/libpmc/pmu-events/json.h diff --git a/lib/libpmcstat/pmu-events/list.h b/lib/libpmc/pmu-events/list.h similarity index 100% rename from lib/libpmcstat/pmu-events/list.h rename to lib/libpmc/pmu-events/list.h diff --git a/lib/libpmcstat/pmu-events/pmu-events.h b/lib/libpmc/pmu-events/pmu-events.h similarity index 100% rename from lib/libpmcstat/pmu-events/pmu-events.h rename to lib/libpmc/pmu-events/pmu-events.h diff --git a/lib/libpmcstat/Makefile b/lib/libpmcstat/Makefile index a20b14d174d4..5becabb5c957 100644 --- a/lib/libpmcstat/Makefile +++ b/lib/libpmcstat/Makefile @@ -1,38 +1,15 @@ # $FreeBSD$ PACKAGE=lib${LIB} LIB= pmcstat INTERNALLIB= SRCS= \ libpmcstat_event.c \ libpmcstat_image.c \ libpmcstat_logging.c \ libpmcstat_process.c \ libpmcstat_string.c \ - libpmcstat_symbol.c \ - libpmcstat_pmu_util.c + libpmcstat_symbol.c INCS= libpmcstat.h -CFLAGS+= -I${.CURDIR} - -.if ${MACHINE_CPUARCH} == "amd64" - -.if ${MACHINE_CPUARCH} == "aarch64" -EVENT_ARCH="arm64" -.elif ${MACHINE_CPUARCH} == "amd64" -EVENT_ARCH="x86" -.elif ${MACHINE_CPUARCH} == "powerpc" -EVENT_ARCH="powerpc" -.endif - -JEVENTS= ${BTOOLSPATH:U.}/pmu-events/jevents -# This file is built in a subdirectory so never try to rebuild -# it here due to missing meta file. -${JEVENTS}: .NOMETA - -libpmcstat_events.c: ${JEVENTS} - ${JEVENTS} ${EVENT_ARCH} ${.CURDIR}/pmu-events/arch libpmcstat_events.c -SRCS+= libpmcstat_events.c -.endif - .include diff --git a/lib/libpmcstat/libpmcstat.h b/lib/libpmcstat/libpmcstat.h index 77965b612e5c..3f5f2689f6b3 100644 --- a/lib/libpmcstat/libpmcstat.h +++ b/lib/libpmcstat/libpmcstat.h @@ -1,389 +1,387 @@ /*- * Copyright (c) 2005-2007, Joseph Koshy * Copyright (c) 2007 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by A. Joseph Koshy under * sponsorship from the FreeBSD Foundation and Google, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _LIBPMCSTAT_H_ #define _LIBPMCSTAT_H_ #include #include #include #include #define PMCSTAT_ALLOCATE 1 #define NSOCKPAIRFD 2 #define PARENTSOCKET 0 #define CHILDSOCKET 1 #define PMCSTAT_OPEN_FOR_READ 0 #define PMCSTAT_OPEN_FOR_WRITE 1 #define READPIPEFD 0 #define WRITEPIPEFD 1 #define NPIPEFD 2 #define PMCSTAT_NHASH 256 #define PMCSTAT_HASH_MASK 0xFF #define DEFAULT_SAMPLE_COUNT 65536 typedef const void *pmcstat_interned_string; struct pmc_plugins; enum pmcstat_state { PMCSTAT_FINISHED = 0, PMCSTAT_EXITING = 1, PMCSTAT_RUNNING = 2 }; struct pmcstat_ev { STAILQ_ENTRY(pmcstat_ev) ev_next; int ev_count; /* associated count if in sampling mode */ uint32_t ev_cpu; /* cpus for this event */ int ev_cumulative; /* show cumulative counts */ int ev_flags; /* PMC_F_* */ int ev_fieldskip; /* #leading spaces */ int ev_fieldwidth; /* print width */ enum pmc_mode ev_mode; /* desired mode */ char *ev_name; /* (derived) event name */ pmc_id_t ev_pmcid; /* allocated ID */ pmc_value_t ev_saved; /* for incremental counts */ char *ev_spec; /* event specification */ }; struct pmcstat_target { SLIST_ENTRY(pmcstat_target) pt_next; pid_t pt_pid; }; struct pmcstat_args { int pa_flags; /* argument flags */ #define FLAG_HAS_TARGET 0x00000001 /* process target */ #define FLAG_HAS_WAIT_INTERVAL 0x00000002 /* -w secs */ #define FLAG_HAS_OUTPUT_LOGFILE 0x00000004 /* -O file or pipe */ #define FLAG_HAS_COMMANDLINE 0x00000008 /* command */ #define FLAG_HAS_SAMPLING_PMCS 0x00000010 /* -S or -P */ #define FLAG_HAS_COUNTING_PMCS 0x00000020 /* -s or -p */ #define FLAG_HAS_PROCESS_PMCS 0x00000040 /* -P or -p */ #define FLAG_HAS_SYSTEM_PMCS 0x00000080 /* -S or -s */ #define FLAG_HAS_PIPE 0x00000100 /* implicit log */ #define FLAG_READ_LOGFILE 0x00000200 /* -R file */ #define FLAG_DO_GPROF 0x00000400 /* -g */ #define FLAG_HAS_SAMPLESDIR 0x00000800 /* -D dir */ #define FLAG_HAS_KERNELPATH 0x00001000 /* -k kernel */ #define FLAG_DO_PRINT 0x00002000 /* -o */ #define FLAG_DO_CALLGRAPHS 0x00004000 /* -G or -F */ #define FLAG_DO_ANNOTATE 0x00008000 /* -m */ #define FLAG_DO_TOP 0x00010000 /* -T */ #define FLAG_DO_ANALYSIS 0x00020000 /* -g or -G or -m or -T */ #define FLAGS_HAS_CPUMASK 0x00040000 /* -c */ #define FLAG_HAS_DURATION 0x00080000 /* -l secs */ #define FLAG_DO_WIDE_GPROF_HC 0x00100000 /* -e */ #define FLAG_SKIP_TOP_FN_RES 0x00200000 /* -I */ #define FLAG_FILTER_THREAD_ID 0x00400000 /* -L */ int pa_required; /* required features */ int pa_pplugin; /* pre-processing plugin */ int pa_plugin; /* analysis plugin */ int pa_verbosity; /* verbosity level */ FILE *pa_printfile; /* where to send printed output */ int pa_logfd; /* output log file */ char *pa_inputpath; /* path to input log */ char *pa_outputpath; /* path to output log */ void *pa_logparser; /* log file parser */ const char *pa_fsroot; /* FS root where executables reside */ char *pa_kernel; /* pathname of the kernel */ const char *pa_samplesdir; /* directory for profile files */ const char *pa_mapfilename;/* mapfile name */ FILE *pa_graphfile; /* where to send the callgraph */ int pa_graphdepth; /* print depth for callgraphs */ double pa_interval; /* printing interval in seconds */ cpuset_t pa_cpumask; /* filter for CPUs analysed */ int pa_ctdumpinstr; /* dump instructions with calltree */ int pa_topmode; /* delta or accumulative */ int pa_toptty; /* output to tty or file */ int pa_topcolor; /* terminal support color */ int pa_mergepmc; /* merge PMC with same name */ double pa_duration; /* time duration */ uint32_t pa_tid; int pa_argc; char **pa_argv; STAILQ_HEAD(, pmcstat_ev) pa_events; SLIST_HEAD(, pmcstat_target) pa_targets; }; /* * Each function symbol tracked by pmcstat(8). */ struct pmcstat_symbol { pmcstat_interned_string ps_name; uint64_t ps_start; uint64_t ps_end; }; /* * A 'pmcstat_image' structure describes an executable program on * disk. 'pi_execpath' is a cookie representing the pathname of * the executable. 'pi_start' and 'pi_end' are the least and greatest * virtual addresses for the text segments in the executable. * 'pi_gmonlist' contains a linked list of gmon.out files associated * with this image. */ enum pmcstat_image_type { PMCSTAT_IMAGE_UNKNOWN = 0, /* never looked at the image */ PMCSTAT_IMAGE_INDETERMINABLE, /* can't tell what the image is */ PMCSTAT_IMAGE_ELF32, /* ELF 32 bit object */ PMCSTAT_IMAGE_ELF64, /* ELF 64 bit object */ PMCSTAT_IMAGE_AOUT /* AOUT object */ }; struct pmcstat_image { LIST_ENTRY(pmcstat_image) pi_next; /* hash link */ pmcstat_interned_string pi_execpath; /* cookie */ pmcstat_interned_string pi_samplename; /* sample path name */ pmcstat_interned_string pi_fullpath; /* path to FS object */ pmcstat_interned_string pi_name; /* display name */ enum pmcstat_image_type pi_type; /* executable type */ /* * Executables have pi_start and pi_end; these are zero * for shared libraries. */ uintfptr_t pi_start; /* start address (inclusive) */ uintfptr_t pi_end; /* end address (exclusive) */ uintfptr_t pi_entry; /* entry address */ uintfptr_t pi_vaddr; /* virtual address where loaded */ int pi_isdynamic; /* whether a dynamic object */ int pi_iskernelmodule; pmcstat_interned_string pi_dynlinkerpath; /* path in .interp */ /* All symbols associated with this object. */ struct pmcstat_symbol *pi_symbols; size_t pi_symcount; /* Handle to addr2line for this image. */ FILE *pi_addr2line; /* * Plugins private data */ /* gprof: * An image can be associated with one or more gmon.out files; * one per PMC. */ LIST_HEAD(,pmcstat_gmonfile) pi_gmlist; }; extern LIST_HEAD(pmcstat_image_hash_list, pmcstat_image) pmcstat_image_hash[PMCSTAT_NHASH]; /* * A simple implementation of interned strings. Each interned string * is assigned a unique address, so that subsequent string compares * can be done by a simple pointer comparison instead of using * strcmp(). This speeds up hash table lookups and saves memory if * duplicate strings are the norm. */ struct pmcstat_string { LIST_ENTRY(pmcstat_string) ps_next; /* hash link */ int ps_len; int ps_hash; char *ps_string; }; /* * A 'pmcstat_pcmap' structure maps a virtual address range to an * underlying 'pmcstat_image' descriptor. */ struct pmcstat_pcmap { TAILQ_ENTRY(pmcstat_pcmap) ppm_next; uintfptr_t ppm_lowpc; uintfptr_t ppm_highpc; struct pmcstat_image *ppm_image; }; /* * A 'pmcstat_process' structure models processes. Each process is * associated with a set of pmcstat_pcmap structures that map * addresses inside it to executable objects. This set is implemented * as a list, kept sorted in ascending order of mapped addresses. * * 'pp_pid' holds the pid of the process. When a process exits, the * 'pp_isactive' field is set to zero, but the process structure is * not immediately reclaimed because there may still be samples in the * log for this process. */ struct pmcstat_process { LIST_ENTRY(pmcstat_process) pp_next; /* hash-next */ pid_t pp_pid; /* associated pid */ int pp_isactive; /* whether active */ uintfptr_t pp_entryaddr; /* entry address */ TAILQ_HEAD(,pmcstat_pcmap) pp_map; /* address range map */ }; extern LIST_HEAD(pmcstat_process_hash_list, pmcstat_process) pmcstat_process_hash[PMCSTAT_NHASH]; /* * 'pmcstat_pmcrecord' is a mapping from PMC ids to human-readable * names. */ struct pmcstat_pmcrecord { LIST_ENTRY(pmcstat_pmcrecord) pr_next; pmc_id_t pr_pmcid; int pr_pmcin; pmcstat_interned_string pr_pmcname; int pr_samples; int pr_dubious_frames; struct pmcstat_pmcrecord *pr_merge; }; extern LIST_HEAD(pmcstat_pmcs, pmcstat_pmcrecord) pmcstat_pmcs; /* PMC list */ struct pmc_plugins { const char *pl_name; /* configure */ int (*pl_configure)(char *opt); /* init and shutdown */ int (*pl_init)(void); void (*pl_shutdown)(FILE *mf); /* sample processing */ void (*pl_process)(struct pmcstat_process *pp, struct pmcstat_pmcrecord *pmcr, uint32_t nsamples, uintfptr_t *cc, int usermode, uint32_t cpu); /* image */ void (*pl_initimage)(struct pmcstat_image *pi); void (*pl_shutdownimage)(struct pmcstat_image *pi); /* pmc */ void (*pl_newpmc)(pmcstat_interned_string ps, struct pmcstat_pmcrecord *pr); /* top display */ void (*pl_topdisplay)(void); /* top keypress */ int (*pl_topkeypress)(int c, void *w); }; /* * Misc. statistics */ struct pmcstat_stats { int ps_exec_aout; /* # a.out executables seen */ int ps_exec_elf; /* # elf executables seen */ int ps_exec_errors; /* # errors processing executables */ int ps_exec_indeterminable; /* # unknown executables seen */ int ps_samples_total; /* total number of samples processed */ int ps_samples_skipped; /* #samples filtered out for any reason */ int ps_samples_unknown_offset; /* #samples of rank 0 not in a map */ int ps_samples_indeterminable; /* #samples in indeterminable images */ int ps_samples_unknown_function;/* #samples with unknown function at offset */ int ps_callchain_dubious_frames;/* #dubious frame pointers seen */ }; __BEGIN_DECLS int pmcstat_symbol_compare(const void *a, const void *b); struct pmcstat_symbol *pmcstat_symbol_search(struct pmcstat_image *image, uintfptr_t addr); void pmcstat_image_add_symbols(struct pmcstat_image *image, Elf *e, Elf_Scn *scn, GElf_Shdr *sh); const char *pmcstat_string_unintern(pmcstat_interned_string _is); pmcstat_interned_string pmcstat_string_intern(const char *_s); int pmcstat_string_compute_hash(const char *s); pmcstat_interned_string pmcstat_string_lookup(const char *_s); void pmcstat_image_get_elf_params(struct pmcstat_image *image, struct pmcstat_args *args); struct pmcstat_image * pmcstat_image_from_path(pmcstat_interned_string internedpath, int iskernelmodule, struct pmcstat_args *args, struct pmc_plugins *plugins); int pmcstat_string_lookup_hash(pmcstat_interned_string _is); void pmcstat_process_elf_exec(struct pmcstat_process *_pp, struct pmcstat_image *_image, uintfptr_t _entryaddr, struct pmcstat_args *args, struct pmc_plugins *plugins, struct pmcstat_stats *pmcstat_stats); void pmcstat_image_link(struct pmcstat_process *_pp, struct pmcstat_image *_i, uintfptr_t _lpc); void pmcstat_process_aout_exec(struct pmcstat_process *_pp, struct pmcstat_image *_image, uintfptr_t _entryaddr); void pmcstat_process_exec(struct pmcstat_process *_pp, pmcstat_interned_string _path, uintfptr_t _entryaddr, struct pmcstat_args *args, struct pmc_plugins *plugins, struct pmcstat_stats *pmcstat_stats); void pmcstat_image_determine_type(struct pmcstat_image *_image, struct pmcstat_args *args); void pmcstat_image_get_aout_params(struct pmcstat_image *_image, struct pmcstat_args *args); struct pmcstat_pcmap *pmcstat_process_find_map(struct pmcstat_process *_p, uintfptr_t _pc); void pmcstat_initialize_logging(struct pmcstat_process **pmcstat_kernproc, struct pmcstat_args *args, struct pmc_plugins *plugins, int *pmcstat_npmcs, int *pmcstat_mergepmc); void pmcstat_shutdown_logging(struct pmcstat_args *args, struct pmc_plugins *plugins, struct pmcstat_stats *pmcstat_stats); struct pmcstat_process *pmcstat_process_lookup(pid_t _pid, int _allocate); void pmcstat_clone_event_descriptor(struct pmcstat_ev *ev, const cpuset_t *cpumask, struct pmcstat_args *args); void pmcstat_create_process(int *pmcstat_sockpair, struct pmcstat_args *args, int pmcstat_kq); void pmcstat_start_process(int *pmcstat_sockpair); void pmcstat_attach_pmcs(struct pmcstat_args *args); struct pmcstat_symbol *pmcstat_symbol_search_by_name(struct pmcstat_process *pp, const char *pi_name, const char *name, uintptr_t *, uintptr_t *); void pmcstat_string_initialize(void); void pmcstat_string_shutdown(void); int pmcstat_analyze_log(struct pmcstat_args *args, struct pmc_plugins *plugins, struct pmcstat_stats *pmcstat_stats, struct pmcstat_process *pmcstat_kernproc, int pmcstat_mergepmc, int *pmcstat_npmcs, int *ps_samples_period); int pmcstat_open_log(const char *_p, int _mode); int pmcstat_close_log(struct pmcstat_args *args); -uint64_t pmcstat_pmu_sample_rate_get(const char *); - __END_DECLS #endif /* !_LIBPMCSTAT_H_ */ diff --git a/lib/libpmcstat/libpmcstat_logging.c b/lib/libpmcstat/libpmcstat_logging.c index 71ee524bbd8c..42054e636b4b 100644 --- a/lib/libpmcstat/libpmcstat_logging.c +++ b/lib/libpmcstat/libpmcstat_logging.c @@ -1,723 +1,684 @@ /*- * Copyright (c) 2003-2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libpmcstat.h" /* * Get PMC record by id, apply merge policy. */ static struct pmcstat_pmcrecord * pmcstat_lookup_pmcid(pmc_id_t pmcid, int pmcstat_mergepmc) { struct pmcstat_pmcrecord *pr; LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) { if (pr->pr_pmcid == pmcid) { if (pmcstat_mergepmc) return pr->pr_merge; return pr; } } return NULL; } /* * Add a {pmcid,name} mapping. */ static void pmcstat_pmcid_add(pmc_id_t pmcid, pmcstat_interned_string ps, struct pmcstat_args *args, struct pmc_plugins *plugins, int *pmcstat_npmcs) { struct pmcstat_pmcrecord *pr, *prm; /* Replace an existing name for the PMC. */ prm = NULL; LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) if (pr->pr_pmcid == pmcid) { pr->pr_pmcname = ps; return; } else if (pr->pr_pmcname == ps) prm = pr; /* * Otherwise, allocate a new descriptor and call the * plugins hook. */ if ((pr = malloc(sizeof(*pr))) == NULL) err(EX_OSERR, "ERROR: Cannot allocate pmc record"); pr->pr_pmcid = pmcid; pr->pr_pmcname = ps; pr->pr_pmcin = (*pmcstat_npmcs)++; pr->pr_samples = 0; pr->pr_dubious_frames = 0; pr->pr_merge = prm == NULL ? pr : prm; LIST_INSERT_HEAD(&pmcstat_pmcs, pr, pr_next); if (plugins[args->pa_pplugin].pl_newpmc != NULL) plugins[args->pa_pplugin].pl_newpmc(ps, pr); if (plugins[args->pa_plugin].pl_newpmc != NULL) plugins[args->pa_plugin].pl_newpmc(ps, pr); } /* * Unmap images in the range [start..end) associated with process * 'pp'. */ static void pmcstat_image_unmap(struct pmcstat_process *pp, uintfptr_t start, uintfptr_t end) { struct pmcstat_pcmap *pcm, *pcmtmp, *pcmnew; assert(pp != NULL); assert(start < end); /* * Cases: * - we could have the range completely in the middle of an * existing pcmap; in this case we have to split the pcmap * structure into two (i.e., generate a 'hole'). * - we could have the range covering multiple pcmaps; these * will have to be removed. * - we could have either 'start' or 'end' falling in the * middle of a pcmap; in this case shorten the entry. */ TAILQ_FOREACH_SAFE(pcm, &pp->pp_map, ppm_next, pcmtmp) { assert(pcm->ppm_lowpc < pcm->ppm_highpc); if (pcm->ppm_highpc <= start) continue; if (pcm->ppm_lowpc >= end) return; if (pcm->ppm_lowpc >= start && pcm->ppm_highpc <= end) { /* * The current pcmap is completely inside the * unmapped range: remove it entirely. */ TAILQ_REMOVE(&pp->pp_map, pcm, ppm_next); free(pcm); } else if (pcm->ppm_lowpc < start && pcm->ppm_highpc > end) { /* * Split this pcmap into two; curtail the * current map to end at [start-1], and start * the new one at [end]. */ if ((pcmnew = malloc(sizeof(*pcmnew))) == NULL) err(EX_OSERR, "ERROR: Cannot split a map entry"); pcmnew->ppm_image = pcm->ppm_image; pcmnew->ppm_lowpc = end; pcmnew->ppm_highpc = pcm->ppm_highpc; pcm->ppm_highpc = start; TAILQ_INSERT_AFTER(&pp->pp_map, pcm, pcmnew, ppm_next); return; } else if (pcm->ppm_lowpc < start && pcm->ppm_highpc <= end) pcm->ppm_highpc = start; else if (pcm->ppm_lowpc >= start && pcm->ppm_highpc > end) pcm->ppm_lowpc = end; else assert(0); } } /* * Convert a hwpmc(4) log to profile information. A system-wide * callgraph is generated if FLAG_DO_CALLGRAPHS is set. gmon.out * files usable by gprof(1) are created if FLAG_DO_GPROF is set. */ int pmcstat_analyze_log(struct pmcstat_args *args, struct pmc_plugins *plugins, struct pmcstat_stats *pmcstat_stats, struct pmcstat_process *pmcstat_kernproc, int pmcstat_mergepmc, int *pmcstat_npmcs, int *ps_samples_period) { uint32_t cpu, cpuflags; - uintfptr_t pc; pid_t pid; struct pmcstat_image *image; struct pmcstat_process *pp, *ppnew; struct pmcstat_pcmap *ppm, *ppmtmp; struct pmclog_ev ev; struct pmcstat_pmcrecord *pmcr; pmcstat_interned_string image_path; assert(args->pa_flags & FLAG_DO_ANALYSIS); if (elf_version(EV_CURRENT) == EV_NONE) err(EX_UNAVAILABLE, "Elf library initialization failed"); while (pmclog_read(args->pa_logparser, &ev) == 0) { assert(ev.pl_state == PMCLOG_OK); switch (ev.pl_type) { case PMCLOG_TYPE_INITIALIZE: if ((ev.pl_u.pl_i.pl_version & 0xFF000000) != PMC_VERSION_MAJOR << 24 && args->pa_verbosity > 0) warnx( "WARNING: Log version 0x%x does not match compiled version 0x%x.", ev.pl_u.pl_i.pl_version, PMC_VERSION_MAJOR); break; case PMCLOG_TYPE_MAP_IN: /* * Introduce an address range mapping for a * userland process or the kernel (pid == -1). * * We always allocate a process descriptor so * that subsequent samples seen for this * address range are mapped to the current * object being mapped in. */ pid = ev.pl_u.pl_mi.pl_pid; if (pid == -1) pp = pmcstat_kernproc; else pp = pmcstat_process_lookup(pid, PMCSTAT_ALLOCATE); assert(pp != NULL); image_path = pmcstat_string_intern(ev.pl_u.pl_mi. pl_pathname); image = pmcstat_image_from_path(image_path, pid == -1, args, plugins); if (image->pi_type == PMCSTAT_IMAGE_UNKNOWN) pmcstat_image_determine_type(image, args); if (image->pi_type != PMCSTAT_IMAGE_INDETERMINABLE) pmcstat_image_link(pp, image, ev.pl_u.pl_mi.pl_start); break; case PMCLOG_TYPE_MAP_OUT: /* * Remove an address map. */ pid = ev.pl_u.pl_mo.pl_pid; if (pid == -1) pp = pmcstat_kernproc; else pp = pmcstat_process_lookup(pid, 0); if (pp == NULL) /* unknown process */ break; pmcstat_image_unmap(pp, ev.pl_u.pl_mo.pl_start, ev.pl_u.pl_mo.pl_end); break; - case PMCLOG_TYPE_PCSAMPLE: - /* - * Note: the `PCSAMPLE' log entry is not - * generated by hpwmc(4) after version 2. - */ - - /* - * We bring in the gmon file for the image - * currently associated with the PMC & pid - * pair and increment the appropriate entry - * bin inside this. - */ - pmcstat_stats->ps_samples_total++; - *ps_samples_period += 1; - - pc = ev.pl_u.pl_s.pl_pc; - pp = pmcstat_process_lookup(ev.pl_u.pl_s.pl_pid, - PMCSTAT_ALLOCATE); - - /* Get PMC record. */ - pmcr = pmcstat_lookup_pmcid(ev.pl_u.pl_s.pl_pmcid, pmcstat_mergepmc); - assert(pmcr != NULL); - pmcr->pr_samples++; - - /* - * Call the plugins processing - * TODO: move pmcstat_process_find_map inside plugins - */ - - if (plugins[args->pa_pplugin].pl_process != NULL) - plugins[args->pa_pplugin].pl_process( - pp, pmcr, 1, &pc, - pmcstat_process_find_map(pp, pc) != NULL, 0); - plugins[args->pa_plugin].pl_process( - pp, pmcr, 1, &pc, - pmcstat_process_find_map(pp, pc) != NULL, 0); - break; - case PMCLOG_TYPE_CALLCHAIN: pmcstat_stats->ps_samples_total++; *ps_samples_period += 1; cpuflags = ev.pl_u.pl_cc.pl_cpuflags; cpu = PMC_CALLCHAIN_CPUFLAGS_TO_CPU(cpuflags); if ((args->pa_flags & FLAG_FILTER_THREAD_ID) && args->pa_tid != ev.pl_u.pl_cc.pl_tid) { pmcstat_stats->ps_samples_skipped++; break; } /* Filter on the CPU id. */ if (!CPU_ISSET(cpu, &(args->pa_cpumask))) { pmcstat_stats->ps_samples_skipped++; break; } pp = pmcstat_process_lookup(ev.pl_u.pl_cc.pl_pid, PMCSTAT_ALLOCATE); /* Get PMC record. */ pmcr = pmcstat_lookup_pmcid(ev.pl_u.pl_cc.pl_pmcid, pmcstat_mergepmc); assert(pmcr != NULL); pmcr->pr_samples++; /* * Call the plugins processing */ if (plugins[args->pa_pplugin].pl_process != NULL) plugins[args->pa_pplugin].pl_process( pp, pmcr, ev.pl_u.pl_cc.pl_npc, ev.pl_u.pl_cc.pl_pc, PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(cpuflags), cpu); plugins[args->pa_plugin].pl_process( pp, pmcr, ev.pl_u.pl_cc.pl_npc, ev.pl_u.pl_cc.pl_pc, PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(cpuflags), cpu); break; case PMCLOG_TYPE_PMCALLOCATE: /* * Record the association pmc id between this * PMC and its name. */ pmcstat_pmcid_add(ev.pl_u.pl_a.pl_pmcid, pmcstat_string_intern(ev.pl_u.pl_a.pl_evname), args, plugins, pmcstat_npmcs); break; case PMCLOG_TYPE_PMCALLOCATEDYN: /* * Record the association pmc id between this * PMC and its name. */ pmcstat_pmcid_add(ev.pl_u.pl_ad.pl_pmcid, pmcstat_string_intern(ev.pl_u.pl_ad.pl_evname), args, plugins, pmcstat_npmcs); break; case PMCLOG_TYPE_PROCEXEC: /* * Change the executable image associated with * a process. */ pp = pmcstat_process_lookup(ev.pl_u.pl_x.pl_pid, PMCSTAT_ALLOCATE); /* delete the current process map */ TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, ppmtmp) { TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next); free(ppm); } /* * Associate this process image. */ image_path = pmcstat_string_intern( ev.pl_u.pl_x.pl_pathname); assert(image_path != NULL); pmcstat_process_exec(pp, image_path, ev.pl_u.pl_x.pl_entryaddr, args, plugins, pmcstat_stats); break; case PMCLOG_TYPE_PROCEXIT: /* * Due to the way the log is generated, the * last few samples corresponding to a process * may appear in the log after the process * exit event is recorded. Thus we keep the * process' descriptor and associated data * structures around, but mark the process as * having exited. */ pp = pmcstat_process_lookup(ev.pl_u.pl_e.pl_pid, 0); if (pp == NULL) break; pp->pp_isactive = 0; /* mark as a zombie */ break; case PMCLOG_TYPE_SYSEXIT: pp = pmcstat_process_lookup(ev.pl_u.pl_se.pl_pid, 0); if (pp == NULL) break; pp->pp_isactive = 0; /* make a zombie */ break; case PMCLOG_TYPE_PROCFORK: /* * Allocate a process descriptor for the new * (child) process. */ ppnew = pmcstat_process_lookup(ev.pl_u.pl_f.pl_newpid, PMCSTAT_ALLOCATE); /* * If we had been tracking the parent, clone * its address maps. */ pp = pmcstat_process_lookup(ev.pl_u.pl_f.pl_oldpid, 0); if (pp == NULL) break; TAILQ_FOREACH(ppm, &pp->pp_map, ppm_next) pmcstat_image_link(ppnew, ppm->ppm_image, ppm->ppm_lowpc); break; default: /* other types of entries are not relevant */ break; } } if (ev.pl_state == PMCLOG_EOF) return (PMCSTAT_FINISHED); else if (ev.pl_state == PMCLOG_REQUIRE_DATA) return (PMCSTAT_RUNNING); err(EX_DATAERR, - "ERROR: event parsing failed (record %jd, offset 0x%jx)", - (uintmax_t) ev.pl_count + 1, ev.pl_offset); + "ERROR: event parsing failed state: %d type: %d (record %jd, offset 0x%jx)", + ev.pl_state, ev.pl_type, (uintmax_t) ev.pl_count + 1, ev.pl_offset); } /* * Open a log file, for reading or writing. * * The function returns the fd of a successfully opened log or -1 in * case of failure. */ int pmcstat_open_log(const char *path, int mode) { int error, fd, cfd; size_t hlen; const char *p, *errstr; struct addrinfo hints, *res, *res0; char hostname[MAXHOSTNAMELEN]; errstr = NULL; fd = -1; /* * If 'path' is "-" then open one of stdin or stdout depending * on the value of 'mode'. * * If 'path' contains a ':' and does not start with a '/' or '.', * and is being opened for writing, treat it as a "host:port" * specification and open a network socket. * * Otherwise, treat 'path' as a file name and open that. */ if (path[0] == '-' && path[1] == '\0') fd = (mode == PMCSTAT_OPEN_FOR_READ) ? 0 : 1; else if (path[0] != '/' && path[0] != '.' && strchr(path, ':') != NULL) { p = strrchr(path, ':'); hlen = p - path; if (p == path || hlen >= sizeof(hostname)) { errstr = strerror(EINVAL); goto done; } assert(hlen < sizeof(hostname)); (void) strncpy(hostname, path, hlen); hostname[hlen] = '\0'; (void) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((error = getaddrinfo(hostname, p+1, &hints, &res0)) != 0) { errstr = gai_strerror(error); goto done; } fd = -1; for (res = res0; res; res = res->ai_next) { if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) { errstr = strerror(errno); continue; } if (mode == PMCSTAT_OPEN_FOR_READ) { if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) { errstr = strerror(errno); (void) close(fd); fd = -1; continue; } listen(fd, 1); cfd = accept(fd, NULL, NULL); (void) close(fd); if (cfd < 0) { errstr = strerror(errno); fd = -1; break; } fd = cfd; } else { if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) { errstr = strerror(errno); (void) close(fd); fd = -1; continue; } } errstr = NULL; break; } freeaddrinfo(res0); } else if ((fd = open(path, mode == PMCSTAT_OPEN_FOR_READ ? O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) errstr = strerror(errno); done: if (errstr) errx(EX_OSERR, "ERROR: Cannot open \"%s\" for %s: %s.", path, (mode == PMCSTAT_OPEN_FOR_READ ? "reading" : "writing"), errstr); return (fd); } /* * Close a logfile, after first flushing all in-module queued data. */ int pmcstat_close_log(struct pmcstat_args *args) { /* If a local logfile is configured ask the kernel to stop * and flush data. Kernel will close the file when data is flushed * so keep the status to EXITING. */ if (args->pa_logfd != -1) { if (pmc_close_logfile() < 0) err(EX_OSERR, "ERROR: logging failed"); } return (args->pa_flags & FLAG_HAS_PIPE ? PMCSTAT_EXITING : PMCSTAT_FINISHED); } /* * Initialize module. */ void pmcstat_initialize_logging(struct pmcstat_process **pmcstat_kernproc, struct pmcstat_args *args, struct pmc_plugins *plugins, int *pmcstat_npmcs, int *pmcstat_mergepmc) { struct pmcstat_process *pmcstat_kp; int i; /* use a convenient format for 'ldd' output */ if (setenv("LD_TRACE_LOADED_OBJECTS_FMT1","%o \"%p\" %x\n",1) != 0) err(EX_OSERR, "ERROR: Cannot setenv"); /* Initialize hash tables */ pmcstat_string_initialize(); for (i = 0; i < PMCSTAT_NHASH; i++) { LIST_INIT(&pmcstat_image_hash[i]); LIST_INIT(&pmcstat_process_hash[i]); } /* * Create a fake 'process' entry for the kernel with pid -1. * hwpmc(4) will subsequently inform us about where the kernel * and any loaded kernel modules are mapped. */ if ((pmcstat_kp = pmcstat_process_lookup((pid_t) -1, PMCSTAT_ALLOCATE)) == NULL) err(EX_OSERR, "ERROR: Cannot initialize logging"); *pmcstat_kernproc = pmcstat_kp; /* PMC count. */ *pmcstat_npmcs = 0; /* Merge PMC with same name. */ *pmcstat_mergepmc = args->pa_mergepmc; /* * Initialize plugins */ if (plugins[args->pa_pplugin].pl_init != NULL) plugins[args->pa_pplugin].pl_init(); if (plugins[args->pa_plugin].pl_init != NULL) plugins[args->pa_plugin].pl_init(); } /* * Shutdown module. */ void pmcstat_shutdown_logging(struct pmcstat_args *args, struct pmc_plugins *plugins, struct pmcstat_stats *pmcstat_stats) { struct pmcstat_image *pi, *pitmp; struct pmcstat_process *pp, *pptmp; struct pmcstat_pcmap *ppm, *ppmtmp; FILE *mf; int i; /* determine where to send the map file */ mf = NULL; if (args->pa_mapfilename != NULL) mf = (strcmp(args->pa_mapfilename, "-") == 0) ? args->pa_printfile : fopen(args->pa_mapfilename, "w"); if (mf == NULL && args->pa_flags & FLAG_DO_GPROF && args->pa_verbosity >= 2) mf = args->pa_printfile; if (mf) (void) fprintf(mf, "MAP:\n"); /* * Shutdown the plugins */ if (plugins[args->pa_plugin].pl_shutdown != NULL) plugins[args->pa_plugin].pl_shutdown(mf); if (plugins[args->pa_pplugin].pl_shutdown != NULL) plugins[args->pa_pplugin].pl_shutdown(mf); for (i = 0; i < PMCSTAT_NHASH; i++) { LIST_FOREACH_SAFE(pi, &pmcstat_image_hash[i], pi_next, pitmp) { if (plugins[args->pa_plugin].pl_shutdownimage != NULL) plugins[args->pa_plugin].pl_shutdownimage(pi); if (plugins[args->pa_pplugin].pl_shutdownimage != NULL) plugins[args->pa_pplugin].pl_shutdownimage(pi); free(pi->pi_symbols); if (pi->pi_addr2line != NULL) pclose(pi->pi_addr2line); LIST_REMOVE(pi, pi_next); free(pi); } LIST_FOREACH_SAFE(pp, &pmcstat_process_hash[i], pp_next, pptmp) { TAILQ_FOREACH_SAFE(ppm, &pp->pp_map, ppm_next, ppmtmp) { TAILQ_REMOVE(&pp->pp_map, ppm, ppm_next); free(ppm); } LIST_REMOVE(pp, pp_next); free(pp); } } pmcstat_string_shutdown(); /* * Print errors unless -q was specified. Print all statistics * if verbosity > 1. */ #define PRINT(N,V) do { \ if (pmcstat_stats->ps_##V || args->pa_verbosity >= 2) \ (void) fprintf(args->pa_printfile, " %-40s %d\n",\ N, pmcstat_stats->ps_##V); \ } while (0) if (args->pa_verbosity >= 1 && (args->pa_flags & FLAG_DO_ANALYSIS)) { (void) fprintf(args->pa_printfile, "CONVERSION STATISTICS:\n"); PRINT("#exec/a.out", exec_aout); PRINT("#exec/elf", exec_elf); PRINT("#exec/unknown", exec_indeterminable); PRINT("#exec handling errors", exec_errors); PRINT("#samples/total", samples_total); PRINT("#samples/unclaimed", samples_unknown_offset); PRINT("#samples/unknown-object", samples_indeterminable); PRINT("#samples/unknown-function", samples_unknown_function); PRINT("#callchain/dubious-frames", callchain_dubious_frames); } if (mf) (void) fclose(mf); } diff --git a/lib/libpmcstat/libpmcstat_pmu_util.c b/lib/libpmcstat/libpmcstat_pmu_util.c deleted file mode 100644 index 915856f1998a..000000000000 --- a/lib/libpmcstat/libpmcstat_pmu_util.c +++ /dev/null @@ -1,164 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2018, Matthew Macy - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pmu-events/pmu-events.h" - -#if defined(__amd64__) -struct pmu_alias { - const char *pa_alias; - const char *pa_name; -}; -static struct pmu_alias pmu_alias_table[] = { - { "UNHALTED_CORE_CYCLES", "CPU_CLK_UNHALTED.THREAD_P_ANY"}, - { "UNHALTED-CORE-CYCLES", "CPU_CLK_UNHALTED.THREAD_P_ANY"}, - { "LLC_MISSES", "LONGEST_LAT_CACHE.MISS"}, - { "LLC-MISSES", "LONGEST_LAT_CACHE.MISS"}, - { "LLC_REFERENCE", "LONGEST_LAT_CACHE.REFERENCE"}, - { "LLC-REFERENCE", "LONGEST_LAT_CACHE.REFERENCE"}, - { "LLC_MISS_RHITM", "mem_load_l3_miss_retired.remote_hitm"}, - { "LLC-MISS-RHITM", "mem_load_l3_miss_retired.remote_hitm"}, - { "RESOURCE_STALL", "RESOURCE_STALLS.ANY"}, - { "RESOURCE_STALLS_ANY", "RESOURCE_STALLS.ANY"}, - { "BRANCH_INSTRUCTION_RETIRED", "BR_INST_RETIRED.ALL_BRANCHES"}, - { "BRANCH-INSTRUCTION-RETIRED", "BR_INST_RETIRED.ALL_BRANCHES"}, - { "BRANCH_MISSES_RETIRED", "BR_MISP_RETIRED.ALL_BRANCHES"}, - { "BRANCH-MISSES-RETIRED", "BR_MISP_RETIRED.ALL_BRANCHES"}, - { NULL, NULL }, -}; - -static const char * -pmu_alias_get(const char *name) -{ - struct pmu_alias *pa; - - for (pa = pmu_alias_table; pa->pa_alias != NULL; pa++) - if (strcasecmp(name, pa->pa_alias) == 0) - return (pa->pa_name); - return (name); -} - -struct pmu_event_desc { - uint32_t ped_umask; - uint32_t ped_event; - uint64_t ped_period; -}; - -static const struct pmu_events_map * -pmu_events_map_get(void) -{ - size_t s; - char buf[64]; - const struct pmu_events_map *pme; - - if (sysctlbyname("kern.hwpmc.cpuid", (void *)NULL, &s, - (void *)NULL, 0) == -1) - return (NULL); - if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, - (void *)NULL, 0) == -1) - return (NULL); - for (pme = pmu_events_map; pme->cpuid != NULL; pme++) - if (strcmp(buf, pme->cpuid) == 0) - return (pme); - return (NULL); -} - -static const struct pmu_event * -pmu_event_get(const char *event_name) -{ - const struct pmu_events_map *pme; - const struct pmu_event *pe; - - if ((pme = pmu_events_map_get()) == NULL) - return (NULL); - for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { - if (pe->name == NULL) - continue; - if (strcasecmp(pe->name, event_name) == 0) - return (pe); - } - return (NULL); -} - -static int -pmu_parse_event(struct pmu_event_desc *ped, const char *eventin) -{ - char *event; - char *kvp, *key, *value; - - if ((event = strdup(eventin)) == NULL) - return (ENOMEM); - bzero(ped, sizeof(*ped)); - while ((kvp = strsep(&event, ",")) != NULL) { - key = strsep(&kvp, "="); - if (key == NULL) - abort(); - value = kvp; - if (strcmp(key, "umask") == 0) - ped->ped_umask = strtol(value, NULL, 16); - if (strcmp(key, "event") == 0) - ped->ped_event = strtol(value, NULL, 16); - if (strcmp(key, "period") == 0) - ped->ped_period = strtol(value, NULL, 10); - } - free(event); - return (0); -} - -uint64_t -pmcstat_pmu_sample_rate_get(const char *event_name) -{ - const struct pmu_event *pe; - struct pmu_event_desc ped; - - event_name = pmu_alias_get(event_name); - if ((pe = pmu_event_get(event_name)) == NULL) - return (DEFAULT_SAMPLE_COUNT); - if (pe->alias && (pe = pmu_event_get(pe->alias)) == NULL) - return (DEFAULT_SAMPLE_COUNT); - if (pe->event == NULL) - return (DEFAULT_SAMPLE_COUNT); - if (pmu_parse_event(&ped, pe->event)) - return (DEFAULT_SAMPLE_COUNT); - return (ped.ped_period); -} - -#else -uint64_t pmcstat_pmu_sample_rate_get(const char *event_name __unused) { return (DEFAULT_SAMPLE_COUNT); } -#endif diff --git a/sys/dev/hwpmc/hwpmc_core.c b/sys/dev/hwpmc/hwpmc_core.c index 9fedfc0f32fc..d1a57de45480 100644 --- a/sys/dev/hwpmc/hwpmc_core.c +++ b/sys/dev/hwpmc/hwpmc_core.c @@ -1,3058 +1,1334 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Intel Core PMCs. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #if (__FreeBSD_version >= 1100000) #include #else #include #endif #include #include #include #include #define CORE_CPUID_REQUEST 0xA #define CORE_CPUID_REQUEST_SIZE 0x4 #define CORE_CPUID_EAX 0x0 #define CORE_CPUID_EBX 0x1 #define CORE_CPUID_ECX 0x2 #define CORE_CPUID_EDX 0x3 #define IAF_PMC_CAPS \ (PMC_CAP_READ | PMC_CAP_WRITE | PMC_CAP_INTERRUPT | \ PMC_CAP_USER | PMC_CAP_SYSTEM) #define IAF_RI_TO_MSR(RI) ((RI) + (1 << 30)) #define IAP_PMC_CAPS (PMC_CAP_INTERRUPT | PMC_CAP_USER | PMC_CAP_SYSTEM | \ PMC_CAP_EDGE | PMC_CAP_THRESHOLD | PMC_CAP_READ | PMC_CAP_WRITE | \ PMC_CAP_INVERT | PMC_CAP_QUALIFIER | PMC_CAP_PRECISE) #define EV_IS_NOTARCH 0 #define EV_IS_ARCH_SUPP 1 #define EV_IS_ARCH_NOTSUPP -1 /* * "Architectural" events defined by Intel. The values of these * symbols correspond to positions in the bitmask returned by * the CPUID.0AH instruction. */ enum core_arch_events { CORE_AE_BRANCH_INSTRUCTION_RETIRED = 5, CORE_AE_BRANCH_MISSES_RETIRED = 6, CORE_AE_INSTRUCTION_RETIRED = 1, CORE_AE_LLC_MISSES = 4, CORE_AE_LLC_REFERENCE = 3, CORE_AE_UNHALTED_REFERENCE_CYCLES = 2, CORE_AE_UNHALTED_CORE_CYCLES = 0 }; static enum pmc_cputype core_cputype; struct core_cpu { volatile uint32_t pc_resync; volatile uint32_t pc_iafctrl; /* Fixed function control. */ volatile uint64_t pc_globalctrl; /* Global control register. */ struct pmc_hw pc_corepmcs[]; }; static struct core_cpu **core_pcpu; static uint32_t core_architectural_events; static uint64_t core_pmcmask; static int core_iaf_ri; /* relative index of fixed counters */ static int core_iaf_width; static int core_iaf_npmc; static int core_iap_width; static int core_iap_npmc; static int core_iap_wroffset; static int core_pcpu_noop(struct pmc_mdep *md, int cpu) { (void) md; (void) cpu; return (0); } static int core_pcpu_init(struct pmc_mdep *md, int cpu) { struct pmc_cpu *pc; struct core_cpu *cc; struct pmc_hw *phw; int core_ri, n, npmc; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[iaf,%d] insane cpu number %d", __LINE__, cpu)); PMCDBG1(MDP,INI,1,"core-init cpu=%d", cpu); core_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP].pcd_ri; npmc = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP].pcd_num; if (core_cputype != PMC_CPU_INTEL_CORE) npmc += md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAF].pcd_num; cc = malloc(sizeof(struct core_cpu) + npmc * sizeof(struct pmc_hw), M_PMC, M_WAITOK | M_ZERO); core_pcpu[cpu] = cc; pc = pmc_pcpu[cpu]; KASSERT(pc != NULL && cc != NULL, ("[core,%d] NULL per-cpu structures cpu=%d", __LINE__, cpu)); for (n = 0, phw = cc->pc_corepmcs; n < npmc; n++, phw++) { phw->phw_state = PMC_PHW_FLAG_IS_ENABLED | PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(n + core_ri); phw->phw_pmc = NULL; pc->pc_hwpmcs[n + core_ri] = phw; } return (0); } static int core_pcpu_fini(struct pmc_mdep *md, int cpu) { int core_ri, n, npmc; struct pmc_cpu *pc; struct core_cpu *cc; uint64_t msr = 0; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] insane cpu number (%d)", __LINE__, cpu)); PMCDBG1(MDP,INI,1,"core-pcpu-fini cpu=%d", cpu); if ((cc = core_pcpu[cpu]) == NULL) return (0); core_pcpu[cpu] = NULL; pc = pmc_pcpu[cpu]; KASSERT(pc != NULL, ("[core,%d] NULL per-cpu %d state", __LINE__, cpu)); npmc = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP].pcd_num; core_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP].pcd_ri; for (n = 0; n < npmc; n++) { msr = rdmsr(IAP_EVSEL0 + n) & ~IAP_EVSEL_MASK; wrmsr(IAP_EVSEL0 + n, msr); } if (core_cputype != PMC_CPU_INTEL_CORE) { msr = rdmsr(IAF_CTRL) & ~IAF_CTRL_MASK; wrmsr(IAF_CTRL, msr); npmc += md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAF].pcd_num; } for (n = 0; n < npmc; n++) pc->pc_hwpmcs[n + core_ri] = NULL; free(cc, M_PMC); return (0); } /* * Fixed function counters. */ static pmc_value_t iaf_perfctr_value_to_reload_count(pmc_value_t v) { /* If the PMC has overflowed, return a reload count of zero. */ if ((v & (1ULL << (core_iaf_width - 1))) == 0) return (0); v &= (1ULL << core_iaf_width) - 1; return (1ULL << core_iaf_width) - v; } static pmc_value_t iaf_reload_count_to_perfctr_value(pmc_value_t rlc) { return (1ULL << core_iaf_width) - rlc; } static int iaf_allocate_pmc(int cpu, int ri, struct pmc *pm, const struct pmc_op_pmcallocate *a) { enum pmc_event ev; uint32_t caps, flags, validflags; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal CPU %d", __LINE__, cpu)); PMCDBG2(MDP,ALL,1, "iaf-allocate ri=%d reqcaps=0x%x", ri, pm->pm_caps); if (ri < 0 || ri > core_iaf_npmc) return (EINVAL); caps = a->pm_caps; if (a->pm_class != PMC_CLASS_IAF || (caps & IAF_PMC_CAPS) != caps) return (EINVAL); ev = pm->pm_event; if (ev < PMC_EV_IAF_FIRST || ev > PMC_EV_IAF_LAST) return (EINVAL); if (ev == PMC_EV_IAF_INSTR_RETIRED_ANY && ri != 0) return (EINVAL); if (ev == PMC_EV_IAF_CPU_CLK_UNHALTED_CORE && ri != 1) return (EINVAL); if (ev == PMC_EV_IAF_CPU_CLK_UNHALTED_REF && ri != 2) return (EINVAL); flags = a->pm_md.pm_iaf.pm_iaf_flags; validflags = IAF_MASK; if (core_cputype != PMC_CPU_INTEL_ATOM && core_cputype != PMC_CPU_INTEL_ATOM_SILVERMONT) validflags &= ~IAF_ANY; if ((flags & ~validflags) != 0) return (EINVAL); if (caps & PMC_CAP_INTERRUPT) flags |= IAF_PMI; if (caps & PMC_CAP_SYSTEM) flags |= IAF_OS; if (caps & PMC_CAP_USER) flags |= IAF_USR; if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0) flags |= (IAF_OS | IAF_USR); pm->pm_md.pm_iaf.pm_iaf_ctrl = (flags << (ri * 4)); PMCDBG1(MDP,ALL,2, "iaf-allocate config=0x%jx", (uintmax_t) pm->pm_md.pm_iaf.pm_iaf_ctrl); return (0); } static int iaf_config_pmc(int cpu, int ri, struct pmc *pm) { KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal CPU %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iaf_npmc, ("[core,%d] illegal row-index %d", __LINE__, ri)); PMCDBG3(MDP,CFG,1, "iaf-config cpu=%d ri=%d pm=%p", cpu, ri, pm); KASSERT(core_pcpu[cpu] != NULL, ("[core,%d] null per-cpu %d", __LINE__, cpu)); core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri].phw_pmc = pm; return (0); } static int iaf_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) { int error; struct pmc_hw *phw; char iaf_name[PMC_NAME_MAX]; phw = &core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri]; (void) snprintf(iaf_name, sizeof(iaf_name), "IAF-%d", ri); if ((error = copystr(iaf_name, pi->pm_name, PMC_NAME_MAX, NULL)) != 0) return (error); pi->pm_class = PMC_CLASS_IAF; if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { pi->pm_enabled = TRUE; *ppmc = phw->phw_pmc; } else { pi->pm_enabled = FALSE; *ppmc = NULL; } return (0); } static int iaf_get_config(int cpu, int ri, struct pmc **ppm) { *ppm = core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri].phw_pmc; return (0); } static int iaf_get_msr(int ri, uint32_t *msr) { KASSERT(ri >= 0 && ri < core_iaf_npmc, ("[iaf,%d] ri %d out of range", __LINE__, ri)); *msr = IAF_RI_TO_MSR(ri); return (0); } static int iaf_read_pmc(int cpu, int ri, pmc_value_t *v) { struct pmc *pm; pmc_value_t tmp; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal cpu value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iaf_npmc, ("[core,%d] illegal row-index %d", __LINE__, ri)); pm = core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri].phw_pmc; KASSERT(pm, ("[core,%d] cpu %d ri %d(%d) pmc not configured", __LINE__, cpu, ri, ri + core_iaf_ri)); tmp = rdpmc(IAF_RI_TO_MSR(ri)); if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) *v = iaf_perfctr_value_to_reload_count(tmp); else *v = tmp & ((1ULL << core_iaf_width) - 1); PMCDBG4(MDP,REA,1, "iaf-read cpu=%d ri=%d msr=0x%x -> v=%jx", cpu, ri, IAF_RI_TO_MSR(ri), *v); return (0); } static int iaf_release_pmc(int cpu, int ri, struct pmc *pmc) { PMCDBG3(MDP,REL,1, "iaf-release cpu=%d ri=%d pm=%p", cpu, ri, pmc); KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal CPU value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iaf_npmc, ("[core,%d] illegal row-index %d", __LINE__, ri)); KASSERT(core_pcpu[cpu]->pc_corepmcs[ri + core_iaf_ri].phw_pmc == NULL, ("[core,%d] PHW pmc non-NULL", __LINE__)); return (0); } static int iaf_start_pmc(int cpu, int ri) { struct pmc *pm; struct core_cpu *iafc; uint64_t msr = 0; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal CPU value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iaf_npmc, ("[core,%d] illegal row-index %d", __LINE__, ri)); PMCDBG2(MDP,STA,1,"iaf-start cpu=%d ri=%d", cpu, ri); iafc = core_pcpu[cpu]; pm = iafc->pc_corepmcs[ri + core_iaf_ri].phw_pmc; iafc->pc_iafctrl |= pm->pm_md.pm_iaf.pm_iaf_ctrl; msr = rdmsr(IAF_CTRL) & ~IAF_CTRL_MASK; wrmsr(IAF_CTRL, msr | (iafc->pc_iafctrl & IAF_CTRL_MASK)); do { iafc->pc_resync = 0; iafc->pc_globalctrl |= (1ULL << (ri + IAF_OFFSET)); msr = rdmsr(IA_GLOBAL_CTRL) & ~IAF_GLOBAL_CTRL_MASK; wrmsr(IA_GLOBAL_CTRL, msr | (iafc->pc_globalctrl & IAF_GLOBAL_CTRL_MASK)); } while (iafc->pc_resync != 0); PMCDBG4(MDP,STA,1,"iafctrl=%x(%x) globalctrl=%jx(%jx)", iafc->pc_iafctrl, (uint32_t) rdmsr(IAF_CTRL), iafc->pc_globalctrl, rdmsr(IA_GLOBAL_CTRL)); return (0); } static int iaf_stop_pmc(int cpu, int ri) { uint32_t fc; struct core_cpu *iafc; uint64_t msr = 0; PMCDBG2(MDP,STO,1,"iaf-stop cpu=%d ri=%d", cpu, ri); iafc = core_pcpu[cpu]; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal CPU value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iaf_npmc, ("[core,%d] illegal row-index %d", __LINE__, ri)); fc = (IAF_MASK << (ri * 4)); if (core_cputype != PMC_CPU_INTEL_ATOM && core_cputype != PMC_CPU_INTEL_ATOM_SILVERMONT) fc &= ~IAF_ANY; iafc->pc_iafctrl &= ~fc; PMCDBG1(MDP,STO,1,"iaf-stop iafctrl=%x", iafc->pc_iafctrl); msr = rdmsr(IAF_CTRL) & ~IAF_CTRL_MASK; wrmsr(IAF_CTRL, msr | (iafc->pc_iafctrl & IAF_CTRL_MASK)); do { iafc->pc_resync = 0; iafc->pc_globalctrl &= ~(1ULL << (ri + IAF_OFFSET)); msr = rdmsr(IA_GLOBAL_CTRL) & ~IAF_GLOBAL_CTRL_MASK; wrmsr(IA_GLOBAL_CTRL, msr | (iafc->pc_globalctrl & IAF_GLOBAL_CTRL_MASK)); } while (iafc->pc_resync != 0); PMCDBG4(MDP,STO,1,"iafctrl=%x(%x) globalctrl=%jx(%jx)", iafc->pc_iafctrl, (uint32_t) rdmsr(IAF_CTRL), iafc->pc_globalctrl, rdmsr(IA_GLOBAL_CTRL)); return (0); } static int iaf_write_pmc(int cpu, int ri, pmc_value_t v) { struct core_cpu *cc; struct pmc *pm; uint64_t msr; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal cpu value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iaf_npmc, ("[core,%d] illegal row-index %d", __LINE__, ri)); cc = core_pcpu[cpu]; pm = cc->pc_corepmcs[ri + core_iaf_ri].phw_pmc; KASSERT(pm, ("[core,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri)); if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) v = iaf_reload_count_to_perfctr_value(v); /* Turn off fixed counters */ msr = rdmsr(IAF_CTRL) & ~IAF_CTRL_MASK; wrmsr(IAF_CTRL, msr); wrmsr(IAF_CTR0 + ri, v & ((1ULL << core_iaf_width) - 1)); /* Turn on fixed counters */ msr = rdmsr(IAF_CTRL) & ~IAF_CTRL_MASK; wrmsr(IAF_CTRL, msr | (cc->pc_iafctrl & IAF_CTRL_MASK)); PMCDBG6(MDP,WRI,1, "iaf-write cpu=%d ri=%d msr=0x%x v=%jx iafctrl=%jx " "pmc=%jx", cpu, ri, IAF_RI_TO_MSR(ri), v, (uintmax_t) rdmsr(IAF_CTRL), (uintmax_t) rdpmc(IAF_RI_TO_MSR(ri))); return (0); } static void iaf_initialize(struct pmc_mdep *md, int maxcpu, int npmc, int pmcwidth) { struct pmc_classdep *pcd; KASSERT(md != NULL, ("[iaf,%d] md is NULL", __LINE__)); PMCDBG0(MDP,INI,1, "iaf-initialize"); pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAF]; pcd->pcd_caps = IAF_PMC_CAPS; pcd->pcd_class = PMC_CLASS_IAF; pcd->pcd_num = npmc; pcd->pcd_ri = md->pmd_npmc; pcd->pcd_width = pmcwidth; pcd->pcd_allocate_pmc = iaf_allocate_pmc; pcd->pcd_config_pmc = iaf_config_pmc; pcd->pcd_describe = iaf_describe; pcd->pcd_get_config = iaf_get_config; pcd->pcd_get_msr = iaf_get_msr; pcd->pcd_pcpu_fini = core_pcpu_noop; pcd->pcd_pcpu_init = core_pcpu_noop; pcd->pcd_read_pmc = iaf_read_pmc; pcd->pcd_release_pmc = iaf_release_pmc; pcd->pcd_start_pmc = iaf_start_pmc; pcd->pcd_stop_pmc = iaf_stop_pmc; pcd->pcd_write_pmc = iaf_write_pmc; md->pmd_npmc += npmc; } /* * Intel programmable PMCs. */ -/* - * Event descriptor tables. - * - * For each event id, we track: - * - * 1. The CPUs that the event is valid for. - * - * 2. If the event uses a fixed UMASK, the value of the umask field. - * If the event doesn't use a fixed UMASK, a mask of legal bits - * to check against. - */ - -struct iap_event_descr { - enum pmc_event iap_ev; - unsigned char iap_evcode; - unsigned char iap_umask; - unsigned int iap_flags; -}; - -#define IAP_F_CC (1 << 0) /* CPU: Core */ -#define IAP_F_CC2 (1 << 1) /* CPU: Core2 family */ -#define IAP_F_CC2E (1 << 2) /* CPU: Core2 Extreme only */ -#define IAP_F_CA (1 << 3) /* CPU: Atom */ -#define IAP_F_I7 (1 << 4) /* CPU: Core i7 */ -#define IAP_F_I7O (1 << 4) /* CPU: Core i7 (old) */ -#define IAP_F_WM (1 << 5) /* CPU: Westmere */ -#define IAP_F_SB (1 << 6) /* CPU: Sandy Bridge */ -#define IAP_F_IB (1 << 7) /* CPU: Ivy Bridge */ -#define IAP_F_SBX (1 << 8) /* CPU: Sandy Bridge Xeon */ -#define IAP_F_IBX (1 << 9) /* CPU: Ivy Bridge Xeon */ -#define IAP_F_HW (1 << 10) /* CPU: Haswell */ -#define IAP_F_CAS (1 << 11) /* CPU: Atom Silvermont */ -#define IAP_F_HWX (1 << 12) /* CPU: Haswell Xeon */ -#define IAP_F_BW (1 << 13) /* CPU: Broadwell */ -#define IAP_F_BWX (1 << 14) /* CPU: Broadwell Xeon */ -#define IAP_F_SL (1 << 15) /* CPU: Skylake */ -#define IAP_F_SLX (1 << 16) /* CPU: Skylake Xeon AKA scalable */ -#define IAP_F_FM (1 << 18) /* Fixed mask */ - -#define IAP_F_ALLCPUSCORE2 \ - (IAP_F_CC | IAP_F_CC2 | IAP_F_CC2E | IAP_F_CA) - /* Sub fields of UMASK that this event supports. */ #define IAP_M_CORE (1 << 0) /* Core specificity */ #define IAP_M_AGENT (1 << 1) /* Agent specificity */ #define IAP_M_PREFETCH (1 << 2) /* Prefetch */ #define IAP_M_MESI (1 << 3) /* MESI */ #define IAP_M_SNOOPRESPONSE (1 << 4) /* Snoop response */ #define IAP_M_SNOOPTYPE (1 << 5) /* Snoop type */ #define IAP_M_TRANSITION (1 << 6) /* Transition */ #define IAP_F_CORE (0x3 << 14) /* Core specificity */ #define IAP_F_AGENT (0x1 << 13) /* Agent specificity */ #define IAP_F_PREFETCH (0x3 << 12) /* Prefetch */ #define IAP_F_MESI (0xF << 8) /* MESI */ #define IAP_F_SNOOPRESPONSE (0xB << 8) /* Snoop response */ #define IAP_F_SNOOPTYPE (0x3 << 8) /* Snoop type */ #define IAP_F_TRANSITION (0x1 << 12) /* Transition */ #define IAP_PREFETCH_RESERVED (0x2 << 12) #define IAP_CORE_THIS (0x1 << 14) #define IAP_CORE_ALL (0x3 << 14) #define IAP_F_CMASK 0xFF000000 -static struct iap_event_descr iap_events[] = { -#undef IAPDESCR -#define IAPDESCR(N,EV,UM,FLAGS) { \ - .iap_ev = PMC_EV_IAP_EVENT_##N, \ - .iap_evcode = (EV), \ - .iap_umask = (UM), \ - .iap_flags = (FLAGS) \ - } - - IAPDESCR(02H_01H, 0x02, 0x01, IAP_F_FM | IAP_F_I7O), - IAPDESCR(02H_81H, 0x02, 0x81, IAP_F_FM | IAP_F_CA), - - IAPDESCR(03H_00H, 0x03, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(03H_01H, 0x03, 0x01, IAP_F_FM | IAP_F_I7O | IAP_F_SB | - IAP_F_SBX | IAP_F_CAS), - IAPDESCR(03H_02H, 0x03, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | - IAP_F_CAS | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(03H_04H, 0x03, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_I7O | - IAP_F_CAS), - IAPDESCR(03H_08H, 0x03, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_SB | - IAP_F_SBX | IAP_F_CAS | IAP_F_IB | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(03H_10H, 0x03, 0x10, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_SB | - IAP_F_SBX | IAP_F_CAS), - IAPDESCR(03H_20H, 0x03, 0x20, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_CAS), - IAPDESCR(03H_40H, 0x03, 0x40, IAP_F_FM | IAP_F_CAS), - IAPDESCR(03H_80H, 0x03, 0x80, IAP_F_FM | IAP_F_CAS), - - IAPDESCR(04H_00H, 0x04, 0x00, IAP_F_FM | IAP_F_CC | IAP_F_CAS), - IAPDESCR(04H_01H, 0x04, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_I7O | - IAP_F_CAS), - IAPDESCR(04H_02H, 0x04, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_CAS), - IAPDESCR(04H_04H, 0x04, 0x04, IAP_F_FM | IAP_F_CAS), - IAPDESCR(04H_07H, 0x04, 0x07, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(04H_08H, 0x04, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_CAS), - IAPDESCR(04H_10H, 0x04, 0x10, IAP_F_FM | IAP_F_CAS), - IAPDESCR(04H_20H, 0x04, 0x20, IAP_F_FM | IAP_F_CAS), - IAPDESCR(04H_40H, 0x04, 0x40, IAP_F_FM | IAP_F_CAS), - IAPDESCR(04H_80H, 0x04, 0x80, IAP_F_FM | IAP_F_CAS), - - IAPDESCR(05H_00H, 0x05, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(05H_01H, 0x05, 0x01, IAP_F_FM | IAP_F_I7O | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_CAS | IAP_F_HWX | IAP_F_BW | - IAP_F_BWX), - IAPDESCR(05H_02H, 0x05, 0x02, IAP_F_FM | IAP_F_I7O | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_CAS | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(05H_03H, 0x05, 0x03, IAP_F_FM | IAP_F_I7O | IAP_F_CAS), - - IAPDESCR(06H_00H, 0x06, 0x00, IAP_F_FM | IAP_F_CC | IAP_F_CC2 | - IAP_F_CC2E | IAP_F_CA), - IAPDESCR(06H_01H, 0x06, 0x01, IAP_F_FM | IAP_F_I7O), - IAPDESCR(06H_02H, 0x06, 0x02, IAP_F_FM | IAP_F_I7O), - IAPDESCR(06H_04H, 0x06, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(06H_08H, 0x06, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(06H_0FH, 0x06, 0x0F, IAP_F_FM | IAP_F_I7O), - - IAPDESCR(07H_00H, 0x07, 0x00, IAP_F_FM | IAP_F_CC | IAP_F_CC2), - IAPDESCR(07H_01H, 0x07, 0x01, IAP_F_FM | IAP_F_ALLCPUSCORE2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | - IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(07H_02H, 0x07, 0x02, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(07H_03H, 0x07, 0x03, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(07H_06H, 0x07, 0x06, IAP_F_FM | IAP_F_CA), - IAPDESCR(07H_08H, 0x07, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_SB | - IAP_F_SBX), - - IAPDESCR(08H_01H, 0x08, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_SBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(08H_02H, 0x08, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_SBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SLX), - IAPDESCR(08H_04H, 0x08, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_WM | IAP_F_SB | IAP_F_SBX | IAP_F_HW | IAP_F_HWX | IAP_F_SLX), - IAPDESCR(08H_05H, 0x08, 0x05, IAP_F_FM | IAP_F_CA), - IAPDESCR(08H_06H, 0x08, 0x06, IAP_F_FM | IAP_F_CA), - IAPDESCR(08H_07H, 0x08, 0x07, IAP_F_FM | IAP_F_CA), - IAPDESCR(08H_08H, 0x08, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_SLX), - IAPDESCR(08H_09H, 0x08, 0x09, IAP_F_FM | IAP_F_CA), - IAPDESCR(08H_0EH, 0x08, 0x0E, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(08H_10H, 0x08, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_SBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(08H_20H, 0x08, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(08H_40H, 0x08, 0x40, IAP_F_FM | IAP_F_I7O | IAP_F_HW | IAP_F_HWX), - IAPDESCR(08H_60H, 0x08, 0x60, IAP_F_FM | IAP_F_HW | IAP_F_HWX), - IAPDESCR(08H_80H, 0x08, 0x80, IAP_F_FM | IAP_F_I7 | IAP_F_HW | IAP_F_HWX), - IAPDESCR(08H_81H, 0x08, 0x81, IAP_F_FM | IAP_F_IB | IAP_F_IBX), - IAPDESCR(08H_82H, 0x08, 0x82, IAP_F_FM | IAP_F_IB | IAP_F_IBX), - IAPDESCR(08H_84H, 0x08, 0x84, IAP_F_FM | IAP_F_IB | IAP_F_IBX), - IAPDESCR(08H_88H, 0x08, 0x88, IAP_F_FM | IAP_F_IB | IAP_F_IBX), - - IAPDESCR(09H_01H, 0x09, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_I7O), - IAPDESCR(09H_02H, 0x09, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_I7O), - IAPDESCR(09H_04H, 0x09, 0x04, IAP_F_FM | IAP_F_I7O), - IAPDESCR(09H_08H, 0x09, 0x08, IAP_F_FM | IAP_F_I7O), - - IAPDESCR(0BH_01H, 0x0B, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(0BH_02H, 0x0B, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(0BH_10H, 0x0B, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(0CH_01H, 0x0C, 0x01, IAP_F_FM | IAP_F_CC2 | IAP_F_I7 | - IAP_F_WM | IAP_F_SL), - IAPDESCR(0CH_02H, 0x0C, 0x02, IAP_F_FM | IAP_F_CC2), - IAPDESCR(0CH_03H, 0x0C, 0x03, IAP_F_FM | IAP_F_CA), - - IAPDESCR(0DH_01H, 0x0D, 0x01, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(0DH_03H, 0x0D, 0x03, IAP_F_FM | IAP_F_SB | IAP_F_SBX | IAP_F_HW | - IAP_F_IB | IAP_F_IBX | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(0DH_40H, 0x0D, 0x40, IAP_F_FM | IAP_F_SB | IAP_F_SBX), - IAPDESCR(0DH_80H, 0x0D, 0x80, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - - IAPDESCR(0EH_01H, 0x0E, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(0EH_02H, 0x0E, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(0EH_10H, 0x0E, 0x10, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(0EH_20H, 0x0E, 0x20, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(0EH_40H, 0x0E, 0x40, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - - IAPDESCR(0FH_01H, 0x0F, 0x01, IAP_F_FM | IAP_F_I7), - IAPDESCR(0FH_02H, 0x0F, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(0FH_08H, 0x0F, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(0FH_10H, 0x0F, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(0FH_20H, 0x0F, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(0FH_80H, 0x0F, 0x80, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(10H_00H, 0x10, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(10H_01H, 0x10, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_I7 | - IAP_F_WM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | IAP_F_IBX ), - IAPDESCR(10H_02H, 0x10, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(10H_04H, 0x10, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(10H_08H, 0x10, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(10H_10H, 0x10, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_SBX | IAP_F_IB | IAP_F_IBX), - IAPDESCR(10H_20H, 0x10, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_SBX | IAP_F_IB | IAP_F_IBX), - IAPDESCR(10H_40H, 0x10, 0x40, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_SBX | IAP_F_IB | IAP_F_IBX), - IAPDESCR(10H_80H, 0x10, 0x80, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_SBX | IAP_F_IB | IAP_F_IBX), - IAPDESCR(10H_81H, 0x10, 0x81, IAP_F_FM | IAP_F_CA), - - IAPDESCR(11H_00H, 0x11, 0x00, IAP_F_FM | IAP_F_CC | IAP_F_CC2), - IAPDESCR(11H_01H, 0x11, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_SB | - IAP_F_SBX | IAP_F_IB | IAP_F_IBX), - IAPDESCR(11H_02H, 0x11, 0x02, IAP_F_FM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | IAP_F_IBX), - IAPDESCR(11H_81H, 0x11, 0x81, IAP_F_FM | IAP_F_CA), - - IAPDESCR(12H_00H, 0x12, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(12H_01H, 0x12, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_I7 | IAP_F_WM), - IAPDESCR(12H_02H, 0x12, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(12H_04H, 0x12, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(12H_08H, 0x12, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(12H_10H, 0x12, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(12H_20H, 0x12, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(12H_40H, 0x12, 0x40, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(12H_81H, 0x12, 0x81, IAP_F_FM | IAP_F_CA), - - IAPDESCR(13H_00H, 0x13, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(13H_01H, 0x13, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_I7 | IAP_F_WM), - IAPDESCR(13H_02H, 0x13, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(13H_04H, 0x13, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(13H_07H, 0x13, 0x07, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(13H_81H, 0x13, 0x81, IAP_F_FM | IAP_F_CA), - - IAPDESCR(14H_00H, 0x14, 0x00, IAP_F_FM | IAP_F_CC | IAP_F_CC2), - IAPDESCR(14H_01H, 0x14, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_I7 | - IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(14H_02H, 0x14, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(17H_01H, 0x17, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_SBX), - - IAPDESCR(18H_00H, 0x18, 0x00, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(18H_01H, 0x18, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(19H_00H, 0x19, 0x00, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(19H_01H, 0x19, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM), - IAPDESCR(19H_02H, 0x19, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - - IAPDESCR(1DH_01H, 0x1D, 0x01, IAP_F_FM | IAP_F_I7O), - IAPDESCR(1DH_02H, 0x1D, 0x02, IAP_F_FM | IAP_F_I7O), - IAPDESCR(1DH_04H, 0x1D, 0x04, IAP_F_FM | IAP_F_I7O), - - IAPDESCR(1EH_01H, 0x1E, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(20H_01H, 0x20, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(21H, 0x21, IAP_M_CORE, IAP_F_ALLCPUSCORE2), - IAPDESCR(22H, 0x22, IAP_M_CORE, IAP_F_CC2), - IAPDESCR(23H, 0x23, IAP_M_CORE, IAP_F_ALLCPUSCORE2), - - IAPDESCR(24H, 0x24, IAP_M_CORE | IAP_M_PREFETCH, IAP_F_ALLCPUSCORE2), - IAPDESCR(24H_01H, 0x24, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX ), - IAPDESCR(24H_02H, 0x24, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(24H_03H, 0x24, 0x03, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(24H_04H, 0x24, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(24H_08H, 0x24, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(24H_0CH, 0x24, 0x0C, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(24H_10H, 0x24, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(24H_20H, 0x24, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(24H_21H, 0x24, 0x21, IAP_F_FM | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(24H_22H, 0x24, 0x22, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(24H_24H, 0x24, 0x24, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(24H_27H, 0x24, 0x27, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(24H_30H, 0x24, 0x30, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(24H_38H, 0x24, 0x38, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(24H_3FH, 0x24, 0x3F, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(24H_40H, 0x24, 0x40, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(24H_41H, 0x24, 0x41, IAP_F_FM | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(24H_42H, 0x24, 0x42, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(24H_44H, 0x24, 0x44, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(24H_50H, 0x24, 0x50, IAP_F_FM | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(24H_80H, 0x24, 0x80, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(24H_AAH, 0x24, 0xAA, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(24H_C0H, 0x24, 0xC0, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(24H_D8H, 0x24, 0xD8, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(24H_E1H, 0x24, 0xE1, IAP_F_FM | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(24H_E2H, 0x24, 0xE2, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | - IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(24H_E4H, 0x24, 0xE4, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | - IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(24H_E7H, 0x24, 0xE7, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(24H_EFH, 0x24, 0xEF, IAP_F_FM | IAP_F_SL), - IAPDESCR(24H_F8H, 0x24, 0xF8, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | - IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(24H_FFH, 0x24, 0xFF, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_HW | - IAP_F_HWX | IAP_F_SLX), - - IAPDESCR(25H, 0x25, IAP_M_CORE, IAP_F_ALLCPUSCORE2), - - IAPDESCR(26H, 0x26, IAP_M_CORE | IAP_M_PREFETCH, IAP_F_ALLCPUSCORE2), - IAPDESCR(26H_01H, 0x26, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(26H_02H, 0x26, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(26H_04H, 0x26, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(26H_08H, 0x26, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(26H_0FH, 0x26, 0x0F, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(26H_10H, 0x26, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(26H_20H, 0x26, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(26H_40H, 0x26, 0x40, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(26H_80H, 0x26, 0x80, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(26H_F0H, 0x26, 0xF0, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(26H_FFH, 0x26, 0xFF, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(27H, 0x27, IAP_M_CORE | IAP_M_PREFETCH, IAP_F_ALLCPUSCORE2), - IAPDESCR(27H_01H, 0x27, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(27H_02H, 0x27, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(27H_04H, 0x27, 0x04, IAP_F_FM | IAP_F_I7O | IAP_F_SB | - IAP_F_SBX), - IAPDESCR(27H_08H, 0x27, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(27H_0EH, 0x27, 0x0E, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(27H_0FH, 0x27, 0x0F, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(27H_10H, 0x27, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(27H_20H, 0x27, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(27H_40H, 0x27, 0x40, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(27H_50H, 0x27, 0x50, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(27H_80H, 0x27, 0x80, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(27H_E0H, 0x27, 0xE0, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(27H_F0H, 0x27, 0xF0, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(28H, 0x28, IAP_M_CORE | IAP_M_MESI, IAP_F_ALLCPUSCORE2), - IAPDESCR(28H_01H, 0x28, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX), - IAPDESCR(28H_02H, 0x28, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SBX), - IAPDESCR(28H_04H, 0x28, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(28H_07H, 0x28, 0x07, IAP_F_FM | IAP_F_SLX), - IAPDESCR(28H_08H, 0x28, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(28H_0FH, 0x28, 0x0F, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX), - IAPDESCR(28H_18H, 0x28, 0x18, IAP_F_SLX), - IAPDESCR(28H_20H, 0x28, 0x20, IAP_F_SLX), - IAPDESCR(28H_40H, 0x28, 0x40, IAP_F_SLX), - - IAPDESCR(29H, 0x29, IAP_M_CORE | IAP_M_MESI, IAP_F_CC), - IAPDESCR(29H, 0x29, IAP_M_CORE | IAP_M_MESI | IAP_M_PREFETCH, - IAP_F_CA | IAP_F_CC2), - IAPDESCR(2AH, 0x2A, IAP_M_CORE | IAP_M_MESI, IAP_F_ALLCPUSCORE2), - IAPDESCR(2BH, 0x2B, IAP_M_CORE | IAP_M_MESI, IAP_F_CA | IAP_F_CC2), - - IAPDESCR(2EH, 0x2E, IAP_M_CORE | IAP_M_MESI | IAP_M_PREFETCH, - IAP_F_ALLCPUSCORE2), - IAPDESCR(2EH_01H, 0x2E, 0x01, IAP_F_FM | IAP_F_WM), - IAPDESCR(2EH_02H, 0x2E, 0x02, IAP_F_FM | IAP_F_WM), - IAPDESCR(2EH_41H, 0x2E, 0x41, IAP_F_FM | IAP_F_ALLCPUSCORE2 | IAP_F_I7 | - IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | - IAP_F_CAS | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(2EH_4FH, 0x2E, 0x4F, IAP_F_FM | IAP_F_ALLCPUSCORE2 | IAP_F_I7 | - IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | - IAP_F_CAS | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - - IAPDESCR(30H, 0x30, IAP_M_CORE | IAP_M_MESI | IAP_M_PREFETCH, - IAP_F_ALLCPUSCORE2), - IAPDESCR(30H_00H, 0x30, 0x00, IAP_F_FM | IAP_F_CAS), - IAPDESCR(31H_00H, 0x31, 0x00, IAP_F_FM | IAP_F_CAS), - IAPDESCR(32H, 0x32, IAP_M_CORE | IAP_M_MESI | IAP_M_PREFETCH, IAP_F_CC), - IAPDESCR(32H, 0x32, IAP_M_CORE, IAP_F_CA | IAP_F_CC2), - - IAPDESCR(3AH, 0x3A, IAP_M_TRANSITION, IAP_F_CC), - IAPDESCR(3AH_00H, 0x3A, 0x00, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - - IAPDESCR(3BH_C0H, 0x3B, 0xC0, IAP_F_FM | IAP_F_ALLCPUSCORE2), - - IAPDESCR(3CH_00H, 0x3C, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | - IAP_F_HW | IAP_F_CAS | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(3CH_01H, 0x3C, 0x01, IAP_F_FM | IAP_F_ALLCPUSCORE2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | - IAP_F_HW | IAP_F_CAS | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(3CH_02H, 0x3C, 0x02, IAP_F_FM | IAP_F_ALLCPUSCORE2 | IAP_F_SL | - IAP_F_SLX), - - IAPDESCR(3DH_01H, 0x3D, 0x01, IAP_F_FM | IAP_F_I7O), - - IAPDESCR(40H, 0x40, IAP_M_MESI, IAP_F_CC | IAP_F_CC2), - IAPDESCR(40H_01H, 0x40, 0x01, IAP_F_FM | IAP_F_I7), - IAPDESCR(40H_02H, 0x40, 0x02, IAP_F_FM | IAP_F_I7), - IAPDESCR(40H_04H, 0x40, 0x04, IAP_F_FM | IAP_F_I7), - IAPDESCR(40H_08H, 0x40, 0x08, IAP_F_FM | IAP_F_I7), - IAPDESCR(40H_0FH, 0x40, 0x0F, IAP_F_FM | IAP_F_I7), - IAPDESCR(40H_21H, 0x40, 0x21, IAP_F_FM | IAP_F_CA), - - IAPDESCR(41H, 0x41, IAP_M_MESI, IAP_F_CC | IAP_F_CC2), - IAPDESCR(41H_01H, 0x41, 0x01, IAP_F_FM | IAP_F_I7O), - IAPDESCR(41H_02H, 0x41, 0x02, IAP_F_FM | IAP_F_I7), - IAPDESCR(41H_04H, 0x41, 0x04, IAP_F_FM | IAP_F_I7), - IAPDESCR(41H_08H, 0x41, 0x08, IAP_F_FM | IAP_F_I7), - IAPDESCR(41H_0FH, 0x41, 0x0F, IAP_F_FM | IAP_F_I7O), - IAPDESCR(41H_22H, 0x41, 0x22, IAP_F_FM | IAP_F_CA), - - IAPDESCR(42H, 0x42, IAP_M_MESI, IAP_F_ALLCPUSCORE2), - IAPDESCR(42H_01H, 0x42, 0x01, IAP_F_FM | IAP_F_I7), - IAPDESCR(42H_02H, 0x42, 0x02, IAP_F_FM | IAP_F_I7), - IAPDESCR(42H_04H, 0x42, 0x04, IAP_F_FM | IAP_F_I7), - IAPDESCR(42H_08H, 0x42, 0x08, IAP_F_FM | IAP_F_I7), - IAPDESCR(42H_10H, 0x42, 0x10, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - - IAPDESCR(43H_01H, 0x43, 0x01, IAP_F_FM | IAP_F_ALLCPUSCORE2 | - IAP_F_I7), - IAPDESCR(43H_02H, 0x43, 0x02, IAP_F_FM | IAP_F_CA | - IAP_F_CC2 | IAP_F_I7), - - IAPDESCR(44H_02H, 0x44, 0x02, IAP_F_FM | IAP_F_CC), - - IAPDESCR(45H_0FH, 0x45, 0x0F, IAP_F_FM | IAP_F_ALLCPUSCORE2), - - IAPDESCR(46H_00H, 0x46, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(47H_00H, 0x47, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - - IAPDESCR(48H_00H, 0x48, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(48H_01H, 0x48, 0x01, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(48H_02H, 0x48, 0x02, IAP_F_FM | IAP_F_I7O | IAP_F_SL | IAP_F_SLX), - - IAPDESCR(49H_00H, 0x49, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(49H_01H, 0x49, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | - IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(49H_02H, 0x49, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | - IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SLX), - IAPDESCR(49H_04H, 0x49, 0x04, IAP_F_FM | IAP_F_WM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_SLX), - IAPDESCR(49H_08H, 0x49, 0x08, IAP_F_FM | IAP_F_SLX), - IAPDESCR(49H_0EH, 0x49, 0x0E, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(49H_10H, 0x49, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(49H_20H, 0x49, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(49H_40H, 0x49, 0x40, IAP_F_FM | IAP_F_I7O | IAP_F_HW | IAP_F_HWX), - IAPDESCR(49H_60H, 0x49, 0x60, IAP_F_FM | IAP_F_HW | IAP_F_HWX), - IAPDESCR(49H_80H, 0x49, 0x80, IAP_F_FM | IAP_F_WM | IAP_F_I7 | IAP_F_HW | - IAP_F_HWX), - - IAPDESCR(4BH_00H, 0x4B, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(4BH_01H, 0x4B, 0x01, IAP_F_FM | IAP_F_ALLCPUSCORE2 | IAP_F_I7O), - IAPDESCR(4BH_02H, 0x4B, 0x02, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(4BH_03H, 0x4B, 0x03, IAP_F_FM | IAP_F_CC), - IAPDESCR(4BH_08H, 0x4B, 0x08, IAP_F_FM | IAP_F_I7O), - - IAPDESCR(4CH_00H, 0x4C, 0x00, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(4CH_01H, 0x4C, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(4CH_02H, 0x4C, 0x02, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - - IAPDESCR(4DH_01H, 0x4D, 0x01, IAP_F_FM | IAP_F_I7O), - - IAPDESCR(4EH_01H, 0x4E, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(4EH_02H, 0x4E, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_SBX), - IAPDESCR(4EH_04H, 0x4E, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(4EH_10H, 0x4E, 0x10, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - - IAPDESCR(4FH_00H, 0x4F, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(4FH_02H, 0x4F, 0x02, IAP_F_FM | IAP_F_I7O), - IAPDESCR(4FH_04H, 0x4F, 0x04, IAP_F_FM | IAP_F_I7O), - IAPDESCR(4FH_08H, 0x4F, 0x08, IAP_F_FM | IAP_F_I7O), - IAPDESCR(4FH_10H, 0x4F, 0x10, IAP_F_FM | IAP_F_WM | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - - IAPDESCR(51H_01H, 0x51, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(51H_02H, 0x51, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_SBX), - IAPDESCR(51H_04H, 0x51, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_SBX), - IAPDESCR(51H_08H, 0x51, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_SBX), - - IAPDESCR(52H_01H, 0x52, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(53H_01H, 0x53, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(54H_01H, 0x54, 0x01, IAP_F_FM | IAP_F_SLX), - IAPDESCR(54H_02H, 0x54, 0x02, IAP_F_FM | IAP_F_SLX), - IAPDESCR(54H_04H, 0x54, 0x04, IAP_F_FM | IAP_F_SLX), - IAPDESCR(54H_08H, 0x54, 0x08, IAP_F_FM | IAP_F_SLX), - IAPDESCR(54H_10H, 0x54, 0x10, IAP_F_FM | IAP_F_SLX), - IAPDESCR(54H_20H, 0x54, 0x20, IAP_F_FM | IAP_F_SLX), - IAPDESCR(54H_40H, 0x54, 0x40, IAP_F_FM | IAP_F_SLX), - - IAPDESCR(58H_01H, 0x58, 0x01, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(58H_02H, 0x58, 0x02, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(58H_04H, 0x58, 0x04, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(58H_08H, 0x58, 0x08, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - - IAPDESCR(59H_20H, 0x59, 0x20, IAP_F_FM | IAP_F_SB | IAP_F_SBX), - IAPDESCR(59H_40H, 0x59, 0x40, IAP_F_FM | IAP_F_SB | IAP_F_SBX), - IAPDESCR(59H_80H, 0x59, 0x80, IAP_F_FM | IAP_F_SB | IAP_F_SBX), - - IAPDESCR(5BH_0CH, 0x5B, 0x0C, IAP_F_FM | IAP_F_SB | IAP_F_SBX), - IAPDESCR(5BH_0FH, 0x5B, 0x0F, IAP_F_FM | IAP_F_SB | IAP_F_SBX), - IAPDESCR(5BH_40H, 0x5B, 0x40, IAP_F_FM | IAP_F_SB | IAP_F_SBX), - IAPDESCR(5BH_4FH, 0x5B, 0x4F, IAP_F_FM | IAP_F_SB | IAP_F_SBX), - - IAPDESCR(5CH_01H, 0x5C, 0x01, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(5CH_02H, 0x5C, 0x02, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - - IAPDESCR(5DH_01H, 0x5d, 0x01, IAP_F_FM | IAP_F_SLX), - IAPDESCR(5DH_02H, 0x5d, 0x02, IAP_F_FM | IAP_F_SLX), - IAPDESCR(5DH_04H, 0x5d, 0x04, IAP_F_FM | IAP_F_SLX), - IAPDESCR(5DH_08H, 0x5d, 0x08, IAP_F_FM | IAP_F_SLX), - IAPDESCR(5DH_10H, 0x5d, 0x10, IAP_F_FM | IAP_F_SLX), - - IAPDESCR(5EH_01H, 0x5E, 0x01, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - - IAPDESCR(5FH_01H, 0x5F, 0x01, IAP_F_FM | IAP_F_IB ), /* IB not in manual */ - IAPDESCR(5FH_04H, 0x5F, 0x04, IAP_F_FM | IAP_F_IBX | IAP_F_IB), - - IAPDESCR(60H, 0x60, IAP_M_AGENT | IAP_M_CORE, IAP_F_ALLCPUSCORE2), - IAPDESCR(60H_01H, 0x60, 0x01, IAP_F_FM | IAP_F_WM | IAP_F_I7O | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(60H_02H, 0x60, 0x02, IAP_F_FM | IAP_F_WM | IAP_F_I7O | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(60H_04H, 0x60, 0x04, IAP_F_FM |IAP_F_I7O | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(60H_08H, 0x60, 0x08, IAP_F_FM |IAP_F_I7O | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(60H_10H, 0x60, 0x10, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - - IAPDESCR(61H, 0x61, IAP_M_AGENT, IAP_F_CA | IAP_F_CC2), - - IAPDESCR(61H_00H, 0x61, 0x00, IAP_F_FM | IAP_F_CC), - - IAPDESCR(62H, 0x62, IAP_M_AGENT, IAP_F_ALLCPUSCORE2), - IAPDESCR(62H_00H, 0x62, 0x00, IAP_F_FM | IAP_F_CC), - - IAPDESCR(63H, 0x63, IAP_M_AGENT | IAP_M_CORE, - IAP_F_CA | IAP_F_CC2), - IAPDESCR(63H, 0x63, IAP_M_CORE, IAP_F_CC), - IAPDESCR(63H_01H, 0x63, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX ), - IAPDESCR(63H_02H, 0x63, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL), - - IAPDESCR(64H, 0x64, IAP_M_CORE, IAP_F_CA | IAP_F_CC2), - IAPDESCR(64H_40H, 0x64, 0x40, IAP_F_FM | IAP_F_CC), - - IAPDESCR(65H, 0x65, IAP_M_AGENT | IAP_M_CORE, - IAP_F_CA | IAP_F_CC2), - IAPDESCR(65H, 0x65, IAP_M_CORE, IAP_F_CC), - - IAPDESCR(66H, 0x66, IAP_M_AGENT | IAP_M_CORE, IAP_F_ALLCPUSCORE2), - - IAPDESCR(67H, 0x67, IAP_M_AGENT | IAP_M_CORE, IAP_F_CA | IAP_F_CC2), - IAPDESCR(67H, 0x67, IAP_M_AGENT, IAP_F_CC), - IAPDESCR(68H, 0x68, IAP_M_AGENT | IAP_M_CORE, IAP_F_ALLCPUSCORE2), - IAPDESCR(69H, 0x69, IAP_M_AGENT | IAP_M_CORE, IAP_F_ALLCPUSCORE2), - IAPDESCR(6AH, 0x6A, IAP_M_AGENT | IAP_M_CORE, IAP_F_ALLCPUSCORE2), - IAPDESCR(6BH, 0x6B, IAP_M_AGENT | IAP_M_CORE, IAP_F_ALLCPUSCORE2), - - IAPDESCR(6CH, 0x6C, IAP_M_AGENT | IAP_M_CORE, IAP_F_ALLCPUSCORE2), - IAPDESCR(6CH_01H, 0x6C, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(6DH, 0x6D, IAP_M_AGENT | IAP_M_CORE, IAP_F_CA | IAP_F_CC2), - IAPDESCR(6DH, 0x6D, IAP_M_CORE, IAP_F_CC), - - IAPDESCR(6EH, 0x6E, IAP_M_AGENT | IAP_M_CORE, IAP_F_CA | IAP_F_CC2), - IAPDESCR(6EH, 0x6E, IAP_M_CORE, IAP_F_CC), - - IAPDESCR(6FH, 0x6F, IAP_M_AGENT | IAP_M_CORE, IAP_F_CA | IAP_F_CC2), - IAPDESCR(6FH, 0x6F, IAP_M_CORE, IAP_F_CC), - - IAPDESCR(70H, 0x70, IAP_M_AGENT | IAP_M_CORE, IAP_F_CA | IAP_F_CC2), - IAPDESCR(70H, 0x70, IAP_M_CORE, IAP_F_CC), - - IAPDESCR(77H, 0x77, IAP_M_AGENT | IAP_M_SNOOPRESPONSE, - IAP_F_CA | IAP_F_CC2), - IAPDESCR(77H, 0x77, IAP_M_AGENT | IAP_M_MESI, IAP_F_CC), - - IAPDESCR(78H, 0x78, IAP_M_CORE, IAP_F_CC), - IAPDESCR(78H, 0x78, IAP_M_CORE | IAP_M_SNOOPTYPE, IAP_F_CA | IAP_F_CC2), - - IAPDESCR(79H_02H, 0x79, 0x02, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(79H_04H, 0x79, 0x04, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(79H_08H, 0x79, 0x08, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_SL | IAP_F_BW | - IAP_F_BWX | IAP_F_SLX), - IAPDESCR(79H_10H, 0x79, 0x10, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(79H_18H, 0x79, 0x18, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(79H_20H, 0x79, 0x20, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(79H_24H, 0x79, 0x24, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(79H_30H, 0x79, 0x30, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(79H_3CH, 0x79, 0x3C, IAP_F_FM | IAP_F_IB | IAP_F_IBX | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - - IAPDESCR(7AH, 0x7A, IAP_M_AGENT, IAP_F_CA | IAP_F_CC2), - - IAPDESCR(7BH, 0x7B, IAP_M_AGENT, IAP_F_CA | IAP_F_CC2), - - IAPDESCR(7DH, 0x7D, IAP_M_CORE, IAP_F_ALLCPUSCORE2), - - IAPDESCR(7EH, 0x7E, IAP_M_AGENT | IAP_M_CORE, IAP_F_CA | IAP_F_CC2), - IAPDESCR(7EH_00H, 0x7E, 0x00, IAP_F_FM | IAP_F_CC), - - IAPDESCR(7FH, 0x7F, IAP_M_CORE, IAP_F_CA | IAP_F_CC2), - - IAPDESCR(80H_00H, 0x80, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(80H_01H, 0x80, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_CAS), - IAPDESCR(80H_02H, 0x80, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_I7 | - IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | - IAP_F_CAS | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(80H_03H, 0x80, 0x03, IAP_F_FM | IAP_F_CA | IAP_F_I7 | - IAP_F_WM | IAP_F_CAS), - IAPDESCR(80H_04H, 0x80, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_IB | - IAP_F_IBX | IAP_F_SL | IAP_F_SLX), /* SL may have a spec bug two with - same entry no cmask */ - - IAPDESCR(81H_00H, 0x81, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(81H_01H, 0x81, 0x01, IAP_F_FM | IAP_F_I7O), - IAPDESCR(81H_02H, 0x81, 0x02, IAP_F_FM | IAP_F_I7O), - - IAPDESCR(82H_01H, 0x82, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(82H_02H, 0x82, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(82H_04H, 0x82, 0x04, IAP_F_FM | IAP_F_CA), - IAPDESCR(82H_10H, 0x82, 0x10, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(82H_12H, 0x82, 0x12, IAP_F_FM | IAP_F_CC2), - IAPDESCR(82H_40H, 0x82, 0x40, IAP_F_FM | IAP_F_CC2), - - IAPDESCR(83H_01H, 0x83, 0x01, IAP_F_FM | IAP_F_I7O | IAP_F_SL | IAP_F_SLX), - IAPDESCR(83H_02H, 0x83, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(83H_04H, 0x83, 0x04, IAP_F_FM | IAP_F_SLX), - - IAPDESCR(85H_00H, 0x85, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(85H_01H, 0x85, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(85H_02H, 0x85, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SLX), - IAPDESCR(85H_04H, 0x85, 0x04, IAP_F_FM | IAP_F_WM | IAP_F_I7O | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_SLX), - IAPDESCR(85H_08H, 0x85, 0x08, IAP_F_FM | IAP_F_SLX), - IAPDESCR(85H_0EH, 0x85, 0x0E, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(85H_10H, 0x85, 0x10, IAP_F_FM | IAP_F_I7O | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(85H_20H, 0x85, 0x20, IAP_F_FM | IAP_F_I7O | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(85H_40H, 0x85, 0x40, IAP_F_FM | IAP_F_I7O | IAP_F_HW | IAP_F_HWX), - IAPDESCR(85H_60H, 0x85, 0x60, IAP_F_FM | IAP_F_HW | IAP_F_HWX), - IAPDESCR(85H_80H, 0x85, 0x80, IAP_F_FM | IAP_F_WM | IAP_F_I7O), - - IAPDESCR(86H_00H, 0x86, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - - IAPDESCR(87H_00H, 0x87, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(87H_01H, 0x87, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(87H_02H, 0x87, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(87H_04H, 0x87, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(87H_08H, 0x87, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(87H_0FH, 0x87, 0x0F, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(88H_00H, 0x88, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(88H_01H, 0x88, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(88H_02H, 0x88, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(88H_04H, 0x88, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(88H_07H, 0x88, 0x07, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(88H_08H, 0x88, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(88H_10H, 0x88, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(88H_20H, 0x88, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(88H_30H, 0x88, 0x30, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(88H_40H, 0x88, 0x40, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(88H_41H, 0x88, 0x41, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(88H_7FH, 0x88, 0x7F, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(88H_80H, 0x88, 0x80, IAP_F_FM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(88H_81H, 0x88, 0x81, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(88H_82H, 0x88, 0x82, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(88H_84H, 0x88, 0x84, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(88H_88H, 0x88, 0x88, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(88H_90H, 0x88, 0x90, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(88H_A0H, 0x88, 0xA0, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(88H_FFH, 0x88, 0xFF, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - - IAPDESCR(89H_00H, 0x89, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(89H_01H, 0x89, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(89H_02H, 0x89, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(89H_04H, 0x89, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(89H_07H, 0x89, 0x07, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(89H_08H, 0x89, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(89H_10H, 0x89, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(89H_20H, 0x89, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(89H_30H, 0x89, 0x30, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(89H_40H, 0x89, 0x40, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(89H_41H, 0x89, 0x41, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(89H_7FH, 0x89, 0x7F, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(89H_80H, 0x89, 0x80, IAP_F_FM | IAP_F_BW | IAP_F_BWX), - IAPDESCR(89H_81H, 0x89, 0x81, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(89H_82H, 0x89, 0x82, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(89H_84H, 0x89, 0x84, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(89H_88H, 0x89, 0x88, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(89H_90H, 0x89, 0x90, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(89H_A0H, 0x89, 0xA0, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - IAPDESCR(89H_FFH, 0x89, 0xFF, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - - IAPDESCR(8AH_00H, 0x8A, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(8BH_00H, 0x8B, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(8CH_00H, 0x8C, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(8DH_00H, 0x8D, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(8EH_00H, 0x8E, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(8FH_00H, 0x8F, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - - IAPDESCR(90H_00H, 0x90, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(91H_00H, 0x91, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(92H_00H, 0x92, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(93H_00H, 0x93, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(94H_00H, 0x94, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - - IAPDESCR(97H_00H, 0x97, 0x00, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(98H_00H, 0x98, 0x00, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - - IAPDESCR(9CH_01H, 0x9C, 0x01, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - - IAPDESCR(A0H_00H, 0xA0, 0x00, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - - IAPDESCR(A1H_01H, 0xA1, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A1H_02H, 0xA1, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A1H_04H, 0xA1, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | /* No desc in IB for this*/ - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A1H_08H, 0xA1, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | /* No desc in IB for this*/ - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A1H_0CH, 0xA1, 0x0C, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX), - IAPDESCR(A1H_10H, 0xA1, 0x10, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | /* No desc in IB for this*/ - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A1H_20H, 0xA1, 0x20, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | /* No desc in IB for this*/ - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A1H_40H, 0xA1, 0x40, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(A1H_80H, 0xA1, 0x80, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - - IAPDESCR(A2H_00H, 0xA2, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(A2H_01H, 0xA2, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A2H_02H, 0xA2, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_SBX), - IAPDESCR(A2H_04H, 0xA2, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(A2H_08H, 0xA2, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A2H_10H, 0xA2, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(A2H_20H, 0xA2, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_SBX), - IAPDESCR(A2H_40H, 0xA2, 0x40, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_SBX), - IAPDESCR(A2H_80H, 0xA2, 0x80, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_SBX), - - IAPDESCR(A3H_01H, 0xA3, 0x01, IAP_F_FM | IAP_F_SBX | IAP_F_IBX | IAP_F_IB | - IAP_F_HW | IAP_F_HWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A3H_02H, 0xA3, 0x02, IAP_F_FM | IAP_F_SBX | IAP_F_IBX | IAP_F_IB | - IAP_F_HW | IAP_F_HWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A3H_04H, 0xA3, 0x04, IAP_F_FM | IAP_F_SBX | IAP_F_IBX | IAP_F_IB | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(A3H_05H, 0xA3, 0x05, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(A3H_06H, 0xA3, 0x06, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A3H_08H, 0xA3, 0x08, IAP_F_FM | IAP_F_IBX | IAP_F_HW | IAP_F_IB | - IAP_F_HWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A3H_0CH, 0xA3, 0x0C, IAP_F_FM | IAP_F_HW | IAP_F_HW | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(A3H_10H, 0xA3, 0x10, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A3H_14H, 0xA3, 0x14, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - - IAPDESCR(A6H_01H, 0xA6, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(A6H_02H, 0xA6, 0x02, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A6H_04H, 0xA6, 0x04, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A6H_08H, 0xA6, 0x08, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A6H_10H, 0xA6, 0x10, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(A6H_40H, 0xA6, 0x40, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - - IAPDESCR(A7H_01H, 0xA7, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM ), - - IAPDESCR(A8H_01H, 0xA8, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_IBX | - IAP_F_IB |IAP_F_SB | IAP_F_SBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | - IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - - IAPDESCR(AAH_01H, 0xAA, 0x01, IAP_F_FM | IAP_F_CC2), - IAPDESCR(AAH_02H, 0xAA, 0x02, IAP_F_FM | IAP_F_CA), - IAPDESCR(AAH_03H, 0xAA, 0x03, IAP_F_FM | IAP_F_CA), - IAPDESCR(AAH_08H, 0xAA, 0x08, IAP_F_FM | IAP_F_CC2), - - IAPDESCR(ABH_01H, 0xAB, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(ABH_02H, 0xAB, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - - IAPDESCR(ACH_02H, 0xAC, 0x02, IAP_F_FM | IAP_F_SB | IAP_F_SBX | IAP_F_SL), - IAPDESCR(ACH_08H, 0xAC, 0x08, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX), - IAPDESCR(ACH_0AH, 0xAC, 0x0A, IAP_F_FM | IAP_F_SB | IAP_F_SBX), - - IAPDESCR(AEH_01H, 0xAE, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - - IAPDESCR(B0H_00H, 0xB0, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(B0H_01H, 0xB0, 0x01, IAP_F_FM | IAP_F_WM | IAP_F_I7O | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(B0H_02H, 0xB0, 0x02, IAP_F_FM | IAP_F_WM | IAP_F_I7O | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(B0H_04H, 0xB0, 0x04, IAP_F_FM | IAP_F_WM | IAP_F_I7O | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(B0H_08H, 0xB0, 0x08, IAP_F_FM | IAP_F_WM | IAP_F_I7O | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(B0H_10H, 0xB0, 0x10, IAP_F_FM | IAP_F_WM | IAP_F_I7O | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(B0H_20H, 0xB0, 0x20, IAP_F_FM | IAP_F_I7O), - IAPDESCR(B0H_40H, 0xB0, 0x40, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(B0H_80H, 0xB0, 0x80, IAP_F_FM | IAP_F_CA | IAP_F_WM | IAP_F_I7O | - IAP_F_SL | IAP_F_SLX), - - IAPDESCR(B1H_00H, 0xB1, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(B1H_01H, 0xB1, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(B1H_02H, 0xB1, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(B1H_04H, 0xB1, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(B1H_08H, 0xB1, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(B1H_10H, 0xB1, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(B1H_1FH, 0xB1, 0x1F, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(B1H_20H, 0xB1, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(B1H_3FH, 0xB1, 0x3F, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(B1H_40H, 0xB1, 0x40, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(B1H_80H, 0xB1, 0x80, IAP_F_FM | IAP_F_CA | IAP_F_I7 | - IAP_F_WM), - - IAPDESCR(B2H_01H, 0xB2, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_SBX | IAP_F_SL | IAP_F_SLX), - - IAPDESCR(B3H_01H, 0xB3, 0x01, IAP_F_FM | IAP_F_ALLCPUSCORE2 | - IAP_F_WM | IAP_F_I7O), - IAPDESCR(B3H_02H, 0xB3, 0x02, IAP_F_FM | IAP_F_ALLCPUSCORE2 | - IAP_F_WM | IAP_F_I7O), - IAPDESCR(B3H_04H, 0xB3, 0x04, IAP_F_FM | IAP_F_ALLCPUSCORE2 | - IAP_F_WM | IAP_F_I7O), - IAPDESCR(B3H_08H, 0xB3, 0x08, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(B3H_10H, 0xB3, 0x10, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(B3H_20H, 0xB3, 0x20, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(B3H_81H, 0xB3, 0x81, IAP_F_FM | IAP_F_CA), - IAPDESCR(B3H_82H, 0xB3, 0x82, IAP_F_FM | IAP_F_CA), - IAPDESCR(B3H_84H, 0xB3, 0x84, IAP_F_FM | IAP_F_CA), - IAPDESCR(B3H_88H, 0xB3, 0x88, IAP_F_FM | IAP_F_CA), - IAPDESCR(B3H_90H, 0xB3, 0x90, IAP_F_FM | IAP_F_CA), - IAPDESCR(B3H_A0H, 0xB3, 0xA0, IAP_F_FM | IAP_F_CA), - - IAPDESCR(B4H_01H, 0xB4, 0x01, IAP_F_FM | IAP_F_WM), - IAPDESCR(B4H_02H, 0xB4, 0x02, IAP_F_FM | IAP_F_WM), - IAPDESCR(B4H_04H, 0xB4, 0x04, IAP_F_FM | IAP_F_WM), - - IAPDESCR(B6H_01H, 0xB6, 0x01, IAP_F_FM | IAP_F_SB | IAP_F_SBX), - IAPDESCR(B6H_04H, 0xB6, 0x04, IAP_F_FM | IAP_F_CAS), - - IAPDESCR(B7H_01H, 0xB7, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_CAS | - IAP_F_HWX |IAP_F_BW | IAP_F_BWX | IAP_F_SL), - IAPDESCR(B7H_02H, 0xB7, 0x02, IAP_F_CAS), - - IAPDESCR(B8H_01H, 0xB8, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(B8H_02H, 0xB8, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(B8H_04H, 0xB8, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(BAH_01H, 0xBA, 0x01, IAP_F_FM | IAP_F_I7O), - IAPDESCR(BAH_02H, 0xBA, 0x02, IAP_F_FM | IAP_F_I7O), - - IAPDESCR(BBH_01H, 0xBB, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL), - - IAPDESCR(BCH_11H, 0xBC, 0x11, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(BCH_12H, 0xBC, 0x12, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(BCH_14H, 0xBC, 0x14, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(BCH_18H, 0xBC, 0x18, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(BCH_21H, 0xBC, 0x21, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(BCH_22H, 0xBC, 0x22, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(BCH_24H, 0xBC, 0x24, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(BCH_28H, 0xBC, 0x28, IAP_F_FM | IAP_F_HW | IAP_F_HWX), - - IAPDESCR(BDH_01H, 0xBD, 0x01, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_SL | IAP_F_SLX), /* spec bug SL? */ - IAPDESCR(BDH_20H, 0xBD, 0x20, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_SLX), - - IAPDESCR(BFH_05H, 0xBF, 0x05, IAP_F_FM | IAP_F_SB | IAP_F_SBX), - - IAPDESCR(C0H_00H, 0xC0, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2 | - IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | - IAP_F_CAS | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C0H_01H, 0xC0, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(C0H_02H, 0xC0, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_BW | IAP_F_BWX), - IAPDESCR(C0H_04H, 0xC0, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM), - IAPDESCR(C0H_08H, 0xC0, 0x08, IAP_F_FM | IAP_F_CC2E), - - IAPDESCR(C1H_00H, 0xC1, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(C1H_01H, 0xC1, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(C1H_02H, 0xC1, 0x02, IAP_F_FM | IAP_F_SB | IAP_F_SBX), - IAPDESCR(C1H_08H, 0xC1, 0x08, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(C1H_10H, 0xC1, 0x10, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(C1H_20H, 0xC1, 0x20, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX), - IAPDESCR(C1H_3FH, 0xC1, 0x3F, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C1H_40H, 0xC1, 0x40, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(C1H_80H, 0xC1, 0x80, IAP_F_FM |IAP_F_IB | IAP_F_IBX), - IAPDESCR(C1H_FEH, 0xC1, 0xFE, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - - IAPDESCR(C2H_00H, 0xC2, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(C2H_01H, 0xC2, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | - IAP_F_IBX | IAP_F_HW | IAP_F_CAS | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(C2H_02H, 0xC2, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(C2H_04H, 0xC2, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM), - IAPDESCR(C2H_07H, 0xC2, 0x07, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(C2H_08H, 0xC2, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(C2H_0FH, 0xC2, 0x0F, IAP_F_FM | IAP_F_CC2), - IAPDESCR(C2H_10H, 0xC2, 0x10, IAP_F_FM | IAP_F_CA | IAP_F_CAS), - - IAPDESCR(C3H_00H, 0xC3, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(C3H_01H, 0xC3, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_CAS | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(C3H_02H, 0xC3, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | - IAP_F_CAS | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C3H_04H, 0xC3, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | - IAP_F_IBX | IAP_F_HW | IAP_F_CAS | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(C3H_08H, 0xC3, 0x08, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C3H_10H, 0xC3, 0x10, IAP_F_FM | IAP_F_I7O), - IAPDESCR(C3H_20H, 0xC3, 0x20, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - - IAPDESCR(C4H_00H, 0xC4, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | - IAP_F_IBX | IAP_F_HW | IAP_F_CAS | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(C4H_01H, 0xC4, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(C4H_02H, 0xC4, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(C4H_04H, 0xC4, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(C4H_08H, 0xC4, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | - IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C4H_0CH, 0xC4, 0x0C, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(C4H_0FH, 0xC4, 0x0F, IAP_F_FM | IAP_F_CA), - IAPDESCR(C4H_10H, 0xC4, 0x10, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(C4H_20H, 0xC4, 0x20, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(C4H_40H, 0xC4, 0x40, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(C4H_7EH, 0xC4, 0x7E, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C4H_BFH, 0xC4, 0xBF, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C4H_EBH, 0xC4, 0xEB, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C4H_F7H, 0xC4, 0xF7, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C4H_F9H, 0xC4, 0xF9, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C4H_FBH, 0xC4, 0xFB, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C4H_FDH, 0xC4, 0xFD, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C4H_FEH, 0xC4, 0xFE, IAP_F_FM | IAP_F_CAS), - - IAPDESCR(C5H_00H, 0xC5, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_IB | IAP_F_SBX | - IAP_F_IBX | IAP_F_HW | IAP_F_CAS | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(C5H_01H, 0xC5, 0x01, IAP_F_FM | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | - IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C5H_02H, 0xC5, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C5H_04H, 0xC5, 0x04, IAP_F_FM | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | - IAP_F_BWX | IAP_F_SL), - IAPDESCR(C5H_10H, 0xC5, 0x10, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX), - IAPDESCR(C5H_20H, 0xC5, 0x20, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C5H_7EH, 0xC5, 0x7E, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C5H_BFH, 0xC5, 0xBF, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C5H_EBH, 0xC5, 0xEB, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C5H_F7H, 0xC5, 0xF7, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C5H_F9H, 0xC5, 0xF9, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C5H_FBH, 0xC5, 0xFB, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C5H_FDH, 0xC5, 0xFD, IAP_F_FM | IAP_F_CAS), - IAPDESCR(C5H_FEH, 0xC5, 0xFE, IAP_F_FM | IAP_F_CAS), - - IAPDESCR(C6H_00H, 0xC6, 0x00, IAP_F_FM | IAP_F_CC), - /* For SL C6_01 needs EV_SEL? 0x11, 0x12, 0x13, 0x14, 0x15? */ - IAPDESCR(C6H_01H, 0xC6, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(C6H_02H, 0xC6, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - - IAPDESCR(C7H_00H, 0xC7, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(C7H_01H, 0xC7, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C7H_02H, 0xC7, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C7H_04H, 0xC7, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C7H_08H, 0xC7, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C7H_10H, 0xC7, 0x10, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C7H_1FH, 0xC7, 0x1F, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(C7H_20H, 0xC7, 0x20, IAP_F_FM | IAP_F_SL | IAP_F_SLX), - IAPDESCR(C7H_40H, 0xc7, 0x40, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C7H_80H, 0xc7, 0x80, IAP_F_FM | IAP_F_SLX), - - IAPDESCR(C8H_00H, 0xC8, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(C8H_01H, 0xC8, 0x01, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C8H_02H, 0xC8, 0x02, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C8H_04H, 0xC8, 0x04, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C8H_08H, 0xC8, 0x08, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C8H_10H, 0xC8, 0x10, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C8H_20H, 0xC8, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_SLX), - IAPDESCR(C8H_40H, 0xC8, 0x40, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C8H_80H, 0xC8, 0x80, IAP_F_FM | IAP_F_SLX), - - IAPDESCR(C9H_00H, 0xC9, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(C9H_01H, 0xC9, 0x01, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C9H_02H, 0xC9, 0x02, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C9H_04H, 0xC9, 0x04, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C9H_08H, 0xC9, 0x08, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C9H_10H, 0xC9, 0x10, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C9H_20H, 0xC9, 0x20, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C9H_40H, 0xC9, 0x40, IAP_F_FM | IAP_F_SLX), - IAPDESCR(C9H_80H, 0xC9, 0x80, IAP_F_FM | IAP_F_SLX), - - IAPDESCR(CAH_00H, 0xCA, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(CAH_01H, 0xCA, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_CAS), - IAPDESCR(CAH_02H, 0xCA, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(CAH_04H, 0xCA, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(CAH_08H, 0xCA, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(CAH_10H, 0xCA, 0x10, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(CAH_1EH, 0xCA, 0x1E, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - IAPDESCR(CAH_20H, 0xCA, 0x20, IAP_F_FM | IAP_F_CAS | IAP_F_BW | IAP_F_BWX), - IAPDESCR(CAH_3FH, 0xCA, 0x3F, IAP_F_FM | IAP_F_CAS), - IAPDESCR(CAH_50H, 0xCA, 0x50, IAP_F_FM | IAP_F_CAS), - - IAPDESCR(CBH_01H, 0xCB, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_CAS | IAP_F_SL | IAP_F_SLX), - IAPDESCR(CBH_02H, 0xCB, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM), - IAPDESCR(CBH_04H, 0xCB, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM), - IAPDESCR(CBH_08H, 0xCB, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM), - IAPDESCR(CBH_10H, 0xCB, 0x10, IAP_F_FM | IAP_F_CC2 | IAP_F_I7 | - IAP_F_WM), - IAPDESCR(CBH_1FH, 0xCB, 0x1F, IAP_F_FM | IAP_F_CAS), - IAPDESCR(CBH_40H, 0xCB, 0x40, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(CBH_80H, 0xCB, 0x80, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(CCH_00H, 0xCC, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(CCH_01H, 0xCC, 0x01, IAP_F_FM | IAP_F_ALLCPUSCORE2 | - IAP_F_I7 | IAP_F_WM), - IAPDESCR(CCH_02H, 0xCC, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM), - IAPDESCR(CCH_03H, 0xCC, 0x03, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(CCH_20H, 0xCC, 0x20, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SLX), - - IAPDESCR(CDH_00H, 0xCD, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(CDH_01H, 0xCD, 0x01, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_CAS | IAP_F_HWX | IAP_F_BW | - IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(CDH_02H, 0xCD, 0x02, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX), - - IAPDESCR(CEH_00H, 0xCE, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(CFH_00H, 0xCF, 0x00, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - - /* Sandy Bridge / Sandy Bridge Xeon - 11, 12, 21, 41, 42, 81, 82 */ - IAPDESCR(D0H_00H, 0xD0, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(D0H_01H, 0xD0, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(D0H_11H, 0xD0, 0x11, IAP_F_FM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(D0H_12H, 0xD0, 0x12, IAP_F_FM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(D0H_21H, 0xD0, 0x21, IAP_F_FM | IAP_F_SB | IAP_F_SBX | IAP_F_BW | - IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(D0H_41H, 0xD0, 0x41, IAP_F_FM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(D0H_42H, 0xD0, 0x42, IAP_F_FM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(D0H_81H, 0xD0, 0x81, IAP_F_FM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(D0H_82H, 0xD0, 0x82, IAP_F_FM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - - IAPDESCR(D1H_01H, 0xD1, 0x01, IAP_F_FM | IAP_F_WM | IAP_F_SB | - IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | - IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(D1H_02H, 0xD1, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(D1H_04H, 0xD1, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(D1H_08H, 0xD1, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(D1H_10H, 0xD1, 0x10, IAP_F_HW | IAP_F_IB | IAP_F_IBX | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(D1H_20H, 0xD1, 0x20, IAP_F_FM | IAP_F_SBX | IAP_F_IBX | IAP_F_IB | - IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(D1H_40H, 0xD1, 0x40, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | - IAP_F_SL | IAP_F_SLX), - - IAPDESCR(D2H_01H, 0xD2, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(D2H_02H, 0xD2, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(D2H_04H, 0xD2, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(D2H_08H, 0xD2, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SL | - IAP_F_SLX), - IAPDESCR(D2H_0FH, 0xD2, 0x0F, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM | IAP_F_SB | IAP_F_SBX | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - - IAPDESCR(D2H_10H, 0xD2, 0x10, IAP_F_FM | IAP_F_CC2E), - - IAPDESCR(D3H_01H, 0xD3, 0x01, IAP_F_FM | IAP_F_IB | IAP_F_SBX | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX | IAP_F_SLX), - IAPDESCR(D3H_02H, 0xD3, 0x02, IAP_F_FM | IAP_F_SLX), - IAPDESCR(D3H_03H, 0xD3, 0x03, IAP_F_FM | IAP_F_IBX), - IAPDESCR(D3H_04H, 0xD3, 0x04, IAP_F_FM | IAP_F_SBX | IAP_F_IBX | IAP_F_SLX), /* Not defined for IBX */ - IAPDESCR(D3H_08H, 0xD3, 0x08, IAP_F_FM | IAP_F_SLX), - IAPDESCR(D3H_0CH, 0xD3, 0x0C, IAP_F_FM | IAP_F_IBX), - IAPDESCR(D3H_10H, 0xD3, 0x10, IAP_F_FM | IAP_F_IBX ), - IAPDESCR(D3H_20H, 0xD3, 0x20, IAP_F_FM | IAP_F_IBX ), - - IAPDESCR(D4H_01H, 0xD4, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM), - IAPDESCR(D4H_02H, 0xD4, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_SB | IAP_F_SBX), - IAPDESCR(D4H_04H, 0xD4, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | IAP_F_SLX), - IAPDESCR(D4H_08H, 0xD4, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(D4H_0FH, 0xD4, 0x0F, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - - IAPDESCR(D5H_01H, 0xD5, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2 | - IAP_F_I7 | IAP_F_WM), - IAPDESCR(D5H_02H, 0xD5, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(D5H_04H, 0xD5, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(D5H_08H, 0xD5, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(D5H_0FH, 0xD5, 0x0F, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - - IAPDESCR(D7H_00H, 0xD7, 0x00, IAP_F_FM | IAP_F_CC), - - IAPDESCR(D8H_00H, 0xD8, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(D8H_01H, 0xD8, 0x01, IAP_F_FM | IAP_F_CC), - IAPDESCR(D8H_02H, 0xD8, 0x02, IAP_F_FM | IAP_F_CC), - IAPDESCR(D8H_03H, 0xD8, 0x03, IAP_F_FM | IAP_F_CC), - IAPDESCR(D8H_04H, 0xD8, 0x04, IAP_F_FM | IAP_F_CC), - - IAPDESCR(D9H_00H, 0xD9, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(D9H_01H, 0xD9, 0x01, IAP_F_FM | IAP_F_CC), - IAPDESCR(D9H_02H, 0xD9, 0x02, IAP_F_FM | IAP_F_CC), - IAPDESCR(D9H_03H, 0xD9, 0x03, IAP_F_FM | IAP_F_CC), - - IAPDESCR(DAH_00H, 0xDA, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(DAH_01H, 0xDA, 0x01, IAP_F_FM | IAP_F_CC), - IAPDESCR(DAH_02H, 0xDA, 0x02, IAP_F_FM | IAP_F_CC), - - IAPDESCR(DBH_00H, 0xDB, 0x00, IAP_F_FM | IAP_F_CC), - IAPDESCR(DBH_01H, 0xDB, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(DCH_01H, 0xDC, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(DCH_02H, 0xDC, 0x02, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(DCH_04H, 0xDC, 0x04, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(DCH_08H, 0xDC, 0x08, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(DCH_10H, 0xDC, 0x10, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - IAPDESCR(DCH_1FH, 0xDC, 0x1F, IAP_F_FM | IAP_F_CA | IAP_F_CC2), - - IAPDESCR(E0H_00H, 0xE0, 0x00, IAP_F_FM | IAP_F_CC | IAP_F_CC2), - IAPDESCR(E0H_01H, 0xE0, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_I7 | - IAP_F_WM), - - IAPDESCR(E2H_00H, 0xE2, 0x00, IAP_F_FM | IAP_F_CC), - - IAPDESCR(E4H_00H, 0xE4, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(E4H_01H, 0xE4, 0x01, IAP_F_FM | IAP_F_I7O), - - IAPDESCR(E5H_01H, 0xE5, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(E6H_00H, 0xE6, 0x00, IAP_F_FM | IAP_F_CC | IAP_F_CC2), - IAPDESCR(E6H_01H, 0xE6, 0x01, IAP_F_FM | IAP_F_CA | IAP_F_I7 | - IAP_F_WM | IAP_F_SBX | IAP_F_CAS | IAP_F_SL | IAP_F_SLX), - IAPDESCR(E6H_02H, 0xE6, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(E6H_08H, 0xE6, 0x08, IAP_F_FM | IAP_F_CAS), - IAPDESCR(E6H_10H, 0xE6, 0x10, IAP_F_FM | IAP_F_CAS), - IAPDESCR(E6H_1FH, 0xE6, 0x1F, IAP_F_FM | IAP_F_IB | - IAP_F_IBX | IAP_F_HW | IAP_F_HWX), - - IAPDESCR(E7H_01H, 0xE7, 0x01, IAP_F_FM | IAP_F_CAS), - - IAPDESCR(E8H_01H, 0xE8, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(E8H_02H, 0xE8, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - IAPDESCR(E8H_03H, 0xE8, 0x03, IAP_F_FM | IAP_F_I7O), - - IAPDESCR(ECH_01H, 0xEC, 0x01, IAP_F_FM | IAP_F_WM), - - IAPDESCR(F0H_00H, 0xF0, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(F0H_01H, 0xF0, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(F0H_02H, 0xF0, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(F0H_04H, 0xF0, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(F0H_08H, 0xF0, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(F0H_10H, 0xF0, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(F0H_20H, 0xF0, 0x20, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(F0H_40H, 0xF0, 0x40, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL | IAP_F_SLX), - IAPDESCR(F0H_80H, 0xF0, 0x80, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - - IAPDESCR(F1H_01H, 0xF1, 0x01, IAP_F_FM | IAP_F_SB | IAP_F_IB | - IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | IAP_F_BW | IAP_F_BWX), - IAPDESCR(F1H_02H, 0xF1, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX), - IAPDESCR(F1H_04H, 0xF1, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX ), - IAPDESCR(F1H_07H, 0xF1, 0x07, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_HW | IAP_F_HWX | - IAP_F_BW | IAP_F_BWX | IAP_F_SL), - IAPDESCR(F1H_1FH, 0xF1, 0x1f, IAP_F_FM | IAP_F_SLX), - - IAPDESCR(F2H_01H, 0xF2, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_SLX), - IAPDESCR(F2H_02H, 0xF2, 0x02, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_SLX), - IAPDESCR(F2H_04H, 0xF2, 0x04, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX | IAP_F_SLX), - IAPDESCR(F2H_05H, 0xF2, 0x05, IAP_F_FM | IAP_F_HW | IAP_F_HWX | IAP_F_BW | - IAP_F_BWX), - IAPDESCR(F2H_06H, 0xF2, 0x06, IAP_F_FM | IAP_F_HW | IAP_F_HWX), - IAPDESCR(F2H_08H, 0xF2, 0x08, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_IB | IAP_F_SBX | IAP_F_IBX), - IAPDESCR(F2H_0AH, 0xF2, 0x0A, IAP_F_FM | IAP_F_SB | IAP_F_SBX | - IAP_F_IBX), - IAPDESCR(F2H_0FH, 0xF2, 0x0F, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(F3H_01H, 0xF3, 0x01, IAP_F_FM | IAP_F_I7O), - IAPDESCR(F3H_02H, 0xF3, 0x02, IAP_F_FM | IAP_F_I7O), - IAPDESCR(F3H_04H, 0xF3, 0x04, IAP_F_FM | IAP_F_I7O), - IAPDESCR(F3H_08H, 0xF3, 0x08, IAP_F_FM | IAP_F_I7O), - IAPDESCR(F3H_10H, 0xF3, 0x10, IAP_F_FM | IAP_F_I7O), - IAPDESCR(F3H_20H, 0xF3, 0x20, IAP_F_FM | IAP_F_I7O), - - IAPDESCR(F4H_01H, 0xF4, 0x01, IAP_F_FM | IAP_F_I7O), - IAPDESCR(F4H_02H, 0xF4, 0x02, IAP_F_FM | IAP_F_I7O), - IAPDESCR(F4H_04H, 0xF4, 0x04, IAP_F_FM | IAP_F_WM | IAP_F_I7O), - IAPDESCR(F4H_08H, 0xF4, 0x08, IAP_F_FM | IAP_F_I7O), - IAPDESCR(F4H_10H, 0xF4, 0x10, IAP_F_FM | IAP_F_I7 | IAP_F_WM | - IAP_F_SB | IAP_F_SBX | IAP_F_SLX), - - IAPDESCR(F6H_01H, 0xF6, 0x01, IAP_F_FM | IAP_F_I7 | IAP_F_WM), - - IAPDESCR(F7H_01H, 0xF7, 0x01, IAP_F_FM | IAP_F_WM | IAP_F_I7), - IAPDESCR(F7H_02H, 0xF7, 0x02, IAP_F_FM | IAP_F_WM | IAP_F_I7), - IAPDESCR(F7H_04H, 0xF7, 0x04, IAP_F_FM | IAP_F_WM | IAP_F_I7), - - IAPDESCR(F8H_00H, 0xF8, 0x00, IAP_F_FM | IAP_F_ALLCPUSCORE2), - IAPDESCR(F8H_01H, 0xF8, 0x01, IAP_F_FM | IAP_F_I7O), - - IAPDESCR(FDH_01H, 0xFD, 0x01, IAP_F_FM | IAP_F_WM | IAP_F_I7), - IAPDESCR(FDH_02H, 0xFD, 0x02, IAP_F_FM | IAP_F_WM | IAP_F_I7), - IAPDESCR(FDH_04H, 0xFD, 0x04, IAP_F_FM | IAP_F_WM | IAP_F_I7), - IAPDESCR(FDH_08H, 0xFD, 0x08, IAP_F_FM | IAP_F_WM | IAP_F_I7), - IAPDESCR(FDH_10H, 0xFD, 0x10, IAP_F_FM | IAP_F_WM | IAP_F_I7), - IAPDESCR(FDH_20H, 0xFD, 0x20, IAP_F_FM | IAP_F_WM | IAP_F_I7), - IAPDESCR(FDH_40H, 0xFD, 0x40, IAP_F_FM | IAP_F_WM | IAP_F_I7), - - IAPDESCR(FEH_02H, 0xfe, 0x02, IAP_F_FM | IAP_F_SLX), - IAPDESCR(FEH_04H, 0xfe, 0x04, IAP_F_FM | IAP_F_SLX), -}; - static pmc_value_t iap_perfctr_value_to_reload_count(pmc_value_t v) { /* If the PMC has overflowed, return a reload count of zero. */ if ((v & (1ULL << (core_iap_width - 1))) == 0) return (0); v &= (1ULL << core_iap_width) - 1; return (1ULL << core_iap_width) - v; } static pmc_value_t iap_reload_count_to_perfctr_value(pmc_value_t rlc) { return (1ULL << core_iap_width) - rlc; } static int iap_pmc_has_overflowed(int ri) { uint64_t v; /* * We treat a Core (i.e., Intel architecture v1) PMC as has * having overflowed if its MSB is zero. */ v = rdpmc(ri); return ((v & (1ULL << (core_iap_width - 1))) == 0); } -/* - * Check an event against the set of supported architectural events. - * - * If the event is not architectural EV_IS_NOTARCH is returned. - * If the event is architectural and supported on this CPU, the correct - * event+umask mapping is returned in map, and EV_IS_ARCH_SUPP is returned. - * Otherwise, the function returns EV_IS_ARCH_NOTSUPP. - */ - static int -iap_is_event_architectural(enum pmc_event pe, enum pmc_event *map) -{ - enum core_arch_events ae; - - switch (pe) { - case PMC_EV_IAP_ARCH_UNH_COR_CYC: - ae = CORE_AE_UNHALTED_CORE_CYCLES; - *map = PMC_EV_IAP_EVENT_3CH_00H; - break; - case PMC_EV_IAP_ARCH_INS_RET: - ae = CORE_AE_INSTRUCTION_RETIRED; - *map = PMC_EV_IAP_EVENT_C0H_00H; - break; - case PMC_EV_IAP_ARCH_UNH_REF_CYC: - ae = CORE_AE_UNHALTED_REFERENCE_CYCLES; - *map = PMC_EV_IAP_EVENT_3CH_01H; - break; - case PMC_EV_IAP_ARCH_LLC_REF: - ae = CORE_AE_LLC_REFERENCE; - *map = PMC_EV_IAP_EVENT_2EH_4FH; - break; - case PMC_EV_IAP_ARCH_LLC_MIS: - ae = CORE_AE_LLC_MISSES; - *map = PMC_EV_IAP_EVENT_2EH_41H; - break; - case PMC_EV_IAP_ARCH_BR_INS_RET: - ae = CORE_AE_BRANCH_INSTRUCTION_RETIRED; - *map = PMC_EV_IAP_EVENT_C4H_00H; - break; - case PMC_EV_IAP_ARCH_BR_MIS_RET: - ae = CORE_AE_BRANCH_MISSES_RETIRED; - *map = PMC_EV_IAP_EVENT_C5H_00H; - break; - - default: /* Non architectural event. */ - return (EV_IS_NOTARCH); - } - - return (((core_architectural_events & (1 << ae)) == 0) ? - EV_IS_ARCH_NOTSUPP : EV_IS_ARCH_SUPP); -} - -static int -iap_event_corei7_ok_on_counter(enum pmc_event pe, int ri) +iap_event_corei7_ok_on_counter(uint8_t evsel, int ri) { uint32_t mask; - switch (pe) { + switch (evsel) { /* * Events valid only on counter 0, 1. */ - case PMC_EV_IAP_EVENT_40H_01H: - case PMC_EV_IAP_EVENT_40H_02H: - case PMC_EV_IAP_EVENT_40H_04H: - case PMC_EV_IAP_EVENT_40H_08H: - case PMC_EV_IAP_EVENT_40H_0FH: - case PMC_EV_IAP_EVENT_41H_02H: - case PMC_EV_IAP_EVENT_41H_04H: - case PMC_EV_IAP_EVENT_41H_08H: - case PMC_EV_IAP_EVENT_42H_01H: - case PMC_EV_IAP_EVENT_42H_02H: - case PMC_EV_IAP_EVENT_42H_04H: - case PMC_EV_IAP_EVENT_42H_08H: - case PMC_EV_IAP_EVENT_43H_01H: - case PMC_EV_IAP_EVENT_43H_02H: - case PMC_EV_IAP_EVENT_51H_01H: - case PMC_EV_IAP_EVENT_51H_02H: - case PMC_EV_IAP_EVENT_51H_04H: - case PMC_EV_IAP_EVENT_51H_08H: - case PMC_EV_IAP_EVENT_63H_01H: - case PMC_EV_IAP_EVENT_63H_02H: - mask = 0x3; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x51: + case 0x63: + mask = 0x3; break; - default: + default: mask = ~0; /* Any row index is ok. */ } return (mask & (1 << ri)); } static int -iap_event_westmere_ok_on_counter(enum pmc_event pe, int ri) +iap_event_westmere_ok_on_counter(uint8_t evsel, int ri) { uint32_t mask; - switch (pe) { + switch (evsel) { /* * Events valid only on counter 0. */ - case PMC_EV_IAP_EVENT_60H_01H: - case PMC_EV_IAP_EVENT_60H_02H: - case PMC_EV_IAP_EVENT_60H_04H: - case PMC_EV_IAP_EVENT_60H_08H: - case PMC_EV_IAP_EVENT_B3H_01H: - case PMC_EV_IAP_EVENT_B3H_02H: - case PMC_EV_IAP_EVENT_B3H_04H: + case 0x60: + case 0xB3: mask = 0x1; break; /* * Events valid only on counter 0, 1. */ - case PMC_EV_IAP_EVENT_4CH_01H: - case PMC_EV_IAP_EVENT_4EH_01H: - case PMC_EV_IAP_EVENT_4EH_02H: - case PMC_EV_IAP_EVENT_4EH_04H: - case PMC_EV_IAP_EVENT_51H_01H: - case PMC_EV_IAP_EVENT_51H_02H: - case PMC_EV_IAP_EVENT_51H_04H: - case PMC_EV_IAP_EVENT_51H_08H: - case PMC_EV_IAP_EVENT_63H_01H: - case PMC_EV_IAP_EVENT_63H_02H: + case 0x4C: + case 0x4E: + case 0x51: + case 0x63: mask = 0x3; break; default: mask = ~0; /* Any row index is ok. */ } return (mask & (1 << ri)); } static int -iap_event_sb_sbx_ib_ibx_ok_on_counter(enum pmc_event pe, int ri) +iap_event_sb_sbx_ib_ibx_ok_on_counter(uint8_t evsel, int ri) { uint32_t mask; - switch (pe) { + switch (evsel) { /* Events valid only on counter 0. */ - case PMC_EV_IAP_EVENT_B7H_01H: + case 0xB7: mask = 0x1; break; /* Events valid only on counter 1. */ - case PMC_EV_IAP_EVENT_C0H_01H: + case 0xC0: mask = 0x2; break; /* Events valid only on counter 2. */ - case PMC_EV_IAP_EVENT_48H_01H: - case PMC_EV_IAP_EVENT_A2H_02H: - case PMC_EV_IAP_EVENT_A3H_08H: + case 0x48: + case 0xA2: + case 0xA3: mask = 0x4; break; /* Events valid only on counter 3. */ - case PMC_EV_IAP_EVENT_BBH_01H: - case PMC_EV_IAP_EVENT_CDH_01H: - case PMC_EV_IAP_EVENT_CDH_02H: + case 0xBB: + case 0xCD: mask = 0x8; break; default: mask = ~0; /* Any row index is ok. */ } return (mask & (1 << ri)); } static int -iap_event_ok_on_counter(enum pmc_event pe, int ri) +iap_event_ok_on_counter(uint8_t evsel, int ri) { uint32_t mask; - switch (pe) { + switch (evsel) { /* * Events valid only on counter 0. */ - case PMC_EV_IAP_EVENT_10H_00H: - case PMC_EV_IAP_EVENT_14H_00H: - case PMC_EV_IAP_EVENT_18H_00H: - case PMC_EV_IAP_EVENT_B3H_01H: - case PMC_EV_IAP_EVENT_B3H_02H: - case PMC_EV_IAP_EVENT_B3H_04H: - case PMC_EV_IAP_EVENT_C1H_00H: - case PMC_EV_IAP_EVENT_CBH_01H: - case PMC_EV_IAP_EVENT_CBH_02H: + case 0x10: + case 0x14: + case 0x18: + case 0xB3: + case 0xC1: + case 0xCB: mask = (1 << 0); break; /* * Events valid only on counter 1. */ - case PMC_EV_IAP_EVENT_11H_00H: - case PMC_EV_IAP_EVENT_12H_00H: - case PMC_EV_IAP_EVENT_13H_00H: + case 0x11: + case 0x12: + case 0x13: mask = (1 << 1); break; default: mask = ~0; /* Any row index is ok. */ } return (mask & (1 << ri)); } static int iap_allocate_pmc(int cpu, int ri, struct pmc *pm, const struct pmc_op_pmcallocate *a) { - int arch, n, model; - enum pmc_event ev, map; - struct iap_event_descr *ie; - uint32_t c, caps, config, cpuflag, evsel, mask; + enum pmc_event map; + uint8_t ev; + uint32_t caps; + const struct pmc_md_iap_op_pmcallocate *iap; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal CPU %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iap_npmc, ("[core,%d] illegal row-index value %d", __LINE__, ri)); /* check requested capabilities */ caps = a->pm_caps; if ((IAP_PMC_CAPS & caps) != caps) return (EPERM); map = 0; /* XXX: silent GCC warning */ - arch = iap_is_event_architectural(pm->pm_event, &map); - if (arch == EV_IS_ARCH_NOTSUPP) - return (EOPNOTSUPP); - else if (arch == EV_IS_ARCH_SUPP) - ev = map; - else - ev = pm->pm_event; - - /* - * A small number of events are not supported in all the - * processors based on a given microarchitecture. - */ - if (ev == PMC_EV_IAP_EVENT_0FH_01H || ev == PMC_EV_IAP_EVENT_0FH_80H) { - model = ((cpu_id & 0xF0000) >> 12) | ((cpu_id & 0xF0) >> 4); - if (core_cputype == PMC_CPU_INTEL_COREI7 && model != 0x2E) - return (EINVAL); - } + iap = &a->pm_md.pm_iap; + ev = IAP_EVSEL_GET(iap->pm_iap_config); switch (core_cputype) { case PMC_CPU_INTEL_COREI7: case PMC_CPU_INTEL_NEHALEM_EX: if (iap_event_corei7_ok_on_counter(ev, ri) == 0) return (EINVAL); break; case PMC_CPU_INTEL_SKYLAKE: case PMC_CPU_INTEL_SKYLAKE_XEON: case PMC_CPU_INTEL_BROADWELL: case PMC_CPU_INTEL_BROADWELL_XEON: case PMC_CPU_INTEL_SANDYBRIDGE: case PMC_CPU_INTEL_SANDYBRIDGE_XEON: case PMC_CPU_INTEL_IVYBRIDGE: case PMC_CPU_INTEL_IVYBRIDGE_XEON: case PMC_CPU_INTEL_HASWELL: case PMC_CPU_INTEL_HASWELL_XEON: if (iap_event_sb_sbx_ib_ibx_ok_on_counter(ev, ri) == 0) return (EINVAL); break; case PMC_CPU_INTEL_WESTMERE: case PMC_CPU_INTEL_WESTMERE_EX: if (iap_event_westmere_ok_on_counter(ev, ri) == 0) return (EINVAL); break; default: if (iap_event_ok_on_counter(ev, ri) == 0) return (EINVAL); } - /* - * Look for an event descriptor with matching CPU and event id - * fields. - */ - - switch (core_cputype) { - default: - case PMC_CPU_INTEL_ATOM: - cpuflag = IAP_F_CA; - break; - case PMC_CPU_INTEL_ATOM_SILVERMONT: - cpuflag = IAP_F_CAS; - break; - case PMC_CPU_INTEL_SKYLAKE_XEON: - cpuflag = IAP_F_SLX; - break; - case PMC_CPU_INTEL_SKYLAKE: - cpuflag = IAP_F_SL; - break; - case PMC_CPU_INTEL_BROADWELL_XEON: - cpuflag = IAP_F_BWX; - break; - case PMC_CPU_INTEL_BROADWELL: - cpuflag = IAP_F_BW; - break; - case PMC_CPU_INTEL_CORE: - cpuflag = IAP_F_CC; - break; - case PMC_CPU_INTEL_CORE2: - cpuflag = IAP_F_CC2; - break; - case PMC_CPU_INTEL_CORE2EXTREME: - cpuflag = IAP_F_CC2 | IAP_F_CC2E; - break; - case PMC_CPU_INTEL_COREI7: - cpuflag = IAP_F_I7; - break; - case PMC_CPU_INTEL_HASWELL: - cpuflag = IAP_F_HW; - break; - case PMC_CPU_INTEL_HASWELL_XEON: - cpuflag = IAP_F_HWX; - break; - case PMC_CPU_INTEL_IVYBRIDGE: - cpuflag = IAP_F_IB; - break; - case PMC_CPU_INTEL_IVYBRIDGE_XEON: - cpuflag = IAP_F_IBX; - break; - case PMC_CPU_INTEL_SANDYBRIDGE: - cpuflag = IAP_F_SB; - break; - case PMC_CPU_INTEL_SANDYBRIDGE_XEON: - cpuflag = IAP_F_SBX; - break; - case PMC_CPU_INTEL_WESTMERE: - cpuflag = IAP_F_WM; - break; - } - - for (n = 0, ie = iap_events; n < nitems(iap_events); n++, ie++) - if (ie->iap_ev == ev && ie->iap_flags & cpuflag) - break; - - if (n == nitems(iap_events)) - return (EINVAL); - - /* - * A matching event descriptor has been found, so start - * assembling the contents of the event select register. - */ - evsel = ie->iap_evcode; - - config = a->pm_md.pm_iap.pm_iap_config & ~IAP_F_CMASK; - - /* - * If the event uses a fixed umask value, reject any umask - * bits set by the user. - */ - if (ie->iap_flags & IAP_F_FM) { - - if (IAP_UMASK(config) != 0) - return (EINVAL); - - evsel |= (ie->iap_umask << 8); - - } else { - - /* - * Otherwise, the UMASK value needs to be taken from - * the MD fields of the allocation request. Reject - * requests that specify reserved bits. - */ - - mask = 0; - - if (ie->iap_umask & IAP_M_CORE) { - if ((c = (config & IAP_F_CORE)) != IAP_CORE_ALL && - c != IAP_CORE_THIS) - return (EINVAL); - mask |= IAP_F_CORE; - } - - if (ie->iap_umask & IAP_M_AGENT) - mask |= IAP_F_AGENT; - - if (ie->iap_umask & IAP_M_PREFETCH) { - - if ((c = (config & IAP_F_PREFETCH)) == - IAP_PREFETCH_RESERVED) - return (EINVAL); - - mask |= IAP_F_PREFETCH; - } - - if (ie->iap_umask & IAP_M_MESI) - mask |= IAP_F_MESI; - - if (ie->iap_umask & IAP_M_SNOOPRESPONSE) - mask |= IAP_F_SNOOPRESPONSE; - - if (ie->iap_umask & IAP_M_SNOOPTYPE) - mask |= IAP_F_SNOOPTYPE; - - if (ie->iap_umask & IAP_M_TRANSITION) - mask |= IAP_F_TRANSITION; - - /* - * If bits outside of the allowed set of umask bits - * are set, reject the request. - */ - if (config & ~mask) - return (EINVAL); - - evsel |= (config & mask); - - } - - /* - * Only Atom and SandyBridge CPUs support the 'ANY' qualifier. - */ - if (core_cputype == PMC_CPU_INTEL_ATOM || - core_cputype == PMC_CPU_INTEL_ATOM_SILVERMONT || - core_cputype == PMC_CPU_INTEL_SANDYBRIDGE || - core_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON) - evsel |= (config & IAP_ANY); - else if (config & IAP_ANY) - return (EINVAL); - - /* - * Check offcore response configuration. - */ - if (a->pm_md.pm_iap.pm_iap_rsp != 0) { - if (ev != PMC_EV_IAP_EVENT_B7H_01H && - ev != PMC_EV_IAP_EVENT_BBH_01H) - return (EINVAL); - if (core_cputype == PMC_CPU_INTEL_COREI7 && - ev == PMC_EV_IAP_EVENT_BBH_01H) - return (EINVAL); - if ((core_cputype == PMC_CPU_INTEL_COREI7 || - core_cputype == PMC_CPU_INTEL_WESTMERE || - core_cputype == PMC_CPU_INTEL_NEHALEM_EX || - core_cputype == PMC_CPU_INTEL_WESTMERE_EX) && - a->pm_md.pm_iap.pm_iap_rsp & ~IA_OFFCORE_RSP_MASK_I7WM) - return (EINVAL); - else if ((core_cputype == PMC_CPU_INTEL_SANDYBRIDGE || - core_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON || - core_cputype == PMC_CPU_INTEL_IVYBRIDGE || - core_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON) && - a->pm_md.pm_iap.pm_iap_rsp & ~IA_OFFCORE_RSP_MASK_SBIB) - return (EINVAL); - pm->pm_md.pm_iap.pm_iap_rsp = a->pm_md.pm_iap.pm_iap_rsp; - } - - if (caps & PMC_CAP_THRESHOLD) - evsel |= (a->pm_md.pm_iap.pm_iap_config & IAP_F_CMASK); - if (caps & PMC_CAP_USER) - evsel |= IAP_USR; - if (caps & PMC_CAP_SYSTEM) - evsel |= IAP_OS; - if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0) - evsel |= (IAP_OS | IAP_USR); - if (caps & PMC_CAP_EDGE) - evsel |= IAP_EDGE; - if (caps & PMC_CAP_INVERT) - evsel |= IAP_INV; - if (caps & PMC_CAP_INTERRUPT) - evsel |= IAP_INT; - - pm->pm_md.pm_iap.pm_iap_evsel = evsel; - + pm->pm_md.pm_iap.pm_iap_evsel = iap->pm_iap_config; return (0); } static int iap_config_pmc(int cpu, int ri, struct pmc *pm) { KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal CPU %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iap_npmc, ("[core,%d] illegal row-index %d", __LINE__, ri)); PMCDBG3(MDP,CFG,1, "iap-config cpu=%d ri=%d pm=%p", cpu, ri, pm); KASSERT(core_pcpu[cpu] != NULL, ("[core,%d] null per-cpu %d", __LINE__, cpu)); core_pcpu[cpu]->pc_corepmcs[ri].phw_pmc = pm; return (0); } static int iap_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) { int error; struct pmc_hw *phw; char iap_name[PMC_NAME_MAX]; phw = &core_pcpu[cpu]->pc_corepmcs[ri]; (void) snprintf(iap_name, sizeof(iap_name), "IAP-%d", ri); if ((error = copystr(iap_name, pi->pm_name, PMC_NAME_MAX, NULL)) != 0) return (error); pi->pm_class = PMC_CLASS_IAP; if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { pi->pm_enabled = TRUE; *ppmc = phw->phw_pmc; } else { pi->pm_enabled = FALSE; *ppmc = NULL; } return (0); } static int iap_get_config(int cpu, int ri, struct pmc **ppm) { *ppm = core_pcpu[cpu]->pc_corepmcs[ri].phw_pmc; return (0); } static int iap_get_msr(int ri, uint32_t *msr) { KASSERT(ri >= 0 && ri < core_iap_npmc, ("[iap,%d] ri %d out of range", __LINE__, ri)); *msr = ri; return (0); } static int iap_read_pmc(int cpu, int ri, pmc_value_t *v) { struct pmc *pm; pmc_value_t tmp; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal cpu value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iap_npmc, ("[core,%d] illegal row-index %d", __LINE__, ri)); pm = core_pcpu[cpu]->pc_corepmcs[ri].phw_pmc; KASSERT(pm, ("[core,%d] cpu %d ri %d pmc not configured", __LINE__, cpu, ri)); tmp = rdpmc(ri); if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) *v = iap_perfctr_value_to_reload_count(tmp); else *v = tmp & ((1ULL << core_iap_width) - 1); PMCDBG4(MDP,REA,1, "iap-read cpu=%d ri=%d msr=0x%x -> v=%jx", cpu, ri, IAP_PMC0 + ri, *v); return (0); } static int iap_release_pmc(int cpu, int ri, struct pmc *pm) { (void) pm; PMCDBG3(MDP,REL,1, "iap-release cpu=%d ri=%d pm=%p", cpu, ri, pm); KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal CPU value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iap_npmc, ("[core,%d] illegal row-index %d", __LINE__, ri)); KASSERT(core_pcpu[cpu]->pc_corepmcs[ri].phw_pmc == NULL, ("[core,%d] PHW pmc non-NULL", __LINE__)); return (0); } static int iap_start_pmc(int cpu, int ri) { struct pmc *pm; uint32_t evsel; struct core_cpu *cc; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal CPU value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iap_npmc, ("[core,%d] illegal row-index %d", __LINE__, ri)); cc = core_pcpu[cpu]; pm = cc->pc_corepmcs[ri].phw_pmc; KASSERT(pm, ("[core,%d] starting cpu%d,ri%d with no pmc configured", __LINE__, cpu, ri)); PMCDBG2(MDP,STA,1, "iap-start cpu=%d ri=%d", cpu, ri); evsel = pm->pm_md.pm_iap.pm_iap_evsel; PMCDBG4(MDP,STA,2, "iap-start/2 cpu=%d ri=%d evselmsr=0x%x evsel=0x%x", cpu, ri, IAP_EVSEL0 + ri, evsel); /* Event specific configuration. */ - switch (pm->pm_event) { - case PMC_EV_IAP_EVENT_B7H_01H: + + switch (IAP_EVSEL_GET(evsel)) { + case 0xB7: wrmsr(IA_OFFCORE_RSP0, pm->pm_md.pm_iap.pm_iap_rsp); break; - case PMC_EV_IAP_EVENT_BBH_01H: + case 0xBB: wrmsr(IA_OFFCORE_RSP1, pm->pm_md.pm_iap.pm_iap_rsp); break; default: break; } wrmsr(IAP_EVSEL0 + ri, evsel | IAP_EN); if (core_cputype == PMC_CPU_INTEL_CORE) return (0); do { cc->pc_resync = 0; cc->pc_globalctrl |= (1ULL << ri); wrmsr(IA_GLOBAL_CTRL, cc->pc_globalctrl); } while (cc->pc_resync != 0); return (0); } static int iap_stop_pmc(int cpu, int ri) { struct pmc *pm; struct core_cpu *cc; uint64_t msr; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal cpu value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iap_npmc, ("[core,%d] illegal row index %d", __LINE__, ri)); cc = core_pcpu[cpu]; pm = cc->pc_corepmcs[ri].phw_pmc; KASSERT(pm, ("[core,%d] cpu%d ri%d no configured PMC to stop", __LINE__, cpu, ri)); PMCDBG2(MDP,STO,1, "iap-stop cpu=%d ri=%d", cpu, ri); msr = rdmsr(IAP_EVSEL0 + ri) & ~IAP_EVSEL_MASK; wrmsr(IAP_EVSEL0 + ri, msr); /* stop hw */ if (core_cputype == PMC_CPU_INTEL_CORE) return (0); msr = 0; do { cc->pc_resync = 0; cc->pc_globalctrl &= ~(1ULL << ri); msr = rdmsr(IA_GLOBAL_CTRL) & ~IA_GLOBAL_CTRL_MASK; wrmsr(IA_GLOBAL_CTRL, cc->pc_globalctrl); } while (cc->pc_resync != 0); return (0); } static int iap_write_pmc(int cpu, int ri, pmc_value_t v) { struct pmc *pm; struct core_cpu *cc; KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), ("[core,%d] illegal cpu value %d", __LINE__, cpu)); KASSERT(ri >= 0 && ri < core_iap_npmc, ("[core,%d] illegal row index %d", __LINE__, ri)); cc = core_pcpu[cpu]; pm = cc->pc_corepmcs[ri].phw_pmc; KASSERT(pm, ("[core,%d] cpu%d ri%d no configured PMC to stop", __LINE__, cpu, ri)); if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) v = iap_reload_count_to_perfctr_value(v); v &= (1ULL << core_iap_width) - 1; PMCDBG4(MDP,WRI,1, "iap-write cpu=%d ri=%d msr=0x%x v=%jx", cpu, ri, IAP_PMC0 + ri, v); /* * Write the new value to the counter (or it's alias). The * counter will be in a stopped state when the pcd_write() * entry point is called. */ wrmsr(core_iap_wroffset + IAP_PMC0 + ri, v); return (0); } static void iap_initialize(struct pmc_mdep *md, int maxcpu, int npmc, int pmcwidth, int flags) { struct pmc_classdep *pcd; KASSERT(md != NULL, ("[iap,%d] md is NULL", __LINE__)); PMCDBG0(MDP,INI,1, "iap-initialize"); /* Remember the set of architectural events supported. */ core_architectural_events = ~flags; pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_IAP]; pcd->pcd_caps = IAP_PMC_CAPS; pcd->pcd_class = PMC_CLASS_IAP; pcd->pcd_num = npmc; pcd->pcd_ri = md->pmd_npmc; pcd->pcd_width = pmcwidth; pcd->pcd_allocate_pmc = iap_allocate_pmc; pcd->pcd_config_pmc = iap_config_pmc; pcd->pcd_describe = iap_describe; pcd->pcd_get_config = iap_get_config; pcd->pcd_get_msr = iap_get_msr; pcd->pcd_pcpu_fini = core_pcpu_fini; pcd->pcd_pcpu_init = core_pcpu_init; pcd->pcd_read_pmc = iap_read_pmc; pcd->pcd_release_pmc = iap_release_pmc; pcd->pcd_start_pmc = iap_start_pmc; pcd->pcd_stop_pmc = iap_stop_pmc; pcd->pcd_write_pmc = iap_write_pmc; md->pmd_npmc += npmc; } static int core_intr(int cpu, struct trapframe *tf) { pmc_value_t v; struct pmc *pm; struct core_cpu *cc; int error, found_interrupt, ri; uint64_t msr; PMCDBG3(MDP,INT, 1, "cpu=%d tf=0x%p um=%d", cpu, (void *) tf, TRAPF_USERMODE(tf)); found_interrupt = 0; cc = core_pcpu[cpu]; for (ri = 0; ri < core_iap_npmc; ri++) { if ((pm = cc->pc_corepmcs[ri].phw_pmc) == NULL || !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) continue; if (!iap_pmc_has_overflowed(ri)) continue; found_interrupt = 1; if (pm->pm_state != PMC_STATE_RUNNING) continue; error = pmc_process_interrupt(cpu, PMC_HR, pm, tf, TRAPF_USERMODE(tf)); v = pm->pm_sc.pm_reloadcount; v = iap_reload_count_to_perfctr_value(v); /* * Stop the counter, reload it but only restart it if * the PMC is not stalled. */ msr = rdmsr(IAP_EVSEL0 + ri) & ~IAP_EVSEL_MASK; wrmsr(IAP_EVSEL0 + ri, msr); wrmsr(core_iap_wroffset + IAP_PMC0 + ri, v); if (error) continue; wrmsr(IAP_EVSEL0 + ri, msr | (pm->pm_md.pm_iap.pm_iap_evsel | IAP_EN)); } if (found_interrupt) lapic_reenable_pmc(); if (found_interrupt) counter_u64_add(pmc_stats.pm_intr_processed, 1); else counter_u64_add(pmc_stats.pm_intr_ignored, 1); return (found_interrupt); } static int core2_intr(int cpu, struct trapframe *tf) { int error, found_interrupt, n; uint64_t flag, intrstatus, intrenable, msr; struct pmc *pm; struct core_cpu *cc; pmc_value_t v; PMCDBG3(MDP,INT, 1, "cpu=%d tf=0x%p um=%d", cpu, (void *) tf, TRAPF_USERMODE(tf)); /* * The IA_GLOBAL_STATUS (MSR 0x38E) register indicates which * PMCs have a pending PMI interrupt. We take a 'snapshot' of * the current set of interrupting PMCs and process these * after stopping them. */ intrstatus = rdmsr(IA_GLOBAL_STATUS); intrenable = intrstatus & core_pmcmask; PMCDBG2(MDP,INT, 1, "cpu=%d intrstatus=%jx", cpu, (uintmax_t) intrstatus); found_interrupt = 0; cc = core_pcpu[cpu]; KASSERT(cc != NULL, ("[core,%d] null pcpu", __LINE__)); cc->pc_globalctrl &= ~intrenable; cc->pc_resync = 1; /* MSRs now potentially out of sync. */ /* * Stop PMCs and clear overflow status bits. */ msr = rdmsr(IA_GLOBAL_CTRL) & ~IA_GLOBAL_CTRL_MASK; wrmsr(IA_GLOBAL_CTRL, msr); wrmsr(IA_GLOBAL_OVF_CTRL, intrenable | IA_GLOBAL_STATUS_FLAG_OVFBUF | IA_GLOBAL_STATUS_FLAG_CONDCHG); /* * Look for interrupts from fixed function PMCs. */ for (n = 0, flag = (1ULL << IAF_OFFSET); n < core_iaf_npmc; n++, flag <<= 1) { if ((intrstatus & flag) == 0) continue; found_interrupt = 1; pm = cc->pc_corepmcs[n + core_iaf_ri].phw_pmc; if (pm == NULL || pm->pm_state != PMC_STATE_RUNNING || !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) continue; error = pmc_process_interrupt(cpu, PMC_HR, pm, tf, TRAPF_USERMODE(tf)); if (error) intrenable &= ~flag; v = iaf_reload_count_to_perfctr_value(pm->pm_sc.pm_reloadcount); /* Reload sampling count. */ wrmsr(IAF_CTR0 + n, v); PMCDBG4(MDP,INT, 1, "iaf-intr cpu=%d error=%d v=%jx(%jx)", cpu, error, (uintmax_t) v, (uintmax_t) rdpmc(IAF_RI_TO_MSR(n))); } /* * Process interrupts from the programmable counters. */ for (n = 0, flag = 1; n < core_iap_npmc; n++, flag <<= 1) { if ((intrstatus & flag) == 0) continue; found_interrupt = 1; pm = cc->pc_corepmcs[n].phw_pmc; if (pm == NULL || pm->pm_state != PMC_STATE_RUNNING || !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) continue; error = pmc_process_interrupt(cpu, PMC_HR, pm, tf, TRAPF_USERMODE(tf)); if (error) intrenable &= ~flag; v = iap_reload_count_to_perfctr_value(pm->pm_sc.pm_reloadcount); PMCDBG3(MDP,INT, 1, "iap-intr cpu=%d error=%d v=%jx", cpu, error, (uintmax_t) v); /* Reload sampling count. */ wrmsr(core_iap_wroffset + IAP_PMC0 + n, v); } /* * Reenable all non-stalled PMCs. */ PMCDBG2(MDP,INT, 1, "cpu=%d intrenable=%jx", cpu, (uintmax_t) intrenable); cc->pc_globalctrl |= intrenable; wrmsr(IA_GLOBAL_CTRL, cc->pc_globalctrl & IA_GLOBAL_CTRL_MASK); PMCDBG5(MDP,INT, 1, "cpu=%d fixedctrl=%jx globalctrl=%jx status=%jx " "ovf=%jx", cpu, (uintmax_t) rdmsr(IAF_CTRL), (uintmax_t) rdmsr(IA_GLOBAL_CTRL), (uintmax_t) rdmsr(IA_GLOBAL_STATUS), (uintmax_t) rdmsr(IA_GLOBAL_OVF_CTRL)); if (found_interrupt) lapic_reenable_pmc(); if (found_interrupt) counter_u64_add(pmc_stats.pm_intr_processed, 1); else counter_u64_add(pmc_stats.pm_intr_ignored, 1); return (found_interrupt); } int pmc_core_initialize(struct pmc_mdep *md, int maxcpu, int version_override) { int cpuid[CORE_CPUID_REQUEST_SIZE]; int ipa_version, flags, nflags; do_cpuid(CORE_CPUID_REQUEST, cpuid); ipa_version = (version_override > 0) ? version_override : cpuid[CORE_CPUID_EAX] & 0xFF; core_cputype = md->pmd_cputype; PMCDBG3(MDP,INI,1,"core-init cputype=%d ncpu=%d ipa-version=%d", core_cputype, maxcpu, ipa_version); if (ipa_version < 1 || ipa_version > 4 || (core_cputype != PMC_CPU_INTEL_CORE && ipa_version == 1)) { /* Unknown PMC architecture. */ printf("hwpc_core: unknown PMC architecture: %d\n", ipa_version); return (EPROGMISMATCH); } core_iap_wroffset = 0; if (cpu_feature2 & CPUID2_PDCM) { if (rdmsr(IA32_PERF_CAPABILITIES) & PERFCAP_FW_WRITE) { PMCDBG0(MDP, INI, 1, "core-init full-width write supported"); core_iap_wroffset = IAP_A_PMC0 - IAP_PMC0; } else PMCDBG0(MDP, INI, 1, "core-init full-width write NOT supported"); } else PMCDBG0(MDP, INI, 1, "core-init pdcm not supported"); core_pmcmask = 0; /* * Initialize programmable counters. */ core_iap_npmc = (cpuid[CORE_CPUID_EAX] >> 8) & 0xFF; core_iap_width = (cpuid[CORE_CPUID_EAX] >> 16) & 0xFF; core_pmcmask |= ((1ULL << core_iap_npmc) - 1); nflags = (cpuid[CORE_CPUID_EAX] >> 24) & 0xFF; flags = cpuid[CORE_CPUID_EBX] & ((1 << nflags) - 1); iap_initialize(md, maxcpu, core_iap_npmc, core_iap_width, flags); /* * Initialize fixed function counters, if present. */ if (core_cputype != PMC_CPU_INTEL_CORE) { core_iaf_ri = core_iap_npmc; core_iaf_npmc = cpuid[CORE_CPUID_EDX] & 0x1F; core_iaf_width = (cpuid[CORE_CPUID_EDX] >> 5) & 0xFF; iaf_initialize(md, maxcpu, core_iaf_npmc, core_iaf_width); core_pmcmask |= ((1ULL << core_iaf_npmc) - 1) << IAF_OFFSET; } PMCDBG2(MDP,INI,1,"core-init pmcmask=0x%jx iafri=%d", core_pmcmask, core_iaf_ri); core_pcpu = malloc(sizeof(*core_pcpu) * maxcpu, M_PMC, M_ZERO | M_WAITOK); /* * Choose the appropriate interrupt handler. */ if (ipa_version == 1) md->pmd_intr = core_intr; else md->pmd_intr = core2_intr; md->pmd_pcpu_fini = NULL; md->pmd_pcpu_init = NULL; return (0); } void pmc_core_finalize(struct pmc_mdep *md) { PMCDBG0(MDP,INI,1, "core-finalize"); free(core_pcpu, M_PMC); core_pcpu = NULL; } diff --git a/sys/dev/hwpmc/hwpmc_core.h b/sys/dev/hwpmc/hwpmc_core.h index d264318f8c25..9045318d6363 100644 --- a/sys/dev/hwpmc/hwpmc_core.h +++ b/sys/dev/hwpmc/hwpmc_core.h @@ -1,201 +1,204 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _DEV_HWPMC_CORE_H_ #define _DEV_HWPMC_CORE_H_ 1 #define IA32_PERF_CAPABILITIES 0x345 #define PERFCAP_LBR_FORMAT 0x003f #define PERFCAP_PEBS_TRAP 0x0040 #define PERFCAP_PEBS_SAVEARCH 0x0080 #define PERFCAP_PEBS_RECFORMAT 0x0f00 #define PERFCAP_SMM_FREEZE 0x1000 #define PERFCAP_FW_WRITE 0x2000 /* full width write aliases */ /* * Fixed-function PMCs. */ struct pmc_md_iaf_op_pmcallocate { uint16_t pm_iaf_flags; /* additional flags */ }; #define IAF_OS 0x1 #define IAF_USR 0x2 #define IAF_ANY 0x4 #define IAF_PMI 0x8 /* * Programmable PMCs. */ struct pmc_md_iap_op_pmcallocate { uint32_t pm_iap_config; uint64_t pm_iap_rsp; }; #define IAP_EVSEL(C) ((C) & 0xFF) -#define IAP_UMASK(C) ((C) & 0xFF00) +#define IAP_UMASK(C) (((C) & 0xFF) << 8) #define IAP_USR (1 << 16) #define IAP_OS (1 << 17) #define IAP_EDGE (1 << 18) #define IAP_INT (1 << 20) #define IAP_ANY (1 << 21) #define IAP_EN (1 << 22) #define IAP_INV (1 << 23) #define IAP_CMASK(C) (((C) & 0xFF) << 24) +#define IAP_EVSEL_GET(C) ((C) & 0xFF) +#define IAP_UMASK_GET(C) (((C) & 0xFF00) >> 8) + #define IA_OFFCORE_RSP_MASK_I7WM 0x000000F7FF #define IA_OFFCORE_RSP_MASK_SBIB 0x3F807F8FFF #ifdef _KERNEL /* * Fixed-function counters. */ #define IAF_MASK 0xF #define IAF_COUNTER_MASK 0x0000ffffffffffff #define IAF_CTR0 0x309 #define IAF_CTR1 0x30A #define IAF_CTR2 0x30B /* * The IAF_CTRL MSR is laid out in the following way. * * Bit Position Use * 63 - 12 Reserved (do not touch) * 11 Ctr 2 PMI * 10 Reserved (do not touch) * 9-8 Ctr 2 Enable * 7 Ctr 1 PMI * 6 Reserved (do not touch) * 5-4 Ctr 1 Enable * 3 Ctr 0 PMI * 2 Reserved (do not touch) * 1-0 Ctr 0 Enable (3: All Levels, 2: User, 1: OS, 0: Disable) */ #define IAF_OFFSET 32 #define IAF_CTRL 0x38D #define IAF_CTRL_MASK 0x0000000000000bbb /* * Programmable counters. */ #define IAP_PMC0 0x0C1 #define IAP_A_PMC0 0x4C1 /* * IAP_EVSEL(n) is laid out in the following way. * * Bit Position Use * 63-31 Reserved (do not touch) * 31-24 Counter Mask * 23 Invert * 22 Enable * 21 Reserved (do not touch) * 20 APIC Interrupt Enable * 19 Pin Control * 18 Edge Detect * 17 OS * 16 User * 15-8 Unit Mask * 7-0 Event Select */ #define IAP_EVSEL_MASK 0x00000000ffdfffff #define IAP_EVSEL0 0x186 /* * Simplified programming interface in Intel Performance Architecture * v2 and later. */ #define IA_GLOBAL_STATUS 0x38E #define IA_GLOBAL_CTRL 0x38F /* * IA_GLOBAL_CTRL is laid out in the following way. * * Bit Position Use * 63-35 Reserved (do not touch) * 34 IAF Counter 2 Enable * 33 IAF Counter 1 Enable * 32 IAF Counter 0 Enable * 31-0 Depends on programmable counters */ /* The mask is only for the fixed porttion of the register. */ #define IAF_GLOBAL_CTRL_MASK 0x0000000700000000 /* The mask is only for the programmable porttion of the register. */ #define IAP_GLOBAL_CTRL_MASK 0x00000000ffffffff /* The mask is for both the fixed and programmable porttions of the register. */ #define IA_GLOBAL_CTRL_MASK 0x00000007ffffffff #define IA_GLOBAL_OVF_CTRL 0x390 #define IA_GLOBAL_STATUS_FLAG_CONDCHG (1ULL << 63) #define IA_GLOBAL_STATUS_FLAG_OVFBUF (1ULL << 62) /* * Offcore response configuration. */ #define IA_OFFCORE_RSP0 0x1A6 #define IA_OFFCORE_RSP1 0x1A7 struct pmc_md_iaf_pmc { uint64_t pm_iaf_ctrl; }; struct pmc_md_iap_pmc { uint32_t pm_iap_evsel; uint64_t pm_iap_rsp; }; /* * Prototypes. */ int pmc_core_initialize(struct pmc_mdep *_md, int _maxcpu, int _version_override); void pmc_core_finalize(struct pmc_mdep *_md); int pmc_iaf_initialize(struct pmc_mdep *_md, int _maxcpu, int _npmc, int _width); void pmc_iaf_finalize(struct pmc_mdep *_md); int pmc_iap_initialize(struct pmc_mdep *_md, int _maxcpu, int _npmc, int _width, int _flags); void pmc_iap_finalize(struct pmc_mdep *_md); #endif /* _KERNEL */ #endif /* _DEV_HWPMC_CORE_H */ diff --git a/sys/dev/hwpmc/hwpmc_logging.c b/sys/dev/hwpmc/hwpmc_logging.c index 385ba8577a3a..3967e7a3e48c 100644 --- a/sys/dev/hwpmc/hwpmc_logging.c +++ b/sys/dev/hwpmc/hwpmc_logging.c @@ -1,1217 +1,1219 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2007 Joseph Koshy * Copyright (c) 2007 The FreeBSD Foundation * Copyright (c) 2018 Matthew Macy * All rights reserved. * * Portions of this software were developed by A. Joseph Koshy under * sponsorship from the FreeBSD Foundation and Google, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * Logging code for hwpmc(4) */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef NUMA #define NDOMAINS vm_ndomains #define curdomain PCPU_GET(domain) #else #define NDOMAINS 1 #define curdomain 0 #define malloc_domain(size, type, domain, flags) malloc((size), (type), (flags)) #define free_domain(addr, type) free(addr, type) #endif /* * Sysctl tunables */ SYSCTL_DECL(_kern_hwpmc); /* * kern.hwpmc.logbuffersize -- size of the per-cpu owner buffers. */ static int pmclog_buffer_size = PMC_LOG_BUFFER_SIZE; #if (__FreeBSD_version < 1100000) TUNABLE_INT(PMC_SYSCTL_NAME_PREFIX "logbuffersize", &pmclog_buffer_size); #endif SYSCTL_INT(_kern_hwpmc, OID_AUTO, logbuffersize, CTLFLAG_RDTUN, &pmclog_buffer_size, 0, "size of log buffers in kilobytes"); /* * kern.hwpmc.nbuffer -- number of global log buffers */ static int pmc_nlogbuffers_pcpu = PMC_NLOGBUFFERS_PCPU; #if (__FreeBSD_version < 1100000) TUNABLE_INT(PMC_SYSCTL_NAME_PREFIX "nbuffers", &pmc_nlogbuffers_pcpu); #endif SYSCTL_INT(_kern_hwpmc, OID_AUTO, nbuffers_pcpu, CTLFLAG_RDTUN, &pmc_nlogbuffers_pcpu, 0, "number of log buffers per cpu"); /* * Global log buffer list and associated spin lock. */ static struct mtx pmc_kthread_mtx; /* sleep lock */ #define PMCLOG_INIT_BUFFER_DESCRIPTOR(D, buf, domain) do { \ (D)->plb_fence = ((char *) (buf)) + 1024*pmclog_buffer_size; \ (D)->plb_base = (D)->plb_ptr = ((char *) (buf)); \ (D)->plb_domain = domain; \ } while (0) #define PMCLOG_RESET_BUFFER_DESCRIPTOR(D) do { \ (D)->plb_ptr = (D)->plb_base; \ } while (0) /* * Log file record constructors. */ #define _PMCLOG_TO_HEADER(T,L) \ ((PMCLOG_HEADER_MAGIC << 24) | \ (PMCLOG_TYPE_ ## T << 16) | \ ((L) & 0xFFFF)) /* reserve LEN bytes of space and initialize the entry header */ #define _PMCLOG_RESERVE_SAFE(PO,TYPE,LEN,ACTION) do { \ uint32_t *_le; \ int _len = roundup((LEN), sizeof(uint32_t)); \ if ((_le = pmclog_reserve((PO), _len)) == NULL) { \ ACTION; \ } \ *_le = _PMCLOG_TO_HEADER(TYPE,_len); \ _le += 3 /* skip over timestamp */ /* reserve LEN bytes of space and initialize the entry header */ #define _PMCLOG_RESERVE(PO,TYPE,LEN,ACTION) do { \ uint32_t *_le; \ int _len = roundup((LEN), sizeof(uint32_t)); \ spinlock_enter(); \ if ((_le = pmclog_reserve((PO), _len)) == NULL) { \ spinlock_exit(); \ ACTION; \ } \ *_le = _PMCLOG_TO_HEADER(TYPE,_len); \ _le += 3 /* skip over timestamp */ #define PMCLOG_RESERVE_SAFE(P,T,L) _PMCLOG_RESERVE_SAFE(P,T,L,return) #define PMCLOG_RESERVE(P,T,L) _PMCLOG_RESERVE(P,T,L,return) #define PMCLOG_RESERVE_WITH_ERROR(P,T,L) _PMCLOG_RESERVE(P,T,L, \ error=ENOMEM;goto error) #define PMCLOG_EMIT32(V) do { *_le++ = (V); } while (0) #define PMCLOG_EMIT64(V) do { \ *_le++ = (uint32_t) ((V) & 0xFFFFFFFF); \ *_le++ = (uint32_t) (((V) >> 32) & 0xFFFFFFFF); \ } while (0) /* Emit a string. Caution: does NOT update _le, so needs to be last */ #define PMCLOG_EMITSTRING(S,L) do { bcopy((S), _le, (L)); } while (0) #define PMCLOG_EMITNULLSTRING(L) do { bzero(_le, (L)); } while (0) #define PMCLOG_DESPATCH_SAFE(PO) \ pmclog_release((PO)); \ } while (0) #define PMCLOG_DESPATCH(PO) \ pmclog_release((PO)); \ spinlock_exit(); \ } while (0) #define PMCLOG_DESPATCH_SYNC(PO) \ pmclog_schedule_io((PO)); \ spinlock_exit(); \ } while (0) /* * Assertions about the log file format. */ CTASSERT(sizeof(struct pmclog_callchain) == 8*4 + PMC_CALLCHAIN_DEPTH_MAX*sizeof(uintfptr_t)); -CTASSERT(sizeof(struct pmclog_closelog) == 3*4); -CTASSERT(sizeof(struct pmclog_dropnotify) == 3*4); +CTASSERT(sizeof(struct pmclog_closelog) == 4*4); +CTASSERT(sizeof(struct pmclog_dropnotify) == 4*4); CTASSERT(sizeof(struct pmclog_map_in) == PATH_MAX + 4*4 + sizeof(uintfptr_t)); CTASSERT(offsetof(struct pmclog_map_in,pl_pathname) == 4*4 + sizeof(uintfptr_t)); CTASSERT(sizeof(struct pmclog_map_out) == 4*4 + 2*sizeof(uintfptr_t)); -CTASSERT(sizeof(struct pmclog_pcsample) == 8*4 + sizeof(uintfptr_t)); CTASSERT(sizeof(struct pmclog_pmcallocate) == 6*4); -CTASSERT(sizeof(struct pmclog_pmcattach) == 5*4 + PATH_MAX); -CTASSERT(offsetof(struct pmclog_pmcattach,pl_pathname) == 5*4); -CTASSERT(sizeof(struct pmclog_pmcdetach) == 5*4); +CTASSERT(sizeof(struct pmclog_pmcattach) == 6*4 + PATH_MAX); +CTASSERT(offsetof(struct pmclog_pmcattach,pl_pathname) == 6*4); +CTASSERT(sizeof(struct pmclog_pmcdetach) == 6*4); CTASSERT(sizeof(struct pmclog_proccsw) == 6*4 + 8); -CTASSERT(sizeof(struct pmclog_procexec) == 5*4 + PATH_MAX + +CTASSERT(sizeof(struct pmclog_procexec) == 6*4 + PATH_MAX + sizeof(uintfptr_t)); -CTASSERT(offsetof(struct pmclog_procexec,pl_pathname) == 5*4 + +CTASSERT(offsetof(struct pmclog_procexec,pl_pathname) == 6*4 + sizeof(uintfptr_t)); -CTASSERT(sizeof(struct pmclog_procexit) == 5*4 + 8); -CTASSERT(sizeof(struct pmclog_procfork) == 5*4); +CTASSERT(sizeof(struct pmclog_procexit) == 6*4 + 8); +CTASSERT(sizeof(struct pmclog_procfork) == 6*4); CTASSERT(sizeof(struct pmclog_sysexit) == 4*4); CTASSERT(sizeof(struct pmclog_userdata) == 4*4); /* * Log buffer structure */ struct pmclog_buffer { TAILQ_ENTRY(pmclog_buffer) plb_next; char *plb_base; char *plb_ptr; char *plb_fence; uint16_t plb_domain; } __aligned(CACHE_LINE_SIZE); /* * Prototypes */ static int pmclog_get_buffer(struct pmc_owner *po); static void pmclog_loop(void *arg); static void pmclog_release(struct pmc_owner *po); static uint32_t *pmclog_reserve(struct pmc_owner *po, int length); static void pmclog_schedule_io(struct pmc_owner *po); static void pmclog_schedule_all(struct pmc_owner *po); static void pmclog_stop_kthread(struct pmc_owner *po); /* * Helper functions */ static inline void pmc_plb_rele_unlocked(struct pmclog_buffer *plb) { TAILQ_INSERT_HEAD(&pmc_dom_hdrs[plb->plb_domain]->pdbh_head, plb, plb_next); } static inline void pmc_plb_rele(struct pmclog_buffer *plb) { mtx_lock_spin(&pmc_dom_hdrs[plb->plb_domain]->pdbh_mtx); pmc_plb_rele_unlocked(plb); mtx_unlock_spin(&pmc_dom_hdrs[plb->plb_domain]->pdbh_mtx); } /* * Get a log buffer */ static int pmclog_get_buffer(struct pmc_owner *po) { struct pmclog_buffer *plb; int domain; KASSERT(po->po_curbuf[curcpu] == NULL, ("[pmclog,%d] po=%p current buffer still valid", __LINE__, po)); domain = curdomain; MPASS(pmc_dom_hdrs[domain]); mtx_lock_spin(&pmc_dom_hdrs[domain]->pdbh_mtx); if ((plb = TAILQ_FIRST(&pmc_dom_hdrs[domain]->pdbh_head)) != NULL) TAILQ_REMOVE(&pmc_dom_hdrs[domain]->pdbh_head, plb, plb_next); mtx_unlock_spin(&pmc_dom_hdrs[domain]->pdbh_mtx); PMCDBG2(LOG,GTB,1, "po=%p plb=%p", po, plb); #ifdef HWPMC_DEBUG if (plb) KASSERT(plb->plb_ptr == plb->plb_base && plb->plb_base < plb->plb_fence, ("[pmclog,%d] po=%p buffer invariants: ptr=%p " "base=%p fence=%p", __LINE__, po, plb->plb_ptr, plb->plb_base, plb->plb_fence)); #endif po->po_curbuf[curcpu] = plb; /* update stats */ counter_u64_add(pmc_stats.pm_buffer_requests, 1); if (plb == NULL) counter_u64_add(pmc_stats.pm_buffer_requests_failed, 1); return (plb ? 0 : ENOMEM); } struct pmclog_proc_init_args { struct proc *kthr; struct pmc_owner *po; bool exit; bool acted; }; int pmclog_proc_create(struct thread *td, void **handlep) { struct pmclog_proc_init_args *ia; int error; ia = malloc(sizeof(*ia), M_TEMP, M_WAITOK | M_ZERO); error = kproc_create(pmclog_loop, ia, &ia->kthr, RFHIGHPID, 0, "hwpmc: proc(%d)", td->td_proc->p_pid); if (error == 0) *handlep = ia; return (error); } void pmclog_proc_ignite(void *handle, struct pmc_owner *po) { struct pmclog_proc_init_args *ia; ia = handle; mtx_lock(&pmc_kthread_mtx); MPASS(!ia->acted); MPASS(ia->po == NULL); MPASS(!ia->exit); MPASS(ia->kthr != NULL); if (po == NULL) { ia->exit = true; } else { ia->po = po; KASSERT(po->po_kthread == NULL, ("[pmclog,%d] po=%p kthread (%p) already present", __LINE__, po, po->po_kthread)); po->po_kthread = ia->kthr; } wakeup(ia); while (!ia->acted) msleep(ia, &pmc_kthread_mtx, PWAIT, "pmclogw", 0); mtx_unlock(&pmc_kthread_mtx); free(ia, M_TEMP); } /* * Log handler loop. * * This function is executed by each pmc owner's helper thread. */ static void pmclog_loop(void *arg) { struct pmclog_proc_init_args *ia; struct pmc_owner *po; struct pmclog_buffer *lb; struct proc *p; struct ucred *ownercred; struct ucred *mycred; struct thread *td; sigset_t unb; struct uio auio; struct iovec aiov; size_t nbytes; int error; td = curthread; SIGEMPTYSET(unb); SIGADDSET(unb, SIGHUP); (void)kern_sigprocmask(td, SIG_UNBLOCK, &unb, NULL, 0); ia = arg; MPASS(ia->kthr == curproc); MPASS(!ia->acted); mtx_lock(&pmc_kthread_mtx); while (ia->po == NULL && !ia->exit) msleep(ia, &pmc_kthread_mtx, PWAIT, "pmclogi", 0); if (ia->exit) { ia->acted = true; wakeup(ia); mtx_unlock(&pmc_kthread_mtx); kproc_exit(0); } MPASS(ia->po != NULL); po = ia->po; ia->acted = true; wakeup(ia); mtx_unlock(&pmc_kthread_mtx); ia = NULL; p = po->po_owner; mycred = td->td_ucred; PROC_LOCK(p); ownercred = crhold(p->p_ucred); PROC_UNLOCK(p); PMCDBG2(LOG,INI,1, "po=%p kt=%p", po, po->po_kthread); KASSERT(po->po_kthread == curthread->td_proc, ("[pmclog,%d] proc mismatch po=%p po/kt=%p curproc=%p", __LINE__, po, po->po_kthread, curthread->td_proc)); lb = NULL; /* * Loop waiting for I/O requests to be added to the owner * struct's queue. The loop is exited when the log file * is deconfigured. */ mtx_lock(&pmc_kthread_mtx); for (;;) { /* check if we've been asked to exit */ if ((po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) break; if (lb == NULL) { /* look for a fresh buffer to write */ mtx_lock_spin(&po->po_mtx); if ((lb = TAILQ_FIRST(&po->po_logbuffers)) == NULL) { mtx_unlock_spin(&po->po_mtx); /* No more buffers and shutdown required. */ if (po->po_flags & PMC_PO_SHUTDOWN) break; (void) msleep(po, &pmc_kthread_mtx, PWAIT, "pmcloop", 0); continue; } TAILQ_REMOVE(&po->po_logbuffers, lb, plb_next); mtx_unlock_spin(&po->po_mtx); } mtx_unlock(&pmc_kthread_mtx); /* process the request */ PMCDBG3(LOG,WRI,2, "po=%p base=%p ptr=%p", po, lb->plb_base, lb->plb_ptr); /* change our thread's credentials before issuing the I/O */ aiov.iov_base = lb->plb_base; aiov.iov_len = nbytes = lb->plb_ptr - lb->plb_base; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = -1; auio.uio_resid = nbytes; auio.uio_rw = UIO_WRITE; auio.uio_segflg = UIO_SYSSPACE; auio.uio_td = td; /* switch thread credentials -- see kern_ktrace.c */ td->td_ucred = ownercred; error = fo_write(po->po_file, &auio, ownercred, 0, td); td->td_ucred = mycred; if (error) { /* XXX some errors are recoverable */ /* send a SIGIO to the owner and exit */ PROC_LOCK(p); kern_psignal(p, SIGIO); PROC_UNLOCK(p); mtx_lock(&pmc_kthread_mtx); po->po_error = error; /* save for flush log */ PMCDBG2(LOG,WRI,2, "po=%p error=%d", po, error); break; } mtx_lock(&pmc_kthread_mtx); /* put the used buffer back into the global pool */ PMCLOG_RESET_BUFFER_DESCRIPTOR(lb); pmc_plb_rele(lb); lb = NULL; } wakeup_one(po->po_kthread); po->po_kthread = NULL; mtx_unlock(&pmc_kthread_mtx); /* return the current I/O buffer to the global pool */ if (lb) { PMCLOG_RESET_BUFFER_DESCRIPTOR(lb); pmc_plb_rele(lb); } /* * Exit this thread, signalling the waiter */ crfree(ownercred); kproc_exit(0); } /* * Release and log entry and schedule an I/O if needed. */ static void pmclog_release(struct pmc_owner *po) { struct pmclog_buffer *plb; plb = po->po_curbuf[curcpu]; KASSERT(plb->plb_ptr >= plb->plb_base, ("[pmclog,%d] buffer invariants po=%p ptr=%p base=%p", __LINE__, po, plb->plb_ptr, plb->plb_base)); KASSERT(plb->plb_ptr <= plb->plb_fence, ("[pmclog,%d] buffer invariants po=%p ptr=%p fenc=%p", __LINE__, po, plb->plb_ptr, plb->plb_fence)); /* schedule an I/O if we've filled a buffer */ if (plb->plb_ptr >= plb->plb_fence) pmclog_schedule_io(po); PMCDBG1(LOG,REL,1, "po=%p", po); } /* * Attempt to reserve 'length' bytes of space in an owner's log * buffer. The function returns a pointer to 'length' bytes of space * if there was enough space or returns NULL if no space was * available. Non-null returns do so with the po mutex locked. The * caller must invoke pmclog_release() on the pmc owner structure * when done. */ static uint32_t * pmclog_reserve(struct pmc_owner *po, int length) { uintptr_t newptr, oldptr; uint32_t *lh; struct timespec ts; struct pmclog_buffer *plb, **pplb; PMCDBG2(LOG,ALL,1, "po=%p len=%d", po, length); KASSERT(length % sizeof(uint32_t) == 0, ("[pmclog,%d] length not a multiple of word size", __LINE__)); /* No more data when shutdown in progress. */ if (po->po_flags & PMC_PO_SHUTDOWN) return (NULL); pplb = &po->po_curbuf[curcpu]; if (*pplb == NULL && pmclog_get_buffer(po) != 0) goto fail; KASSERT(*pplb != NULL, ("[pmclog,%d] po=%p no current buffer", __LINE__, po)); plb = *pplb; KASSERT(plb->plb_ptr >= plb->plb_base && plb->plb_ptr <= plb->plb_fence, ("[pmclog,%d] po=%p buffer invariants: ptr=%p base=%p fence=%p", __LINE__, po, plb->plb_ptr, plb->plb_base, plb->plb_fence)); oldptr = (uintptr_t) plb->plb_ptr; newptr = oldptr + length; KASSERT(oldptr != (uintptr_t) NULL, ("[pmclog,%d] po=%p Null log buffer pointer", __LINE__, po)); /* * If we have space in the current buffer, return a pointer to * available space with the PO structure locked. */ if (newptr <= (uintptr_t) plb->plb_fence) { plb->plb_ptr = (char *) newptr; goto done; } /* * Otherwise, schedule the current buffer for output and get a * fresh buffer. */ pmclog_schedule_io(po); if (pmclog_get_buffer(po) != 0) goto fail; plb = *pplb; KASSERT(plb != NULL, ("[pmclog,%d] po=%p no current buffer", __LINE__, po)); KASSERT(plb->plb_ptr != NULL, ("[pmclog,%d] null return from pmc_get_log_buffer", __LINE__)); KASSERT(plb->plb_ptr == plb->plb_base && plb->plb_ptr <= plb->plb_fence, ("[pmclog,%d] po=%p buffer invariants: ptr=%p base=%p fence=%p", __LINE__, po, plb->plb_ptr, plb->plb_base, plb->plb_fence)); oldptr = (uintptr_t) plb->plb_ptr; done: lh = (uint32_t *) oldptr; lh++; /* skip header */ getnanotime(&ts); /* fill in the timestamp */ *lh++ = ts.tv_sec & 0xFFFFFFFF; *lh++ = ts.tv_nsec & 0xFFFFFFF; return ((uint32_t *) oldptr); fail: return (NULL); } /* * Schedule an I/O. * * Transfer the current buffer to the helper kthread. */ static void pmclog_schedule_io(struct pmc_owner *po) { struct pmclog_buffer *plb; plb = po->po_curbuf[curcpu]; po->po_curbuf[curcpu] = NULL; KASSERT(plb != NULL, ("[pmclog,%d] schedule_io with null buffer po=%p", __LINE__, po)); KASSERT(plb->plb_ptr >= plb->plb_base, ("[pmclog,%d] buffer invariants po=%p ptr=%p base=%p", __LINE__, po, plb->plb_ptr, plb->plb_base)); KASSERT(plb->plb_ptr <= plb->plb_fence, ("[pmclog,%d] buffer invariants po=%p ptr=%p fenc=%p", __LINE__, po, plb->plb_ptr, plb->plb_fence)); PMCDBG1(LOG,SIO, 1, "po=%p", po); /* * Add the current buffer to the tail of the buffer list and * wakeup the helper. */ mtx_lock_spin(&po->po_mtx); TAILQ_INSERT_TAIL(&po->po_logbuffers, plb, plb_next); mtx_unlock_spin(&po->po_mtx); wakeup_one(po); } /* * Stop the helper kthread. */ static void pmclog_stop_kthread(struct pmc_owner *po) { mtx_lock(&pmc_kthread_mtx); po->po_flags &= ~PMC_PO_OWNS_LOGFILE; if (po->po_kthread != NULL) { PROC_LOCK(po->po_kthread); kern_psignal(po->po_kthread, SIGHUP); PROC_UNLOCK(po->po_kthread); } wakeup_one(po); while (po->po_kthread) msleep(po->po_kthread, &pmc_kthread_mtx, PPAUSE, "pmckstp", 0); mtx_unlock(&pmc_kthread_mtx); } /* * Public functions */ /* * Configure a log file for pmc owner 'po'. * * Parameter 'logfd' is a file handle referencing an open file in the * owner process. This file needs to have been opened for writing. */ int pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd) { struct proc *p; int error; sx_assert(&pmc_sx, SA_XLOCKED); PMCDBG2(LOG,CFG,1, "config po=%p logfd=%d", po, logfd); p = po->po_owner; /* return EBUSY if a log file was already present */ if (po->po_flags & PMC_PO_OWNS_LOGFILE) return (EBUSY); KASSERT(po->po_file == NULL, ("[pmclog,%d] po=%p file (%p) already present", __LINE__, po, po->po_file)); /* get a reference to the file state */ error = fget_write(curthread, logfd, &cap_write_rights, &po->po_file); if (error) goto error; /* mark process as owning a log file */ po->po_flags |= PMC_PO_OWNS_LOGFILE; /* mark process as using HWPMCs */ PROC_LOCK(p); p->p_flag |= P_HWPMC; PROC_UNLOCK(p); /* create a log initialization entry */ PMCLOG_RESERVE_WITH_ERROR(po, INITIALIZE, sizeof(struct pmclog_initialize)); PMCLOG_EMIT32(PMC_VERSION); PMCLOG_EMIT32(md->pmd_cputype); PMCLOG_DESPATCH_SYNC(po); return (0); error: KASSERT(po->po_kthread == NULL, ("[pmclog,%d] po=%p kthread not " "stopped", __LINE__, po)); if (po->po_file) (void) fdrop(po->po_file, curthread); po->po_file = NULL; /* clear file and error state */ po->po_error = 0; po->po_flags &= ~PMC_PO_OWNS_LOGFILE; return (error); } /* * De-configure a log file. This will throw away any buffers queued * for this owner process. */ int pmclog_deconfigure_log(struct pmc_owner *po) { int error; struct pmclog_buffer *lb; PMCDBG1(LOG,CFG,1, "de-config po=%p", po); if ((po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) return (EINVAL); KASSERT(po->po_sscount == 0, ("[pmclog,%d] po=%p still owning SS PMCs", __LINE__, po)); KASSERT(po->po_file != NULL, ("[pmclog,%d] po=%p no log file", __LINE__, po)); /* stop the kthread, this will reset the 'OWNS_LOGFILE' flag */ pmclog_stop_kthread(po); KASSERT(po->po_kthread == NULL, ("[pmclog,%d] po=%p kthread not stopped", __LINE__, po)); /* return all queued log buffers to the global pool */ while ((lb = TAILQ_FIRST(&po->po_logbuffers)) != NULL) { TAILQ_REMOVE(&po->po_logbuffers, lb, plb_next); PMCLOG_RESET_BUFFER_DESCRIPTOR(lb); pmc_plb_rele(lb); } for (int i = 0; i < mp_ncpus; i++) { thread_lock(curthread); sched_bind(curthread, i); thread_unlock(curthread); /* return the 'current' buffer to the global pool */ if ((lb = po->po_curbuf[curcpu]) != NULL) { PMCLOG_RESET_BUFFER_DESCRIPTOR(lb); pmc_plb_rele(lb); } } thread_lock(curthread); sched_unbind(curthread); thread_unlock(curthread); /* drop a reference to the fd */ if (po->po_file != NULL) { error = fdrop(po->po_file, curthread); po->po_file = NULL; } else error = 0; po->po_error = 0; return (error); } /* * Flush a process' log buffer. */ int pmclog_flush(struct pmc_owner *po) { int error; PMCDBG1(LOG,FLS,1, "po=%p", po); /* * If there is a pending error recorded by the logger thread, * return that. */ if (po->po_error) return (po->po_error); error = 0; /* * Check that we do have an active log file. */ mtx_lock(&pmc_kthread_mtx); if ((po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) { error = EINVAL; goto error; } pmclog_schedule_all(po); error: mtx_unlock(&pmc_kthread_mtx); return (error); } static void pmclog_schedule_one_cond(void *arg) { struct pmc_owner *po = arg; struct pmclog_buffer *plb; spinlock_enter(); /* tell hardclock not to run again */ if (PMC_CPU_HAS_SAMPLES(PCPU_GET(cpuid))) PMC_CALL_HOOK_UNLOCKED(curthread, PMC_FN_DO_SAMPLES, NULL); plb = po->po_curbuf[curcpu]; if (plb && plb->plb_ptr != plb->plb_base) pmclog_schedule_io(po); spinlock_exit(); } static void pmclog_schedule_all(struct pmc_owner *po) { /* * Schedule the current buffer if any and not empty. */ for (int i = 0; i < mp_ncpus; i++) { thread_lock(curthread); sched_bind(curthread, i); thread_unlock(curthread); pmclog_schedule_one_cond(po); } thread_lock(curthread); sched_unbind(curthread); thread_unlock(curthread); } int pmclog_close(struct pmc_owner *po) { PMCDBG1(LOG,CLO,1, "po=%p", po); pmclog_process_closelog(po); mtx_lock(&pmc_kthread_mtx); /* * Initiate shutdown: no new data queued, * thread will close file on last block. */ po->po_flags |= PMC_PO_SHUTDOWN; /* give time for all to see */ DELAY(50); /* * Schedule the current buffer. */ pmclog_schedule_all(po); wakeup_one(po); mtx_unlock(&pmc_kthread_mtx); return (0); } void pmclog_process_callchain(struct pmc *pm, struct pmc_sample *ps) { int n, recordlen; uint32_t flags; struct pmc_owner *po; PMCDBG3(LOG,SAM,1,"pm=%p pid=%d n=%d", pm, ps->ps_pid, ps->ps_nsamples); recordlen = offsetof(struct pmclog_callchain, pl_pc) + ps->ps_nsamples * sizeof(uintfptr_t); po = pm->pm_owner; flags = PMC_CALLCHAIN_TO_CPUFLAGS(ps->ps_cpu,ps->ps_flags); PMCLOG_RESERVE_SAFE(po, CALLCHAIN, recordlen); PMCLOG_EMIT32(ps->ps_pid); PMCLOG_EMIT32(ps->ps_tid); PMCLOG_EMIT32(pm->pm_id); PMCLOG_EMIT32(flags); /* unused for now */ PMCLOG_EMIT32(0); for (n = 0; n < ps->ps_nsamples; n++) PMCLOG_EMITADDR(ps->ps_pc[n]); PMCLOG_DESPATCH_SAFE(po); } void pmclog_process_closelog(struct pmc_owner *po) { PMCLOG_RESERVE(po,CLOSELOG,sizeof(struct pmclog_closelog)); PMCLOG_DESPATCH_SYNC(po); } void pmclog_process_dropnotify(struct pmc_owner *po) { PMCLOG_RESERVE(po,DROPNOTIFY,sizeof(struct pmclog_dropnotify)); PMCLOG_DESPATCH(po); } void pmclog_process_map_in(struct pmc_owner *po, pid_t pid, uintfptr_t start, const char *path) { int pathlen, recordlen; KASSERT(path != NULL, ("[pmclog,%d] map-in, null path", __LINE__)); pathlen = strlen(path) + 1; /* #bytes for path name */ recordlen = offsetof(struct pmclog_map_in, pl_pathname) + pathlen; PMCLOG_RESERVE(po, MAP_IN, recordlen); PMCLOG_EMIT32(pid); PMCLOG_EMITADDR(start); PMCLOG_EMITSTRING(path,pathlen); PMCLOG_DESPATCH(po); } void pmclog_process_map_out(struct pmc_owner *po, pid_t pid, uintfptr_t start, uintfptr_t end) { KASSERT(start <= end, ("[pmclog,%d] start > end", __LINE__)); PMCLOG_RESERVE(po, MAP_OUT, sizeof(struct pmclog_map_out)); PMCLOG_EMIT32(pid); PMCLOG_EMITADDR(start); PMCLOG_EMITADDR(end); PMCLOG_DESPATCH(po); } void pmclog_process_pmcallocate(struct pmc *pm) { struct pmc_owner *po; struct pmc_soft *ps; po = pm->pm_owner; PMCDBG1(LOG,ALL,1, "pm=%p", pm); if (PMC_TO_CLASS(pm) == PMC_CLASS_SOFT) { PMCLOG_RESERVE(po, PMCALLOCATEDYN, sizeof(struct pmclog_pmcallocatedyn)); PMCLOG_EMIT32(pm->pm_id); PMCLOG_EMIT32(pm->pm_event); PMCLOG_EMIT32(pm->pm_flags); ps = pmc_soft_ev_acquire(pm->pm_event); if (ps != NULL) PMCLOG_EMITSTRING(ps->ps_ev.pm_ev_name,PMC_NAME_MAX); else PMCLOG_EMITNULLSTRING(PMC_NAME_MAX); pmc_soft_ev_release(ps); PMCLOG_DESPATCH_SYNC(po); } else { PMCLOG_RESERVE(po, PMCALLOCATE, sizeof(struct pmclog_pmcallocate)); PMCLOG_EMIT32(pm->pm_id); PMCLOG_EMIT32(pm->pm_event); PMCLOG_EMIT32(pm->pm_flags); PMCLOG_DESPATCH_SYNC(po); } } void pmclog_process_pmcattach(struct pmc *pm, pid_t pid, char *path) { int pathlen, recordlen; struct pmc_owner *po; PMCDBG2(LOG,ATT,1,"pm=%p pid=%d", pm, pid); po = pm->pm_owner; pathlen = strlen(path) + 1; /* #bytes for the string */ recordlen = offsetof(struct pmclog_pmcattach, pl_pathname) + pathlen; PMCLOG_RESERVE(po, PMCATTACH, recordlen); PMCLOG_EMIT32(pm->pm_id); PMCLOG_EMIT32(pid); + PMCLOG_EMIT32(0); PMCLOG_EMITSTRING(path, pathlen); PMCLOG_DESPATCH_SYNC(po); } void pmclog_process_pmcdetach(struct pmc *pm, pid_t pid) { struct pmc_owner *po; PMCDBG2(LOG,ATT,1,"!pm=%p pid=%d", pm, pid); po = pm->pm_owner; PMCLOG_RESERVE(po, PMCDETACH, sizeof(struct pmclog_pmcdetach)); PMCLOG_EMIT32(pm->pm_id); PMCLOG_EMIT32(pid); PMCLOG_DESPATCH_SYNC(po); } /* * Log a context switch event to the log file. */ void pmclog_process_proccsw(struct pmc *pm, struct pmc_process *pp, pmc_value_t v, struct thread *td) { struct pmc_owner *po; KASSERT(pm->pm_flags & PMC_F_LOG_PROCCSW, ("[pmclog,%d] log-process-csw called gratuitously", __LINE__)); PMCDBG3(LOG,SWO,1,"pm=%p pid=%d v=%jx", pm, pp->pp_proc->p_pid, v); po = pm->pm_owner; PMCLOG_RESERVE(po, PROCCSW, sizeof(struct pmclog_proccsw)); PMCLOG_EMIT32(pm->pm_id); PMCLOG_EMIT64(v); PMCLOG_EMIT32(pp->pp_proc->p_pid); PMCLOG_EMIT32(td->td_tid); PMCLOG_DESPATCH(po); } void pmclog_process_procexec(struct pmc_owner *po, pmc_id_t pmid, pid_t pid, uintfptr_t startaddr, char *path) { int pathlen, recordlen; PMCDBG3(LOG,EXC,1,"po=%p pid=%d path=\"%s\"", po, pid, path); pathlen = strlen(path) + 1; /* #bytes for the path */ recordlen = offsetof(struct pmclog_procexec, pl_pathname) + pathlen; PMCLOG_RESERVE(po, PROCEXEC, recordlen); PMCLOG_EMIT32(pid); - PMCLOG_EMITADDR(startaddr); PMCLOG_EMIT32(pmid); + PMCLOG_EMIT32(0); + PMCLOG_EMITADDR(startaddr); PMCLOG_EMITSTRING(path,pathlen); PMCLOG_DESPATCH(po); } /* * Log a process exit event (and accumulated pmc value) to the log file. */ void pmclog_process_procexit(struct pmc *pm, struct pmc_process *pp) { int ri; struct pmc_owner *po; ri = PMC_TO_ROWINDEX(pm); PMCDBG3(LOG,EXT,1,"pm=%p pid=%d v=%jx", pm, pp->pp_proc->p_pid, pp->pp_pmcs[ri].pp_pmcval); po = pm->pm_owner; PMCLOG_RESERVE(po, PROCEXIT, sizeof(struct pmclog_procexit)); PMCLOG_EMIT32(pm->pm_id); - PMCLOG_EMIT64(pp->pp_pmcs[ri].pp_pmcval); PMCLOG_EMIT32(pp->pp_proc->p_pid); + PMCLOG_EMIT32(0); + PMCLOG_EMIT64(pp->pp_pmcs[ri].pp_pmcval); PMCLOG_DESPATCH(po); } /* * Log a fork event. */ void pmclog_process_procfork(struct pmc_owner *po, pid_t oldpid, pid_t newpid) { PMCLOG_RESERVE(po, PROCFORK, sizeof(struct pmclog_procfork)); PMCLOG_EMIT32(oldpid); PMCLOG_EMIT32(newpid); PMCLOG_DESPATCH(po); } /* * Log a process exit event of the form suitable for system-wide PMCs. */ void pmclog_process_sysexit(struct pmc_owner *po, pid_t pid) { PMCLOG_RESERVE(po, SYSEXIT, sizeof(struct pmclog_sysexit)); PMCLOG_EMIT32(pid); PMCLOG_DESPATCH(po); } /* * Write a user log entry. */ int pmclog_process_userlog(struct pmc_owner *po, struct pmc_op_writelog *wl) { int error; PMCDBG2(LOG,WRI,1, "writelog po=%p ud=0x%x", po, wl->pm_userdata); error = 0; PMCLOG_RESERVE_WITH_ERROR(po, USERDATA, sizeof(struct pmclog_userdata)); PMCLOG_EMIT32(wl->pm_userdata); PMCLOG_DESPATCH(po); error: return (error); } /* * Initialization. * * Create a pool of log buffers and initialize mutexes. */ void pmclog_initialize() { int domain; struct pmclog_buffer *plb; if (pmclog_buffer_size <= 0 || pmclog_buffer_size > 16*1024) { (void) printf("hwpmc: tunable logbuffersize=%d must be " "greater than zero and less than or equal to 16MB.\n", pmclog_buffer_size); pmclog_buffer_size = PMC_LOG_BUFFER_SIZE; } if (pmc_nlogbuffers_pcpu <= 0) { (void) printf("hwpmc: tunable nlogbuffers=%d must be greater " "than zero.\n", pmc_nlogbuffers_pcpu); pmc_nlogbuffers_pcpu = PMC_NLOGBUFFERS_PCPU; } if (pmc_nlogbuffers_pcpu*pmclog_buffer_size > 32*1024) { (void) printf("hwpmc: memory allocated pcpu must be less than 32MB (is %dK).\n", pmc_nlogbuffers_pcpu*pmclog_buffer_size); pmc_nlogbuffers_pcpu = PMC_NLOGBUFFERS_PCPU; pmclog_buffer_size = PMC_LOG_BUFFER_SIZE; } for (domain = 0; domain < NDOMAINS; domain++) { int ncpus = pmc_dom_hdrs[domain]->pdbh_ncpus; int total = ncpus*pmc_nlogbuffers_pcpu; plb = malloc_domain(sizeof(struct pmclog_buffer)*total, M_PMC, domain, M_WAITOK|M_ZERO); pmc_dom_hdrs[domain]->pdbh_plbs = plb; for (int i = 0; i < total; i++, plb++) { void *buf; buf = malloc_domain(1024 * pmclog_buffer_size, M_PMC, domain, M_WAITOK|M_ZERO); PMCLOG_INIT_BUFFER_DESCRIPTOR(plb, buf, domain); pmc_plb_rele_unlocked(plb); } } mtx_init(&pmc_kthread_mtx, "pmc-kthread", "pmc-sleep", MTX_DEF); } /* * Shutdown logging. * * Destroy mutexes and release memory back the to free pool. */ void pmclog_shutdown() { struct pmclog_buffer *plb; int domain; mtx_destroy(&pmc_kthread_mtx); for (domain = 0; domain < NDOMAINS; domain++) { while ((plb = TAILQ_FIRST(&pmc_dom_hdrs[domain]->pdbh_head)) != NULL) { TAILQ_REMOVE(&pmc_dom_hdrs[domain]->pdbh_head, plb, plb_next); free(plb->plb_base, M_PMC); } free(pmc_dom_hdrs[domain]->pdbh_plbs, M_PMC); } } diff --git a/sys/sys/pmc.h b/sys/sys/pmc.h index 64d10ab6f512..f43ade8f311a 100644 --- a/sys/sys/pmc.h +++ b/sys/sys/pmc.h @@ -1,1214 +1,1214 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2003-2008, Joseph Koshy * Copyright (c) 2007 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by A. Joseph Koshy under * sponsorship from the FreeBSD Foundation and Google, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SYS_PMC_H_ #define _SYS_PMC_H_ #include #include #include #include #include #ifdef _KERNEL #include #include #endif #define PMC_MODULE_NAME "hwpmc" #define PMC_NAME_MAX 64 /* HW counter name size */ #define PMC_CLASS_MAX 8 /* max #classes of PMCs per-system */ /* * Kernel<->userland API version number [MMmmpppp] * * Major numbers are to be incremented when an incompatible change to * the ABI occurs that older clients will not be able to handle. * * Minor numbers are incremented when a backwards compatible change * occurs that allows older correct programs to run unchanged. For * example, when support for a new PMC type is added. * * The patch version is incremented for every bug fix. */ -#define PMC_VERSION_MAJOR 0x04 +#define PMC_VERSION_MAJOR 0x05 #define PMC_VERSION_MINOR 0x01 #define PMC_VERSION_PATCH 0x0000 #define PMC_VERSION (PMC_VERSION_MAJOR << 24 | \ PMC_VERSION_MINOR << 16 | PMC_VERSION_PATCH) /* * Kinds of CPUs known. * * We keep track of CPU variants that need to be distinguished in * some way for PMC operations. CPU names are grouped by manufacturer * and numbered sparsely in order to minimize changes to the ABI involved * when new CPUs are added. */ #define __PMC_CPUS() \ __PMC_CPU(AMD_K7, 0x00, "AMD K7") \ __PMC_CPU(AMD_K8, 0x01, "AMD K8") \ __PMC_CPU(INTEL_P5, 0x80, "Intel Pentium") \ __PMC_CPU(INTEL_P6, 0x81, "Intel Pentium Pro") \ __PMC_CPU(INTEL_CL, 0x82, "Intel Celeron") \ __PMC_CPU(INTEL_PII, 0x83, "Intel Pentium II") \ __PMC_CPU(INTEL_PIII, 0x84, "Intel Pentium III") \ __PMC_CPU(INTEL_PM, 0x85, "Intel Pentium M") \ __PMC_CPU(INTEL_PIV, 0x86, "Intel Pentium IV") \ __PMC_CPU(INTEL_CORE, 0x87, "Intel Core Solo/Duo") \ __PMC_CPU(INTEL_CORE2, 0x88, "Intel Core2") \ __PMC_CPU(INTEL_CORE2EXTREME, 0x89, "Intel Core2 Extreme") \ __PMC_CPU(INTEL_ATOM, 0x8A, "Intel Atom") \ __PMC_CPU(INTEL_COREI7, 0x8B, "Intel Core i7") \ __PMC_CPU(INTEL_WESTMERE, 0x8C, "Intel Westmere") \ __PMC_CPU(INTEL_SANDYBRIDGE, 0x8D, "Intel Sandy Bridge") \ __PMC_CPU(INTEL_IVYBRIDGE, 0x8E, "Intel Ivy Bridge") \ __PMC_CPU(INTEL_SANDYBRIDGE_XEON, 0x8F, "Intel Sandy Bridge Xeon") \ __PMC_CPU(INTEL_IVYBRIDGE_XEON, 0x90, "Intel Ivy Bridge Xeon") \ __PMC_CPU(INTEL_HASWELL, 0x91, "Intel Haswell") \ __PMC_CPU(INTEL_ATOM_SILVERMONT, 0x92, "Intel Atom Silvermont") \ __PMC_CPU(INTEL_NEHALEM_EX, 0x93, "Intel Nehalem Xeon 7500") \ __PMC_CPU(INTEL_WESTMERE_EX, 0x94, "Intel Westmere Xeon E7") \ __PMC_CPU(INTEL_HASWELL_XEON, 0x95, "Intel Haswell Xeon E5 v3") \ __PMC_CPU(INTEL_BROADWELL, 0x96, "Intel Broadwell") \ __PMC_CPU(INTEL_BROADWELL_XEON, 0x97, "Intel Broadwell Xeon") \ __PMC_CPU(INTEL_SKYLAKE, 0x98, "Intel Skylake") \ __PMC_CPU(INTEL_SKYLAKE_XEON, 0x99, "Intel Skylake Xeon") \ __PMC_CPU(INTEL_XSCALE, 0x100, "Intel XScale") \ __PMC_CPU(MIPS_24K, 0x200, "MIPS 24K") \ __PMC_CPU(MIPS_OCTEON, 0x201, "Cavium Octeon") \ __PMC_CPU(MIPS_74K, 0x202, "MIPS 74K") \ __PMC_CPU(PPC_7450, 0x300, "PowerPC MPC7450") \ __PMC_CPU(PPC_E500, 0x340, "PowerPC e500 Core") \ __PMC_CPU(PPC_970, 0x380, "IBM PowerPC 970") \ __PMC_CPU(GENERIC, 0x400, "Generic") \ __PMC_CPU(ARMV7_CORTEX_A5, 0x500, "ARMv7 Cortex A5") \ __PMC_CPU(ARMV7_CORTEX_A7, 0x501, "ARMv7 Cortex A7") \ __PMC_CPU(ARMV7_CORTEX_A8, 0x502, "ARMv7 Cortex A8") \ __PMC_CPU(ARMV7_CORTEX_A9, 0x503, "ARMv7 Cortex A9") \ __PMC_CPU(ARMV7_CORTEX_A15, 0x504, "ARMv7 Cortex A15") \ __PMC_CPU(ARMV7_CORTEX_A17, 0x505, "ARMv7 Cortex A17") \ __PMC_CPU(ARMV8_CORTEX_A53, 0x600, "ARMv8 Cortex A53") \ __PMC_CPU(ARMV8_CORTEX_A57, 0x601, "ARMv8 Cortex A57") enum pmc_cputype { #undef __PMC_CPU #define __PMC_CPU(S,V,D) PMC_CPU_##S = V, __PMC_CPUS() }; #define PMC_CPU_FIRST PMC_CPU_AMD_K7 #define PMC_CPU_LAST PMC_CPU_GENERIC /* * Classes of PMCs */ #define __PMC_CLASSES() \ __PMC_CLASS(TSC, 0x00, "CPU Timestamp counter") \ __PMC_CLASS(K7, 0x01, "AMD K7 performance counters") \ __PMC_CLASS(K8, 0x02, "AMD K8 performance counters") \ __PMC_CLASS(P5, 0x03, "Intel Pentium counters") \ __PMC_CLASS(P6, 0x04, "Intel Pentium Pro counters") \ __PMC_CLASS(P4, 0x05, "Intel Pentium-IV counters") \ __PMC_CLASS(IAF, 0x06, "Intel Core2/Atom, fixed function") \ __PMC_CLASS(IAP, 0x07, "Intel Core...Atom, programmable") \ __PMC_CLASS(UCF, 0x08, "Intel Uncore fixed function") \ __PMC_CLASS(UCP, 0x09, "Intel Uncore programmable") \ __PMC_CLASS(XSCALE, 0x0A, "Intel XScale counters") \ __PMC_CLASS(MIPS24K, 0x0B, "MIPS 24K") \ __PMC_CLASS(OCTEON, 0x0C, "Cavium Octeon") \ __PMC_CLASS(PPC7450, 0x0D, "Motorola MPC7450 class") \ __PMC_CLASS(PPC970, 0x0E, "IBM PowerPC 970 class") \ __PMC_CLASS(SOFT, 0x0F, "Software events") \ __PMC_CLASS(ARMV7, 0x10, "ARMv7") \ __PMC_CLASS(ARMV8, 0x11, "ARMv8") \ __PMC_CLASS(MIPS74K, 0x12, "MIPS 74K") \ __PMC_CLASS(E500, 0x13, "Freescale e500 class") enum pmc_class { #undef __PMC_CLASS #define __PMC_CLASS(S,V,D) PMC_CLASS_##S = V, __PMC_CLASSES() }; #define PMC_CLASS_FIRST PMC_CLASS_TSC #define PMC_CLASS_LAST PMC_CLASS_E500 /* * A PMC can be in the following states: * * Hardware states: * DISABLED -- administratively prohibited from being used. * FREE -- HW available for use * Software states: * ALLOCATED -- allocated * STOPPED -- allocated, but not counting events * RUNNING -- allocated, and in operation; 'pm_runcount' * holds the number of CPUs using this PMC at * a given instant * DELETED -- being destroyed */ #define __PMC_HWSTATES() \ __PMC_STATE(DISABLED) \ __PMC_STATE(FREE) #define __PMC_SWSTATES() \ __PMC_STATE(ALLOCATED) \ __PMC_STATE(STOPPED) \ __PMC_STATE(RUNNING) \ __PMC_STATE(DELETED) #define __PMC_STATES() \ __PMC_HWSTATES() \ __PMC_SWSTATES() enum pmc_state { #undef __PMC_STATE #define __PMC_STATE(S) PMC_STATE_##S, __PMC_STATES() __PMC_STATE(MAX) }; #define PMC_STATE_FIRST PMC_STATE_DISABLED #define PMC_STATE_LAST PMC_STATE_DELETED /* * An allocated PMC may used as a 'global' counter or as a * 'thread-private' one. Each such mode of use can be in either * statistical sampling mode or in counting mode. Thus a PMC in use * * SS i.e., SYSTEM STATISTICAL -- system-wide statistical profiling * SC i.e., SYSTEM COUNTER -- system-wide counting mode * TS i.e., THREAD STATISTICAL -- thread virtual, statistical profiling * TC i.e., THREAD COUNTER -- thread virtual, counting mode * * Statistical profiling modes rely on the PMC periodically delivering * a interrupt to the CPU (when the configured number of events have * been measured), so the PMC must have the ability to generate * interrupts. * * In counting modes, the PMC counts its configured events, with the * value of the PMC being read whenever needed by its owner process. * * The thread specific modes "virtualize" the PMCs -- the PMCs appear * to be thread private and count events only when the profiled thread * actually executes on the CPU. * * The system-wide "global" modes keep the PMCs running all the time * and are used to measure the behaviour of the whole system. */ #define __PMC_MODES() \ __PMC_MODE(SS, 0) \ __PMC_MODE(SC, 1) \ __PMC_MODE(TS, 2) \ __PMC_MODE(TC, 3) enum pmc_mode { #undef __PMC_MODE #define __PMC_MODE(M,N) PMC_MODE_##M = N, __PMC_MODES() }; #define PMC_MODE_FIRST PMC_MODE_SS #define PMC_MODE_LAST PMC_MODE_TC #define PMC_IS_COUNTING_MODE(mode) \ ((mode) == PMC_MODE_SC || (mode) == PMC_MODE_TC) #define PMC_IS_SYSTEM_MODE(mode) \ ((mode) == PMC_MODE_SS || (mode) == PMC_MODE_SC) #define PMC_IS_SAMPLING_MODE(mode) \ ((mode) == PMC_MODE_SS || (mode) == PMC_MODE_TS) #define PMC_IS_VIRTUAL_MODE(mode) \ ((mode) == PMC_MODE_TS || (mode) == PMC_MODE_TC) /* * PMC row disposition */ #define __PMC_DISPOSITIONS(N) \ __PMC_DISP(STANDALONE) /* global/disabled counters */ \ __PMC_DISP(FREE) /* free/available */ \ __PMC_DISP(THREAD) /* thread-virtual PMCs */ \ __PMC_DISP(UNKNOWN) /* sentinel */ enum pmc_disp { #undef __PMC_DISP #define __PMC_DISP(D) PMC_DISP_##D , __PMC_DISPOSITIONS() }; #define PMC_DISP_FIRST PMC_DISP_STANDALONE #define PMC_DISP_LAST PMC_DISP_THREAD /* * Counter capabilities * * __PMC_CAPS(NAME, VALUE, DESCRIPTION) */ #define __PMC_CAPS() \ __PMC_CAP(INTERRUPT, 0, "generate interrupts") \ __PMC_CAP(USER, 1, "count user-mode events") \ __PMC_CAP(SYSTEM, 2, "count system-mode events") \ __PMC_CAP(EDGE, 3, "do edge detection of events") \ __PMC_CAP(THRESHOLD, 4, "ignore events below a threshold") \ __PMC_CAP(READ, 5, "read PMC counter") \ __PMC_CAP(WRITE, 6, "reprogram PMC counter") \ __PMC_CAP(INVERT, 7, "invert comparison sense") \ __PMC_CAP(QUALIFIER, 8, "further qualify monitored events") \ __PMC_CAP(PRECISE, 9, "perform precise sampling") \ __PMC_CAP(TAGGING, 10, "tag upstream events") \ __PMC_CAP(CASCADE, 11, "cascade counters") enum pmc_caps { #undef __PMC_CAP #define __PMC_CAP(NAME, VALUE, DESCR) PMC_CAP_##NAME = (1 << VALUE) , __PMC_CAPS() }; #define PMC_CAP_FIRST PMC_CAP_INTERRUPT #define PMC_CAP_LAST PMC_CAP_CASCADE /* * PMC Event Numbers * * These are generated from the definitions in "dev/hwpmc/pmc_events.h". */ enum pmc_event { #undef __PMC_EV #undef __PMC_EV_BLOCK #define __PMC_EV_BLOCK(C,V) PMC_EV_ ## C ## __BLOCK_START = (V) - 1 , #define __PMC_EV(C,N) PMC_EV_ ## C ## _ ## N , __PMC_EVENTS() }; /* * PMC SYSCALL INTERFACE */ /* * "PMC_OPS" -- these are the commands recognized by the kernel * module, and are used when performing a system call from userland. */ #define __PMC_OPS() \ __PMC_OP(CONFIGURELOG, "Set log file") \ __PMC_OP(FLUSHLOG, "Flush log file") \ __PMC_OP(GETCPUINFO, "Get system CPU information") \ __PMC_OP(GETDRIVERSTATS, "Get driver statistics") \ __PMC_OP(GETMODULEVERSION, "Get module version") \ __PMC_OP(GETPMCINFO, "Get per-cpu PMC information") \ __PMC_OP(PMCADMIN, "Set PMC state") \ __PMC_OP(PMCALLOCATE, "Allocate and configure a PMC") \ __PMC_OP(PMCATTACH, "Attach a PMC to a process") \ __PMC_OP(PMCDETACH, "Detach a PMC from a process") \ __PMC_OP(PMCGETMSR, "Get a PMC's hardware address") \ __PMC_OP(PMCRELEASE, "Release a PMC") \ __PMC_OP(PMCRW, "Read/Set a PMC") \ __PMC_OP(PMCSETCOUNT, "Set initial count/sampling rate") \ __PMC_OP(PMCSTART, "Start a PMC") \ __PMC_OP(PMCSTOP, "Stop a PMC") \ __PMC_OP(WRITELOG, "Write a cookie to the log file") \ __PMC_OP(CLOSELOG, "Close log file") \ __PMC_OP(GETDYNEVENTINFO, "Get dynamic events list") enum pmc_ops { #undef __PMC_OP #define __PMC_OP(N, D) PMC_OP_##N, __PMC_OPS() }; /* * Flags used in operations on PMCs. */ #define PMC_F_FORCE 0x00000001 /*OP ADMIN force operation */ #define PMC_F_DESCENDANTS 0x00000002 /*OP ALLOCATE track descendants */ #define PMC_F_LOG_PROCCSW 0x00000004 /*OP ALLOCATE track ctx switches */ #define PMC_F_LOG_PROCEXIT 0x00000008 /*OP ALLOCATE log proc exits */ #define PMC_F_NEWVALUE 0x00000010 /*OP RW write new value */ #define PMC_F_OLDVALUE 0x00000020 /*OP RW get old value */ #define PMC_F_KGMON 0x00000040 /*OP ALLOCATE kgmon(8) profiling */ /* V2 API */ #define PMC_F_CALLCHAIN 0x00000080 /*OP ALLOCATE capture callchains */ /* internal flags */ #define PMC_F_ATTACHED_TO_OWNER 0x00010000 /*attached to owner*/ #define PMC_F_NEEDS_LOGFILE 0x00020000 /*needs log file */ #define PMC_F_ATTACH_DONE 0x00040000 /*attached at least once */ #define PMC_CALLCHAIN_DEPTH_MAX 128 #define PMC_CC_F_USERSPACE 0x01 /*userspace callchain*/ /* * Cookies used to denote allocated PMCs, and the values of PMCs. */ typedef uint32_t pmc_id_t; typedef uint64_t pmc_value_t; #define PMC_ID_INVALID (~ (pmc_id_t) 0) /* * PMC IDs have the following format: * * +--------+----------+-----------+-----------+ * | CPU | PMC MODE | PMC CLASS | ROW INDEX | * +--------+----------+-----------+-----------+ * * where each field is 8 bits wide. Field 'CPU' is set to the * requested CPU for system-wide PMCs or PMC_CPU_ANY for process-mode * PMCs. Field 'PMC MODE' is the allocated PMC mode. Field 'PMC * CLASS' is the class of the PMC. Field 'ROW INDEX' is the row index * for the PMC. * * The 'ROW INDEX' ranges over 0..NWPMCS where NHWPMCS is the total * number of hardware PMCs on this cpu. */ #define PMC_ID_TO_ROWINDEX(ID) ((ID) & 0xFF) #define PMC_ID_TO_CLASS(ID) (((ID) & 0xFF00) >> 8) #define PMC_ID_TO_MODE(ID) (((ID) & 0xFF0000) >> 16) #define PMC_ID_TO_CPU(ID) (((ID) & 0xFF000000) >> 24) #define PMC_ID_MAKE_ID(CPU,MODE,CLASS,ROWINDEX) \ ((((CPU) & 0xFF) << 24) | (((MODE) & 0xFF) << 16) | \ (((CLASS) & 0xFF) << 8) | ((ROWINDEX) & 0xFF)) /* * Data structures for system calls supported by the pmc driver. */ /* * OP PMCALLOCATE * * Allocate a PMC on the named CPU. */ #define PMC_CPU_ANY ~0 struct pmc_op_pmcallocate { uint32_t pm_caps; /* PMC_CAP_* */ uint32_t pm_cpu; /* CPU number or PMC_CPU_ANY */ enum pmc_class pm_class; /* class of PMC desired */ enum pmc_event pm_ev; /* [enum pmc_event] desired */ uint32_t pm_flags; /* additional modifiers PMC_F_* */ enum pmc_mode pm_mode; /* desired mode */ pmc_id_t pm_pmcid; /* [return] process pmc id */ union pmc_md_op_pmcallocate pm_md; /* MD layer extensions */ }; /* * OP PMCADMIN * * Set the administrative state (i.e., whether enabled or disabled) of * a PMC 'pm_pmc' on CPU 'pm_cpu'. Note that 'pm_pmc' specifies an * absolute PMC number and need not have been first allocated by the * calling process. */ struct pmc_op_pmcadmin { int pm_cpu; /* CPU# */ uint32_t pm_flags; /* flags */ int pm_pmc; /* PMC# */ enum pmc_state pm_state; /* desired state */ }; /* * OP PMCATTACH / OP PMCDETACH * * Attach/detach a PMC and a process. */ struct pmc_op_pmcattach { pmc_id_t pm_pmc; /* PMC to attach to */ pid_t pm_pid; /* target process */ }; /* * OP PMCSETCOUNT * * Set the sampling rate (i.e., the reload count) for statistical counters. * 'pm_pmcid' need to have been previously allocated using PMCALLOCATE. */ struct pmc_op_pmcsetcount { pmc_value_t pm_count; /* initial/sample count */ pmc_id_t pm_pmcid; /* PMC id to set */ }; /* * OP PMCRW * * Read the value of a PMC named by 'pm_pmcid'. 'pm_pmcid' needs * to have been previously allocated using PMCALLOCATE. */ struct pmc_op_pmcrw { uint32_t pm_flags; /* PMC_F_{OLD,NEW}VALUE*/ pmc_id_t pm_pmcid; /* pmc id */ pmc_value_t pm_value; /* new&returned value */ }; /* * OP GETPMCINFO * * retrieve PMC state for a named CPU. The caller is expected to * allocate 'npmc' * 'struct pmc_info' bytes of space for the return * values. */ struct pmc_info { char pm_name[PMC_NAME_MAX]; /* pmc name */ enum pmc_class pm_class; /* enum pmc_class */ int pm_enabled; /* whether enabled */ enum pmc_disp pm_rowdisp; /* FREE, THREAD or STANDLONE */ pid_t pm_ownerpid; /* owner, or -1 */ enum pmc_mode pm_mode; /* current mode [enum pmc_mode] */ enum pmc_event pm_event; /* current event */ uint32_t pm_flags; /* current flags */ pmc_value_t pm_reloadcount; /* sampling counters only */ }; struct pmc_op_getpmcinfo { int32_t pm_cpu; /* 0 <= cpu < mp_maxid */ struct pmc_info pm_pmcs[]; /* space for 'npmc' structures */ }; /* * OP GETCPUINFO * * Retrieve system CPU information. */ struct pmc_classinfo { enum pmc_class pm_class; /* class id */ uint32_t pm_caps; /* counter capabilities */ uint32_t pm_width; /* width of the PMC */ uint32_t pm_num; /* number of PMCs in class */ }; struct pmc_op_getcpuinfo { enum pmc_cputype pm_cputype; /* what kind of CPU */ uint32_t pm_ncpu; /* max CPU number */ uint32_t pm_npmc; /* #PMCs per CPU */ uint32_t pm_nclass; /* #classes of PMCs */ struct pmc_classinfo pm_classes[PMC_CLASS_MAX]; }; /* * OP CONFIGURELOG * * Configure a log file for writing system-wide statistics to. */ struct pmc_op_configurelog { int pm_flags; int pm_logfd; /* logfile fd (or -1) */ }; /* * OP GETDRIVERSTATS * * Retrieve pmc(4) driver-wide statistics. */ #ifdef _KERNEL struct pmc_driverstats { counter_u64_t pm_intr_ignored; /* #interrupts ignored */ counter_u64_t pm_intr_processed; /* #interrupts processed */ counter_u64_t pm_intr_bufferfull; /* #interrupts with ENOSPC */ counter_u64_t pm_syscalls; /* #syscalls */ counter_u64_t pm_syscall_errors; /* #syscalls with errors */ counter_u64_t pm_buffer_requests; /* #buffer requests */ counter_u64_t pm_buffer_requests_failed; /* #failed buffer requests */ counter_u64_t pm_log_sweeps; /* #sample buffer processing passes */ }; #endif struct pmc_op_getdriverstats { unsigned int pm_intr_ignored; /* #interrupts ignored */ unsigned int pm_intr_processed; /* #interrupts processed */ unsigned int pm_intr_bufferfull; /* #interrupts with ENOSPC */ unsigned int pm_syscalls; /* #syscalls */ unsigned int pm_syscall_errors; /* #syscalls with errors */ unsigned int pm_buffer_requests; /* #buffer requests */ unsigned int pm_buffer_requests_failed; /* #failed buffer requests */ unsigned int pm_log_sweeps; /* #sample buffer processing passes */ }; /* * OP RELEASE / OP START / OP STOP * * Simple operations on a PMC id. */ struct pmc_op_simple { pmc_id_t pm_pmcid; }; /* * OP WRITELOG * * Flush the current log buffer and write 4 bytes of user data to it. */ struct pmc_op_writelog { uint32_t pm_userdata; }; /* * OP GETMSR * * Retrieve the machine specific address associated with the allocated * PMC. This number can be used subsequently with a read-performance-counter * instruction. */ struct pmc_op_getmsr { uint32_t pm_msr; /* machine specific address */ pmc_id_t pm_pmcid; /* allocated pmc id */ }; /* * OP GETDYNEVENTINFO * * Retrieve a PMC dynamic class events list. */ struct pmc_dyn_event_descr { char pm_ev_name[PMC_NAME_MAX]; enum pmc_event pm_ev_code; }; struct pmc_op_getdyneventinfo { enum pmc_class pm_class; unsigned int pm_nevent; struct pmc_dyn_event_descr pm_events[PMC_EV_DYN_COUNT]; }; #ifdef _KERNEL #include #include #include #include #define PMC_HASH_SIZE 1024 #define PMC_MTXPOOL_SIZE 2048 #define PMC_LOG_BUFFER_SIZE 128 #define PMC_NLOGBUFFERS_PCPU 8 #define PMC_NSAMPLES 64 #define PMC_CALLCHAIN_DEPTH 32 #define PMC_THREADLIST_MAX 64 #define PMC_SYSCTL_NAME_PREFIX "kern." PMC_MODULE_NAME "." /* * Locking keys * * (b) - pmc_bufferlist_mtx (spin lock) * (k) - pmc_kthread_mtx (sleep lock) * (o) - po->po_mtx (spin lock) * (g) - global_epoch_preempt (epoch) * (p) - pmc_sx (sx) */ /* * PMC commands */ struct pmc_syscall_args { register_t pmop_code; /* one of PMC_OP_* */ void *pmop_data; /* syscall parameter */ }; /* * Interface to processor specific s1tuff */ /* * struct pmc_descr * * Machine independent (i.e., the common parts) of a human readable * PMC description. */ struct pmc_descr { char pd_name[PMC_NAME_MAX]; /* name */ uint32_t pd_caps; /* capabilities */ enum pmc_class pd_class; /* class of the PMC */ uint32_t pd_width; /* width in bits */ }; /* * struct pmc_target * * This structure records all the target processes associated with a * PMC. */ struct pmc_target { LIST_ENTRY(pmc_target) pt_next; struct pmc_process *pt_process; /* target descriptor */ }; /* * struct pmc * * Describes each allocated PMC. * * Each PMC has precisely one owner, namely the process that allocated * the PMC. * * A PMC may be attached to multiple target processes. The * 'pm_targets' field links all the target processes being monitored * by this PMC. * * The 'pm_savedvalue' field is protected by a mutex. * * On a multi-cpu machine, multiple target threads associated with a * process-virtual PMC could be concurrently executing on different * CPUs. The 'pm_runcount' field is atomically incremented every time * the PMC gets scheduled on a CPU and atomically decremented when it * get descheduled. Deletion of a PMC is only permitted when this * field is '0'. * */ struct pmc_pcpu_state { uint8_t pps_stalled; uint8_t pps_cpustate; } __aligned(CACHE_LINE_SIZE); struct pmc { LIST_HEAD(,pmc_target) pm_targets; /* list of target processes */ LIST_ENTRY(pmc) pm_next; /* owner's list */ /* * System-wide PMCs are allocated on a CPU and are not moved * around. For system-wide PMCs we record the CPU the PMC was * allocated on in the 'CPU' field of the pmc ID. * * Virtual PMCs run on whichever CPU is currently executing * their targets' threads. For these PMCs we need to save * their current PMC counter values when they are taken off * CPU. */ union { pmc_value_t pm_savedvalue; /* Virtual PMCS */ } pm_gv; /* * For sampling mode PMCs, we keep track of the PMC's "reload * count", which is the counter value to be loaded in when * arming the PMC for the next counting session. For counting * modes on PMCs that are read-only (e.g., the x86 TSC), we * keep track of the initial value at the start of * counting-mode operation. */ union { pmc_value_t pm_reloadcount; /* sampling PMC modes */ pmc_value_t pm_initial; /* counting PMC modes */ } pm_sc; struct pmc_pcpu_state *pm_pcpu_state; volatile cpuset_t pm_cpustate; /* CPUs where PMC should be active */ uint32_t pm_caps; /* PMC capabilities */ enum pmc_event pm_event; /* event being measured */ uint32_t pm_flags; /* additional flags PMC_F_... */ struct pmc_owner *pm_owner; /* owner thread state */ counter_u64_t pm_runcount; /* #cpus currently on */ enum pmc_state pm_state; /* current PMC state */ uint32_t pm_overflowcnt; /* count overflow interrupts */ /* * The PMC ID field encodes the row-index for the PMC, its * mode, class and the CPU# associated with the PMC. */ pmc_id_t pm_id; /* allocated PMC id */ /* md extensions */ union pmc_md_pmc pm_md; }; /* * Accessor macros for 'struct pmc' */ #define PMC_TO_MODE(P) PMC_ID_TO_MODE((P)->pm_id) #define PMC_TO_CLASS(P) PMC_ID_TO_CLASS((P)->pm_id) #define PMC_TO_ROWINDEX(P) PMC_ID_TO_ROWINDEX((P)->pm_id) #define PMC_TO_CPU(P) PMC_ID_TO_CPU((P)->pm_id) /* * struct pmc_threadpmcstate * * Record per-PMC, per-thread state. */ struct pmc_threadpmcstate { pmc_value_t pt_pmcval; /* per-thread reload count */ }; /* * struct pmc_thread * * Record a 'target' thread being profiled. */ struct pmc_thread { LIST_ENTRY(pmc_thread) pt_next; /* linked list */ struct thread *pt_td; /* target thread */ struct pmc_threadpmcstate pt_pmcs[]; /* per-PMC state */ }; /* * struct pmc_process * * Record a 'target' process being profiled. * * The target process being profiled could be different from the owner * process which allocated the PMCs. Each target process descriptor * is associated with NHWPMC 'struct pmc *' pointers. Each PMC at a * given hardware row-index 'n' will use slot 'n' of the 'pp_pmcs[]' * array. The size of this structure is thus PMC architecture * dependent. * */ struct pmc_targetstate { struct pmc *pp_pmc; /* target PMC */ pmc_value_t pp_pmcval; /* per-process value */ }; struct pmc_process { LIST_ENTRY(pmc_process) pp_next; /* hash chain */ LIST_HEAD(,pmc_thread) pp_tds; /* list of threads */ struct mtx *pp_tdslock; /* lock on pp_tds thread list */ int pp_refcnt; /* reference count */ uint32_t pp_flags; /* flags PMC_PP_* */ struct proc *pp_proc; /* target process */ struct pmc_targetstate pp_pmcs[]; /* NHWPMCs */ }; #define PMC_PP_ENABLE_MSR_ACCESS 0x00000001 /* * struct pmc_owner * * We associate a PMC with an 'owner' process. * * A process can be associated with 0..NCPUS*NHWPMC PMCs during its * lifetime, where NCPUS is the numbers of CPUS in the system and * NHWPMC is the number of hardware PMCs per CPU. These are * maintained in the list headed by the 'po_pmcs' to save on space. * */ struct pmc_owner { LIST_ENTRY(pmc_owner) po_next; /* hash chain */ CK_LIST_ENTRY(pmc_owner) po_ssnext; /* (g/p) list of SS PMC owners */ LIST_HEAD(, pmc) po_pmcs; /* owned PMC list */ TAILQ_HEAD(, pmclog_buffer) po_logbuffers; /* (o) logbuffer list */ struct mtx po_mtx; /* spin lock for (o) */ struct proc *po_owner; /* owner proc */ uint32_t po_flags; /* (k) flags PMC_PO_* */ struct proc *po_kthread; /* (k) helper kthread */ struct file *po_file; /* file reference */ int po_error; /* recorded error */ short po_sscount; /* # SS PMCs owned */ short po_logprocmaps; /* global mappings done */ struct pmclog_buffer *po_curbuf[MAXCPU]; /* current log buffer */ }; #define PMC_PO_OWNS_LOGFILE 0x00000001 /* has a log file */ #define PMC_PO_SHUTDOWN 0x00000010 /* in the process of shutdown */ #define PMC_PO_INITIAL_MAPPINGS_DONE 0x00000020 /* * struct pmc_hw -- describe the state of the PMC hardware * * When in use, a HW PMC is associated with one allocated 'struct pmc' * pointed to by field 'phw_pmc'. When inactive, this field is NULL. * * On an SMP box, one or more HW PMC's in process virtual mode with * the same 'phw_pmc' could be executing on different CPUs. In order * to handle this case correctly, we need to ensure that only * incremental counts get added to the saved value in the associated * 'struct pmc'. The 'phw_save' field is used to keep the saved PMC * value at the time the hardware is started during this context * switch (i.e., the difference between the new (hardware) count and * the saved count is atomically added to the count field in 'struct * pmc' at context switch time). * */ struct pmc_hw { uint32_t phw_state; /* see PHW_* macros below */ struct pmc *phw_pmc; /* current thread PMC */ }; #define PMC_PHW_RI_MASK 0x000000FF #define PMC_PHW_CPU_SHIFT 8 #define PMC_PHW_CPU_MASK 0x0000FF00 #define PMC_PHW_FLAGS_SHIFT 16 #define PMC_PHW_FLAGS_MASK 0xFFFF0000 #define PMC_PHW_INDEX_TO_STATE(ri) ((ri) & PMC_PHW_RI_MASK) #define PMC_PHW_STATE_TO_INDEX(state) ((state) & PMC_PHW_RI_MASK) #define PMC_PHW_CPU_TO_STATE(cpu) (((cpu) << PMC_PHW_CPU_SHIFT) & \ PMC_PHW_CPU_MASK) #define PMC_PHW_STATE_TO_CPU(state) (((state) & PMC_PHW_CPU_MASK) >> \ PMC_PHW_CPU_SHIFT) #define PMC_PHW_FLAGS_TO_STATE(flags) (((flags) << PMC_PHW_FLAGS_SHIFT) & \ PMC_PHW_FLAGS_MASK) #define PMC_PHW_STATE_TO_FLAGS(state) (((state) & PMC_PHW_FLAGS_MASK) >> \ PMC_PHW_FLAGS_SHIFT) #define PMC_PHW_FLAG_IS_ENABLED (PMC_PHW_FLAGS_TO_STATE(0x01)) #define PMC_PHW_FLAG_IS_SHAREABLE (PMC_PHW_FLAGS_TO_STATE(0x02)) /* * struct pmc_sample * * Space for N (tunable) PC samples and associated control data. */ struct pmc_sample { uint16_t ps_nsamples; /* callchain depth */ uint16_t ps_cpu; /* cpu number */ uint16_t ps_flags; /* other flags */ uint8_t ps_pad[2]; lwpid_t ps_tid; /* thread id */ pid_t ps_pid; /* process PID or -1 */ struct thread *ps_td; /* which thread */ struct pmc *ps_pmc; /* interrupting PMC */ uintptr_t *ps_pc; /* (const) callchain start */ }; #define PMC_SAMPLE_FREE ((uint16_t) 0) #define PMC_SAMPLE_INUSE ((uint16_t) 0xFFFF) struct pmc_samplebuffer { struct pmc_sample * volatile ps_read; /* read pointer */ struct pmc_sample * volatile ps_write; /* write pointer */ uintptr_t *ps_callchains; /* all saved call chains */ struct pmc_sample *ps_fence; /* one beyond ps_samples[] */ struct pmc_sample ps_samples[]; /* array of sample entries */ }; /* * struct pmc_cpustate * * A CPU is modelled as a collection of HW PMCs with space for additional * flags. */ struct pmc_cpu { uint32_t pc_state; /* physical cpu number + flags */ struct pmc_samplebuffer *pc_sb[2]; /* space for samples */ struct pmc_hw *pc_hwpmcs[]; /* 'npmc' pointers */ }; #define PMC_PCPU_CPU_MASK 0x000000FF #define PMC_PCPU_FLAGS_MASK 0xFFFFFF00 #define PMC_PCPU_FLAGS_SHIFT 8 #define PMC_PCPU_STATE_TO_CPU(S) ((S) & PMC_PCPU_CPU_MASK) #define PMC_PCPU_STATE_TO_FLAGS(S) (((S) & PMC_PCPU_FLAGS_MASK) >> PMC_PCPU_FLAGS_SHIFT) #define PMC_PCPU_FLAGS_TO_STATE(F) (((F) << PMC_PCPU_FLAGS_SHIFT) & PMC_PCPU_FLAGS_MASK) #define PMC_PCPU_CPU_TO_STATE(C) ((C) & PMC_PCPU_CPU_MASK) #define PMC_PCPU_FLAG_HTT (PMC_PCPU_FLAGS_TO_STATE(0x1)) /* * struct pmc_binding * * CPU binding information. */ struct pmc_binding { int pb_bound; /* is bound? */ int pb_cpu; /* if so, to which CPU */ }; struct pmc_mdep; /* * struct pmc_classdep * * PMC class-dependent operations. */ struct pmc_classdep { uint32_t pcd_caps; /* class capabilities */ enum pmc_class pcd_class; /* class id */ int pcd_num; /* number of PMCs */ int pcd_ri; /* row index of the first PMC in class */ int pcd_width; /* width of the PMC */ /* configuring/reading/writing the hardware PMCs */ int (*pcd_config_pmc)(int _cpu, int _ri, struct pmc *_pm); int (*pcd_get_config)(int _cpu, int _ri, struct pmc **_ppm); int (*pcd_read_pmc)(int _cpu, int _ri, pmc_value_t *_value); int (*pcd_write_pmc)(int _cpu, int _ri, pmc_value_t _value); /* pmc allocation/release */ int (*pcd_allocate_pmc)(int _cpu, int _ri, struct pmc *_t, const struct pmc_op_pmcallocate *_a); int (*pcd_release_pmc)(int _cpu, int _ri, struct pmc *_pm); /* starting and stopping PMCs */ int (*pcd_start_pmc)(int _cpu, int _ri); int (*pcd_stop_pmc)(int _cpu, int _ri); /* description */ int (*pcd_describe)(int _cpu, int _ri, struct pmc_info *_pi, struct pmc **_ppmc); /* class-dependent initialization & finalization */ int (*pcd_pcpu_init)(struct pmc_mdep *_md, int _cpu); int (*pcd_pcpu_fini)(struct pmc_mdep *_md, int _cpu); /* machine-specific interface */ int (*pcd_get_msr)(int _ri, uint32_t *_msr); }; /* * struct pmc_mdep * * Machine dependent bits needed per CPU type. */ struct pmc_mdep { uint32_t pmd_cputype; /* from enum pmc_cputype */ uint32_t pmd_npmc; /* number of PMCs per CPU */ uint32_t pmd_nclass; /* number of PMC classes present */ /* * Machine dependent methods. */ /* per-cpu initialization and finalization */ int (*pmd_pcpu_init)(struct pmc_mdep *_md, int _cpu); int (*pmd_pcpu_fini)(struct pmc_mdep *_md, int _cpu); /* thread context switch in/out */ int (*pmd_switch_in)(struct pmc_cpu *_p, struct pmc_process *_pp); int (*pmd_switch_out)(struct pmc_cpu *_p, struct pmc_process *_pp); /* handle a PMC interrupt */ int (*pmd_intr)(int _cpu, struct trapframe *_tf); /* * PMC class dependent information. */ struct pmc_classdep pmd_classdep[]; }; /* * Per-CPU state. This is an array of 'mp_ncpu' pointers * to struct pmc_cpu descriptors. */ extern struct pmc_cpu **pmc_pcpu; /* driver statistics */ extern struct pmc_driverstats pmc_stats; /* cpu model name for pmu lookup */ extern char pmc_cpuid[64]; #if defined(HWPMC_DEBUG) #include /* debug flags, major flag groups */ struct pmc_debugflags { int pdb_CPU; int pdb_CSW; int pdb_LOG; int pdb_MDP; int pdb_MOD; int pdb_OWN; int pdb_PMC; int pdb_PRC; int pdb_SAM; }; extern struct pmc_debugflags pmc_debugflags; #define KTR_PMC KTR_SUBSYS #define PMC_DEBUG_STRSIZE 128 #define PMC_DEBUG_DEFAULT_FLAGS { 0, 0, 0, 0, 0, 0, 0, 0, 0 } #define PMCDBG0(M, N, L, F) do { \ if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \ CTR0(KTR_PMC, #M ":" #N ":" #L ": " F); \ } while (0) #define PMCDBG1(M, N, L, F, p1) do { \ if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \ CTR1(KTR_PMC, #M ":" #N ":" #L ": " F, p1); \ } while (0) #define PMCDBG2(M, N, L, F, p1, p2) do { \ if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \ CTR2(KTR_PMC, #M ":" #N ":" #L ": " F, p1, p2); \ } while (0) #define PMCDBG3(M, N, L, F, p1, p2, p3) do { \ if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \ CTR3(KTR_PMC, #M ":" #N ":" #L ": " F, p1, p2, p3); \ } while (0) #define PMCDBG4(M, N, L, F, p1, p2, p3, p4) do { \ if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \ CTR4(KTR_PMC, #M ":" #N ":" #L ": " F, p1, p2, p3, p4);\ } while (0) #define PMCDBG5(M, N, L, F, p1, p2, p3, p4, p5) do { \ if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \ CTR5(KTR_PMC, #M ":" #N ":" #L ": " F, p1, p2, p3, p4, \ p5); \ } while (0) #define PMCDBG6(M, N, L, F, p1, p2, p3, p4, p5, p6) do { \ if (pmc_debugflags.pdb_ ## M & (1 << PMC_DEBUG_MIN_ ## N)) \ CTR6(KTR_PMC, #M ":" #N ":" #L ": " F, p1, p2, p3, p4, \ p5, p6); \ } while (0) /* Major numbers */ #define PMC_DEBUG_MAJ_CPU 0 /* cpu switches */ #define PMC_DEBUG_MAJ_CSW 1 /* context switches */ #define PMC_DEBUG_MAJ_LOG 2 /* logging */ #define PMC_DEBUG_MAJ_MDP 3 /* machine dependent */ #define PMC_DEBUG_MAJ_MOD 4 /* misc module infrastructure */ #define PMC_DEBUG_MAJ_OWN 5 /* owner */ #define PMC_DEBUG_MAJ_PMC 6 /* pmc management */ #define PMC_DEBUG_MAJ_PRC 7 /* processes */ #define PMC_DEBUG_MAJ_SAM 8 /* sampling */ /* Minor numbers */ /* Common (8 bits) */ #define PMC_DEBUG_MIN_ALL 0 /* allocation */ #define PMC_DEBUG_MIN_REL 1 /* release */ #define PMC_DEBUG_MIN_OPS 2 /* ops: start, stop, ... */ #define PMC_DEBUG_MIN_INI 3 /* init */ #define PMC_DEBUG_MIN_FND 4 /* find */ /* MODULE */ #define PMC_DEBUG_MIN_PMH 14 /* pmc_hook */ #define PMC_DEBUG_MIN_PMS 15 /* pmc_syscall */ /* OWN */ #define PMC_DEBUG_MIN_ORM 8 /* owner remove */ #define PMC_DEBUG_MIN_OMR 9 /* owner maybe remove */ /* PROCESSES */ #define PMC_DEBUG_MIN_TLK 8 /* link target */ #define PMC_DEBUG_MIN_TUL 9 /* unlink target */ #define PMC_DEBUG_MIN_EXT 10 /* process exit */ #define PMC_DEBUG_MIN_EXC 11 /* process exec */ #define PMC_DEBUG_MIN_FRK 12 /* process fork */ #define PMC_DEBUG_MIN_ATT 13 /* attach/detach */ #define PMC_DEBUG_MIN_SIG 14 /* signalling */ /* CONTEXT SWITCHES */ #define PMC_DEBUG_MIN_SWI 8 /* switch in */ #define PMC_DEBUG_MIN_SWO 9 /* switch out */ /* PMC */ #define PMC_DEBUG_MIN_REG 8 /* pmc register */ #define PMC_DEBUG_MIN_ALR 9 /* allocate row */ /* MACHINE DEPENDENT LAYER */ #define PMC_DEBUG_MIN_REA 8 /* read */ #define PMC_DEBUG_MIN_WRI 9 /* write */ #define PMC_DEBUG_MIN_CFG 10 /* config */ #define PMC_DEBUG_MIN_STA 11 /* start */ #define PMC_DEBUG_MIN_STO 12 /* stop */ #define PMC_DEBUG_MIN_INT 13 /* interrupts */ /* CPU */ #define PMC_DEBUG_MIN_BND 8 /* bind */ #define PMC_DEBUG_MIN_SEL 9 /* select */ /* LOG */ #define PMC_DEBUG_MIN_GTB 8 /* get buf */ #define PMC_DEBUG_MIN_SIO 9 /* schedule i/o */ #define PMC_DEBUG_MIN_FLS 10 /* flush */ #define PMC_DEBUG_MIN_SAM 11 /* sample */ #define PMC_DEBUG_MIN_CLO 12 /* close */ #else #define PMCDBG0(M, N, L, F) /* nothing */ #define PMCDBG1(M, N, L, F, p1) #define PMCDBG2(M, N, L, F, p1, p2) #define PMCDBG3(M, N, L, F, p1, p2, p3) #define PMCDBG4(M, N, L, F, p1, p2, p3, p4) #define PMCDBG5(M, N, L, F, p1, p2, p3, p4, p5) #define PMCDBG6(M, N, L, F, p1, p2, p3, p4, p5, p6) #endif /* declare a dedicated memory pool */ MALLOC_DECLARE(M_PMC); /* * Functions */ struct pmc_mdep *pmc_md_initialize(void); /* MD init function */ void pmc_md_finalize(struct pmc_mdep *_md); /* MD fini function */ int pmc_getrowdisp(int _ri); int pmc_process_interrupt(int _cpu, int _soft, struct pmc *_pm, struct trapframe *_tf, int _inuserspace); int pmc_save_kernel_callchain(uintptr_t *_cc, int _maxsamples, struct trapframe *_tf); int pmc_save_user_callchain(uintptr_t *_cc, int _maxsamples, struct trapframe *_tf); struct pmc_mdep *pmc_mdep_alloc(int nclasses); void pmc_mdep_free(struct pmc_mdep *md); #endif /* _KERNEL */ #endif /* _SYS_PMC_H_ */ diff --git a/sys/sys/pmclog.h b/sys/sys/pmclog.h index 7d34f0021d8e..e438bd70acd3 100644 --- a/sys/sys/pmclog.h +++ b/sys/sys/pmclog.h @@ -1,294 +1,290 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2007, Joseph Koshy * Copyright (c) 2007 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by A. Joseph Koshy under * sponsorship from the FreeBSD Foundation and Google, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SYS_PMCLOG_H_ #define _SYS_PMCLOG_H_ #include enum pmclog_type { /* V1 ABI */ - PMCLOG_TYPE_CLOSELOG, - PMCLOG_TYPE_DROPNOTIFY, - PMCLOG_TYPE_INITIALIZE, - PMCLOG_TYPE_MAPPINGCHANGE, /* unused in v1 */ - PMCLOG_TYPE_PCSAMPLE, - PMCLOG_TYPE_PMCALLOCATE, - PMCLOG_TYPE_PMCATTACH, - PMCLOG_TYPE_PMCDETACH, - PMCLOG_TYPE_PROCCSW, - PMCLOG_TYPE_PROCEXEC, - PMCLOG_TYPE_PROCEXIT, - PMCLOG_TYPE_PROCFORK, - PMCLOG_TYPE_SYSEXIT, - PMCLOG_TYPE_USERDATA, + PMCLOG_TYPE_CLOSELOG = 1, + PMCLOG_TYPE_DROPNOTIFY = 2, + PMCLOG_TYPE_INITIALIZE = 3, + PMCLOG_TYPE_MAPPINGCHANGE = 4, /* unused in v1 */ + PMCLOG_TYPE_PMCALLOCATE = 5, + PMCLOG_TYPE_PMCATTACH = 6, + PMCLOG_TYPE_PMCDETACH = 7, + PMCLOG_TYPE_PROCCSW = 8, + PMCLOG_TYPE_PROCEXEC = 9, + PMCLOG_TYPE_PROCEXIT = 10, + PMCLOG_TYPE_PROCFORK = 11, + PMCLOG_TYPE_SYSEXIT = 12, + PMCLOG_TYPE_USERDATA = 13, /* * V2 ABI * * The MAP_{IN,OUT} event types obsolete the MAPPING_CHANGE * event type. The CALLCHAIN event type obsoletes the * PCSAMPLE event type. */ - PMCLOG_TYPE_MAP_IN, - PMCLOG_TYPE_MAP_OUT, - PMCLOG_TYPE_CALLCHAIN, + PMCLOG_TYPE_MAP_IN = 14, + PMCLOG_TYPE_MAP_OUT = 15, + PMCLOG_TYPE_CALLCHAIN = 16, /* * V3 ABI * * New variant of PMCLOG_TYPE_PMCALLOCATE for dynamic event. */ - PMCLOG_TYPE_PMCALLOCATEDYN + PMCLOG_TYPE_PMCALLOCATEDYN = 17 }; /* * A log entry descriptor comprises of a 32 bit header and a 64 bit * time stamp followed by as many 32 bit words are required to record * the event. * * Header field format: * * 31 24 16 0 * +------------+------------+-----------------------------------+ * | MAGIC | TYPE | LENGTH | * +------------+------------+-----------------------------------+ * * MAGIC is the constant PMCLOG_HEADER_MAGIC. * TYPE contains a value of type enum pmclog_type. * LENGTH contains the length of the event record, in bytes. */ #define PMCLOG_ENTRY_HEADER \ uint32_t pl_header; \ uint32_t pl_ts_sec; \ uint32_t pl_ts_nsec; /* * The following structures are used to describe the size of each kind * of log entry to sizeof(). To keep the compiler from adding * padding, the fields of each structure are aligned to their natural * boundaries, and the structures are marked as 'packed'. * * The actual reading and writing of the log file is always in terms * of 4 byte quantities. */ struct pmclog_callchain { PMCLOG_ENTRY_HEADER uint32_t pl_pid; uint32_t pl_tid; uint32_t pl_pmcid; uint32_t pl_cpuflags; uint32_t pl_cpuflags2; /* 8 byte aligned */ uintptr_t pl_pc[PMC_CALLCHAIN_DEPTH_MAX]; } __packed; #define PMC_CALLCHAIN_CPUFLAGS_TO_CPU(CF) (((CF) >> 16) & 0xFFFF) #define PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(CF) ((CF) & PMC_CC_F_USERSPACE) #define PMC_CALLCHAIN_TO_CPUFLAGS(CPU,FLAGS) \ (((CPU) << 16) | ((FLAGS) & 0xFFFF)) struct pmclog_closelog { PMCLOG_ENTRY_HEADER + uint32_t pl_pad; }; struct pmclog_dropnotify { PMCLOG_ENTRY_HEADER + uint32_t pl_pad; }; struct pmclog_initialize { PMCLOG_ENTRY_HEADER uint32_t pl_version; /* driver version */ uint32_t pl_cpu; /* enum pmc_cputype */ + uint32_t pl_pad; } __packed; struct pmclog_map_in { PMCLOG_ENTRY_HEADER uint32_t pl_pid; uintfptr_t pl_start; /* 8 byte aligned */ char pl_pathname[PATH_MAX]; } __packed; struct pmclog_map_out { PMCLOG_ENTRY_HEADER uint32_t pl_pid; uintfptr_t pl_start; /* 8 byte aligned */ uintfptr_t pl_end; } __packed; -struct pmclog_pcsample { - PMCLOG_ENTRY_HEADER - uint32_t pl_pid; - uintfptr_t pl_pc; /* 8 byte aligned */ - uint32_t pl_pmcid; - uint32_t pl_usermode; - uint32_t pl_tid; - uint32_t pl_pad; -} __packed; - struct pmclog_pmcallocate { PMCLOG_ENTRY_HEADER uint32_t pl_pmcid; uint32_t pl_event; uint32_t pl_flags; } __packed; struct pmclog_pmcattach { PMCLOG_ENTRY_HEADER uint32_t pl_pmcid; uint32_t pl_pid; + uint32_t pl_pad; char pl_pathname[PATH_MAX]; } __packed; struct pmclog_pmcdetach { PMCLOG_ENTRY_HEADER uint32_t pl_pmcid; uint32_t pl_pid; + uint32_t pl_pad; } __packed; struct pmclog_proccsw { PMCLOG_ENTRY_HEADER uint32_t pl_pmcid; uint64_t pl_value; /* keep 8 byte aligned */ uint32_t pl_pid; uint32_t pl_tid; } __packed; struct pmclog_procexec { PMCLOG_ENTRY_HEADER uint32_t pl_pid; - uintfptr_t pl_start; /* keep 8 byte aligned */ uint32_t pl_pmcid; + uint32_t pl_pad; + uintfptr_t pl_start; /* keep 8 byte aligned */ char pl_pathname[PATH_MAX]; } __packed; struct pmclog_procexit { PMCLOG_ENTRY_HEADER uint32_t pl_pmcid; - uint64_t pl_value; /* keep 8 byte aligned */ uint32_t pl_pid; + uint32_t pl_pad; + uint64_t pl_value; /* keep 8 byte aligned */ } __packed; struct pmclog_procfork { PMCLOG_ENTRY_HEADER uint32_t pl_oldpid; uint32_t pl_newpid; + uint32_t pl_pad; } __packed; struct pmclog_sysexit { PMCLOG_ENTRY_HEADER uint32_t pl_pid; } __packed; struct pmclog_userdata { PMCLOG_ENTRY_HEADER uint32_t pl_userdata; } __packed; struct pmclog_pmcallocatedyn { PMCLOG_ENTRY_HEADER uint32_t pl_pmcid; uint32_t pl_event; uint32_t pl_flags; char pl_evname[PMC_NAME_MAX]; } __packed; union pmclog_entry { /* only used to size scratch areas */ struct pmclog_callchain pl_cc; struct pmclog_closelog pl_cl; struct pmclog_dropnotify pl_dn; struct pmclog_initialize pl_i; struct pmclog_map_in pl_mi; struct pmclog_map_out pl_mo; - struct pmclog_pcsample pl_s; struct pmclog_pmcallocate pl_a; struct pmclog_pmcallocatedyn pl_ad; struct pmclog_pmcattach pl_t; struct pmclog_pmcdetach pl_d; struct pmclog_proccsw pl_c; struct pmclog_procexec pl_x; struct pmclog_procexit pl_e; struct pmclog_procfork pl_f; struct pmclog_sysexit pl_se; struct pmclog_userdata pl_u; }; #define PMCLOG_HEADER_MAGIC 0xEEU #define PMCLOG_HEADER_TO_LENGTH(H) \ ((H) & 0x0000FFFF) #define PMCLOG_HEADER_TO_TYPE(H) \ (((H) & 0x00FF0000) >> 16) #define PMCLOG_HEADER_TO_MAGIC(H) \ (((H) & 0xFF000000) >> 24) #define PMCLOG_HEADER_CHECK_MAGIC(H) \ (PMCLOG_HEADER_TO_MAGIC(H) == PMCLOG_HEADER_MAGIC) #ifdef _KERNEL /* * Prototypes */ int pmclog_configure_log(struct pmc_mdep *_md, struct pmc_owner *_po, int _logfd); int pmclog_deconfigure_log(struct pmc_owner *_po); int pmclog_flush(struct pmc_owner *_po); int pmclog_close(struct pmc_owner *_po); void pmclog_initialize(void); int pmclog_proc_create(struct thread *td, void **handlep); void pmclog_proc_ignite(void *handle, struct pmc_owner *po); void pmclog_process_callchain(struct pmc *_pm, struct pmc_sample *_ps); void pmclog_process_closelog(struct pmc_owner *po); void pmclog_process_dropnotify(struct pmc_owner *po); void pmclog_process_map_in(struct pmc_owner *po, pid_t pid, uintfptr_t start, const char *path); void pmclog_process_map_out(struct pmc_owner *po, pid_t pid, uintfptr_t start, uintfptr_t end); void pmclog_process_pmcallocate(struct pmc *_pm); void pmclog_process_pmcattach(struct pmc *_pm, pid_t _pid, char *_path); void pmclog_process_pmcdetach(struct pmc *_pm, pid_t _pid); void pmclog_process_proccsw(struct pmc *_pm, struct pmc_process *_pp, pmc_value_t _v, struct thread *); void pmclog_process_procexec(struct pmc_owner *_po, pmc_id_t _pmid, pid_t _pid, uintfptr_t _startaddr, char *_path); void pmclog_process_procexit(struct pmc *_pm, struct pmc_process *_pp); void pmclog_process_procfork(struct pmc_owner *_po, pid_t _oldpid, pid_t _newpid); void pmclog_process_sysexit(struct pmc_owner *_po, pid_t _pid); int pmclog_process_userlog(struct pmc_owner *_po, struct pmc_op_writelog *_wl); void pmclog_shutdown(void); #endif /* _KERNEL */ #endif /* _SYS_PMCLOG_H_ */ diff --git a/usr.sbin/pmcstat/pmcstat.8 b/usr.sbin/pmcstat/pmcstat.8 index fa68a39a1483..f6ff4fbb32cb 100644 --- a/usr.sbin/pmcstat/pmcstat.8 +++ b/usr.sbin/pmcstat/pmcstat.8 @@ -1,511 +1,520 @@ .\" Copyright (c) 2003-2008 Joseph Koshy .\" Copyright (c) 2007 The FreeBSD Foundation .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" This software is provided by Joseph Koshy ``as is'' and .\" any express or implied warranties, including, but not limited to, the .\" implied warranties of merchantability and fitness for a particular purpose .\" are disclaimed. in no event shall Joseph Koshy be liable .\" for any direct, indirect, incidental, special, exemplary, or consequential .\" damages (including, but not limited to, procurement of substitute goods .\" or services; loss of use, data, or profits; or business interruption) .\" however caused and on any theory of liability, whether in contract, strict .\" liability, or tort (including negligence or otherwise) arising in any way .\" out of the use of this software, even if advised of the possibility of .\" such damage. .\" .\" $FreeBSD$ .\" .Dd May 25, 2018 .Dt PMCSTAT 8 .Os .Sh NAME .Nm pmcstat .Nd "performance measurement with performance monitoring hardware" .Sh SYNOPSIS .Nm .Op Fl C .Op Fl D Ar pathname .Op Fl E .Op Fl F Ar pathname .Op Fl G Ar pathname .Op Fl I -.Op Fl L Ar lwp +.Op Fl L .Op Fl M Ar mapfilename .Op Fl N .Op Fl O Ar logfilename .Op Fl P Ar event-spec .Op Fl R Ar logfilename .Op Fl S Ar event-spec .Op Fl T +.Op Fl U Ar event-spec .Op Fl W .Op Fl a Ar pathname .Op Fl c Ar cpu-spec .Op Fl d .Op Fl e .Op Fl f Ar pluginopt .Op Fl g +.Op Fl i Ar lwp .Op Fl k Ar kerneldir .Op Fl l Ar secs .Op Fl m Ar pathname .Op Fl n Ar rate .Op Fl o Ar outputfile .Op Fl p Ar event-spec .Op Fl q .Op Fl r Ar fsroot .Op Fl s Ar event-spec .Op Fl t Ar process-spec +.Op Fl u Ar event-spec .Op Fl v .Op Fl w Ar secs .Op Fl z Ar graphdepth .Op Ar command Op Ar args .Sh DESCRIPTION The .Nm utility measures system performance using the facilities provided by .Xr hwpmc 4 . .Pp The .Nm utility can measure both hardware events seen by the system as a whole, and those seen when a specified set of processes are executing on the system's CPUs. If a specific set of processes is being targeted (for example, if the .Fl t Ar process-spec option is specified, or if a command line is specified using .Ar command ) , then measurement occurs till .Ar command exits, or till all target processes specified by the .Fl t Ar process-spec options exit, or till the .Nm utility is interrupted by the user. If a specific set of processes is not targeted for measurement, then .Nm will perform system-wide measurements till interrupted by the user. .Pp A given invocation of .Nm can mix allocations of system-mode and process-mode PMCs, of both counting and sampling flavors. The values of all counting PMCs are printed in human readable form at regular intervals by .Nm . The output of sampling PMCs may be configured to go to a log file for subsequent offline analysis, or, at the expense of greater overhead, may be configured to be printed in text form on the fly. .Pp Hardware events to measure are specified to .Nm using event specifier strings .Ar event-spec . The syntax of these event specifiers is machine dependent and is documented in .Xr pmc 3 . .Pp A process-mode PMC may be configured to be inheritable by the target process' current and future children. .Sh OPTIONS The following options are available: .Bl -tag -width indent .It Fl C Toggle between showing cumulative or incremental counts for subsequent counting mode PMCs specified on the command line. The default is to show incremental counts. .It Fl D Ar pathname Create files with per-program samples in the directory named by .Ar pathname . The default is to create these files in the current directory. .It Fl E Toggle showing per-process counts at the time a tracked process exits for subsequent process-mode PMCs specified on the command line. This option is useful for mapping the performance characteristics of a complex pipeline of processes when used in conjunction with the .Fl d option. The default is to not to enable per-process tracking. .It Fl F Ar pathname Print calltree (Kcachegrind) information to file .Ar pathname . If argument .Ar pathname is a .Dq Li - this information is sent to the output file specified by the .Fl o option. .It Fl G Ar pathname Print callchain information to file .Ar pathname . If argument .Ar pathname is a .Dq Li - this information is sent to the output file specified by the .Fl o option. .It Fl I Skip symbol lookup and display address instead. -.It Fl L Ar lwp -Filter on thread ID -.Ar lwp , -which you can get from -.Xr ps 1 -.Fl o -.Li lwp . +.It Fl L +List all event names. .It Fl M Ar mapfilename Write the mapping between executable objects encountered in the event log and the abbreviated pathnames used for .Xr gprof 1 profiles to file .Ar mapfilename . If this option is not specified, mapping information is not written. Argument .Ar mapfilename may be a .Dq Li - in which case this mapping information is sent to the output file configured by the .Fl o option. .It Fl N Toggle capturing callchain information for subsequent sampling PMCs. The default is for sampling PMCs to capture callchain information. .It Fl O Ar logfilename Send logging output to file .Ar logfilename . If .Ar logfilename is of the form .Ar hostname Ns : Ns Ar port , where .Ar hostname does not start with a .Ql \&. or a .Ql / , then .Nm will open a network socket to host .Ar hostname on port .Ar port . .Pp If the .Fl O option is not specified and one of the logging options is requested, then .Nm will print a textual form of the logged events to the configured output file. .It Fl P Ar event-spec Allocate a process mode sampling PMC measuring hardware events specified in .Ar event-spec . .It Fl R Ar logfilename Perform offline analysis using sampling data in file .Ar logfilename . .It Fl S Ar event-spec Allocate a system mode sampling PMC measuring hardware events specified in .Ar event-spec . .It Fl T Use a top like mode for sampling PMCs. The following hotkeys can be used: 'c+a' switch to accumulative mode, 'c+d' switch to delta mode, 'm' merge PMCs, 'n' change view, 'p' show next PMC, ' ' pause, 'q' quit. calltree only: 'f' cost under threshold is seen as a dot. +.It Fl U Ar event-spec +Provide long description of event. .It Fl W Toggle logging the incremental counts seen by the threads of a tracked process each time they are scheduled on a CPU. This is an experimental feature intended to help analyse the dynamic behaviour of processes in the system. It may incur substantial overhead if enabled. The default is for this feature to be disabled. .It Fl a Ar pathname Perform a symbol and file:line lookup for each address in each callgraph and save the output to .Ar pathname . Unlike .Fl m that only resolves the first symbol in the graph, this resolves every node in the callgraph, or prints out addresses if no lookup information is available. This option requires the .Fl R option to read in samples that were previously collected and saved with the .Fl O option. .It Fl c Ar cpu-spec Set the cpus for subsequent system mode PMCs specified on the command line to .Ar cpu-spec . Argument .Ar cpu-spec is a comma separated list of CPU numbers, or the literal .Sq * denoting all available CPUs. The default is to allocate system mode PMCs on all available CPUs. .It Fl d Toggle between process mode PMCs measuring events for the target process' current and future children or only measuring events for the target process. The default is to measure events for the target process alone. (it has to be passed in the command line prior to .Fl p , .Fl s , .Fl P , or .Fl S ) . .It Fl e Specify that the gprof profile files will use a wide history counter. These files are produced in a format compatible with .Xr gprof 1 . However, other tools that cannot fully parse a BSD-style gmon header might be unable to correctly parse these files. .It Fl f Ar pluginopt Pass option string to the active plugin. .br threshold= do not display cost under specified value (Top). .br skiplink=0|1 replace node with cost under threshold by a dot (Top). .It Fl g Produce profiles in a format compatible with .Xr gprof 1 . A separate profile file is generated for each executable object encountered. Profile files are placed in sub-directories named by their PMC event name. +.It Fl i Ar lwp +Filter on thread ID +.Ar lwp , +which you can get from +.Xr ps 1 +.Fl o +.Li lwp . .It Fl k Ar kerneldir Set the pathname of the kernel directory to argument .Ar kerneldir . This directory specifies where .Nm should look for the kernel and its modules. The default is to use the path of the running kernel obtained from the .Va kern.bootfile sysctl. .It Fl l Ar secs Set system-wide performance measurement duration for .Ar secs seconds. The argument .Ar secs may be a fractional value. .It Fl m Ar pathname Print the sampled PCs with the name, the start and ending addresses of the function within they live. The .Ar pathname argument is mandatory and indicates where the information will be stored. If argument .Ar pathname is a .Dq Li - this information is sent to the output file specified by the .Fl o option. This option requires the .Fl R option to read in samples that were previously collected and saved with the .Fl O option. .It Fl n Ar rate Set the default sampling rate for subsequent sampling mode PMCs specified on the command line. The default is to configure PMCs to sample the CPU's instruction pointer every 65536 events. .It Fl o Ar outputfile Send counter readings and textual representations of logged data to file .Ar outputfile . The default is to send output to .Pa stderr when collecting live data and to .Pa stdout when processing a pre-existing logfile. .It Fl p Ar event-spec Allocate a process mode counting PMC measuring hardware events specified in .Ar event-spec . .It Fl q Decrease verbosity. .It Fl r Ar fsroot Set the top of the filesystem hierarchy under which executables are located to argument .Ar fsroot . The default is .Pa / . .It Fl s Ar event-spec Allocate a system mode counting PMC measuring hardware events specified in .Ar event-spec . .It Fl t Ar process-spec Attach process mode PMCs to the processes named by argument .Ar process-spec . Argument .Ar process-spec may be a non-negative integer denoting a specific process id, or a regular expression for selecting processes based on their command names. +.It Fl u Ar event-spec +Provide short description of event. .It Fl v Increase verbosity. .It Fl w Ar secs Print the values of all counting mode PMCs or sampling mode PMCs for top mode every .Ar secs seconds. The argument .Ar secs may be a fractional value. The default interval is 5 seconds. .It Fl z Ar graphdepth When printing system-wide callgraphs, limit callgraphs to the depth specified by argument .Ar graphdepth . .El .Pp If .Ar command is specified, it is executed using .Xr execvp 3 . .Sh EXAMPLES To perform system-wide statistical sampling on an AMD Athlon CPU with samples taken every 32768 instruction retirals and data being sampled to file .Pa sample.stat , use: .Dl "pmcstat -O sample.stat -n 32768 -S k7-retired-instructions" .Pp To execute .Nm firefox and measure the number of data cache misses suffered by it and its children every 12 seconds on an AMD Athlon, use: .Dl "pmcstat -d -w 12 -p k7-dc-misses firefox" .Pp To measure instructions retired for all processes named .Dq emacs use: .Dl "pmcstat -t '^emacs$' -p instructions" .Pp To measure instructions retired for processes named .Dq emacs for a period of 10 seconds use: .Dl "pmcstat -t '^emacs$' -p instructions sleep 10" .Pp To count instruction tlb-misses on CPUs 0 and 2 on a Intel Pentium Pro/Pentium III SMP system use: .Dl "pmcstat -c 0,2 -s p6-itlb-miss" .Pp To collect profiling information for a specific process with pid 1234 based on instruction cache misses seen by it use: .Dl "pmcstat -P ic-misses -t 1234 -O /tmp/sample.out" .Pp To perform system-wide sampling on all configured processors based on processor instructions retired use: .Dl "pmcstat -S instructions -O /tmp/sample.out" If callgraph capture is not desired use: .Dl "pmcstat -N -S instructions -O /tmp/sample.out" .Pp To send the generated event log to a remote machine use: .Dl "pmcstat -S instructions -O remotehost:port" On the remote machine, the sample log can be collected using .Xr nc 1 : .Dl "nc -l remotehost port > /tmp/sample.out" .Pp To generate .Xr gprof 1 compatible profiles from a sample file use: .Dl "pmcstat -R /tmp/sample.out -g" .Pp To print a system-wide profile with callgraphs to file .Pa "foo.graph" use: .Dl "pmcstat -R /tmp/sample.out -G foo.graph" .Sh DIAGNOSTICS If option .Fl v is specified, .Nm may issue the following diagnostic messages: .Bl -diag .It "#callchain/dubious-frames" The number of callchain records that had an .Dq impossible value for a return address. .It "#exec handling errors" The number of .Xr exec 2 events in the log file that named executables that could not be analyzed. .It "#exec/elf" The number of .Xr exec 2 events that named ELF executables. .It "#exec/unknown" The number of .Xr exec 2 events that named executables with unrecognized formats. .It "#samples/total" The total number of samples in the log file. .It "#samples/unclaimed" The number of samples that could not be correlated to a known executable object (i.e., to an executable, shared library, the kernel or the runtime loader). .It "#samples/unknown-object" The number of samples that were associated with an executable with an unrecognized object format. .El .Pp .Ex -std .Sh COMPATIBILITY Due to the limitations of the .Pa gmon.out file format, .Xr gprof 1 compatible profiles generated by the .Fl g option do not contain information about calls that cross executable boundaries. The generated .Pa gmon.out files are also only meaningful for native executables. .Sh SEE ALSO .Xr gprof 1 , .Xr nc 1 , .Xr execvp 3 , .Xr pmc 3 , .Xr pmclog 3 , .Xr hwpmc 4 , .Xr pmccontrol 8 , .Xr sysctl 8 .Sh HISTORY The .Nm utility first appeared in .Fx 6.0 . It is .Ud .Sh AUTHORS .An Joseph Koshy Aq Mt jkoshy@FreeBSD.org .Sh BUGS The .Nm utility cannot yet analyse .Xr hwpmc 4 logs generated by non-native architectures. diff --git a/usr.sbin/pmcstat/pmcstat.c b/usr.sbin/pmcstat/pmcstat.c index 63716e0e5c0d..45b272b60b59 100644 --- a/usr.sbin/pmcstat/pmcstat.c +++ b/usr.sbin/pmcstat/pmcstat.c @@ -1,1426 +1,1457 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2003-2008, Joseph Koshy * Copyright (c) 2007 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by A. Joseph Koshy under * sponsorship from the FreeBSD Foundation and Google, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pmcstat.h" /* * A given invocation of pmcstat(8) can manage multiple PMCs of both * the system-wide and per-process variety. Each of these could be in * 'counting mode' or in 'sampling mode'. * * For 'counting mode' PMCs, pmcstat(8) will periodically issue a * pmc_read() at the configured time interval and print out the value * of the requested PMCs. * * For 'sampling mode' PMCs it can log to a file for offline analysis, * or can analyse sampling data "on the fly", either by converting * samples to printed textual form or by creating gprof(1) compatible * profiles, one per program executed. When creating gprof(1) * profiles it can optionally merge entries from multiple processes * for a given executable into a single profile file. * * pmcstat(8) can also execute a command line and attach PMCs to the * resulting child process. The protocol used is as follows: * * - parent creates a socketpair for two way communication and * fork()s. * - subsequently: * * /Parent/ /Child/ * * - Wait for childs token. * - Sends token. * - Awaits signal to start. * - Attaches PMCs to the child's pid * and starts them. Sets up * monitoring for the child. * - Signals child to start. * - Receives signal, attempts exec(). * * After this point normal processing can happen. */ /* Globals */ int pmcstat_displayheight = DEFAULT_DISPLAY_HEIGHT; int pmcstat_displaywidth = DEFAULT_DISPLAY_WIDTH; static int pmcstat_sockpair[NSOCKPAIRFD]; static int pmcstat_kq; static kvm_t *pmcstat_kvm; static struct kinfo_proc *pmcstat_plist; struct pmcstat_args args; static void pmcstat_get_cpumask(const char *cpuspec, cpuset_t *cpumask) { int cpu; const char *s; char *end; CPU_ZERO(cpumask); s = cpuspec; do { cpu = strtol(s, &end, 0); if (cpu < 0 || end == s) errx(EX_USAGE, "ERROR: Illegal CPU specification \"%s\".", cpuspec); CPU_SET(cpu, cpumask); s = end + strspn(end, ", \t"); } while (*s); assert(!CPU_EMPTY(cpumask)); } void pmcstat_cleanup(void) { struct pmcstat_ev *ev; /* release allocated PMCs. */ STAILQ_FOREACH(ev, &args.pa_events, ev_next) if (ev->ev_pmcid != PMC_ID_INVALID) { if (pmc_stop(ev->ev_pmcid) < 0) err(EX_OSERR, "ERROR: cannot stop pmc 0x%x \"%s\"", ev->ev_pmcid, ev->ev_name); if (pmc_release(ev->ev_pmcid) < 0) err(EX_OSERR, "ERROR: cannot release pmc 0x%x \"%s\"", ev->ev_pmcid, ev->ev_name); } /* de-configure the log file if present. */ if (args.pa_flags & (FLAG_HAS_PIPE | FLAG_HAS_OUTPUT_LOGFILE)) (void) pmc_configure_logfile(-1); if (args.pa_logparser) { pmclog_close(args.pa_logparser); args.pa_logparser = NULL; } pmcstat_log_shutdown_logging(); } void pmcstat_find_targets(const char *spec) { int n, nproc, pid, rv; struct pmcstat_target *pt; char errbuf[_POSIX2_LINE_MAX], *end; static struct kinfo_proc *kp; regex_t reg; regmatch_t regmatch; /* First check if we've been given a process id. */ pid = strtol(spec, &end, 0); if (end != spec && pid >= 0) { if ((pt = malloc(sizeof(*pt))) == NULL) goto outofmemory; pt->pt_pid = pid; SLIST_INSERT_HEAD(&args.pa_targets, pt, pt_next); return; } /* Otherwise treat arg as a regular expression naming processes. */ if (pmcstat_kvm == NULL) { if ((pmcstat_kvm = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf)) == NULL) err(EX_OSERR, "ERROR: Cannot open kernel \"%s\"", errbuf); if ((pmcstat_plist = kvm_getprocs(pmcstat_kvm, KERN_PROC_PROC, 0, &nproc)) == NULL) err(EX_OSERR, "ERROR: Cannot get process list: %s", kvm_geterr(pmcstat_kvm)); } else nproc = 0; if ((rv = regcomp(®, spec, REG_EXTENDED|REG_NOSUB)) != 0) { regerror(rv, ®, errbuf, sizeof(errbuf)); err(EX_DATAERR, "ERROR: Failed to compile regex \"%s\": %s", spec, errbuf); } for (n = 0, kp = pmcstat_plist; n < nproc; n++, kp++) { if ((rv = regexec(®, kp->ki_comm, 1, ®match, 0)) == 0) { if ((pt = malloc(sizeof(*pt))) == NULL) goto outofmemory; pt->pt_pid = kp->ki_pid; SLIST_INSERT_HEAD(&args.pa_targets, pt, pt_next); } else if (rv != REG_NOMATCH) { regerror(rv, ®, errbuf, sizeof(errbuf)); errx(EX_SOFTWARE, "ERROR: Regex evalation failed: %s", errbuf); } } regfree(®); return; outofmemory: errx(EX_SOFTWARE, "Out of memory."); /*NOTREACHED*/ } void pmcstat_kill_process(void) { struct pmcstat_target *pt; assert(args.pa_flags & FLAG_HAS_COMMANDLINE); /* * If a command line was specified, it would be the very first * in the list, before any other processes specified by -t. */ pt = SLIST_FIRST(&args.pa_targets); assert(pt != NULL); if (kill(pt->pt_pid, SIGINT) != 0) err(EX_OSERR, "ERROR: cannot signal child process"); } void pmcstat_start_pmcs(void) { struct pmcstat_ev *ev; STAILQ_FOREACH(ev, &args.pa_events, ev_next) { assert(ev->ev_pmcid != PMC_ID_INVALID); if (pmc_start(ev->ev_pmcid) < 0) { warn("ERROR: Cannot start pmc 0x%x \"%s\"", ev->ev_pmcid, ev->ev_name); pmcstat_cleanup(); exit(EX_OSERR); } } } void pmcstat_print_headers(void) { struct pmcstat_ev *ev; int c, w; (void) fprintf(args.pa_printfile, PRINT_HEADER_PREFIX); STAILQ_FOREACH(ev, &args.pa_events, ev_next) { if (PMC_IS_SAMPLING_MODE(ev->ev_mode)) continue; c = PMC_IS_SYSTEM_MODE(ev->ev_mode) ? 's' : 'p'; if (ev->ev_fieldskip != 0) (void) fprintf(args.pa_printfile, "%*s", ev->ev_fieldskip, ""); w = ev->ev_fieldwidth - ev->ev_fieldskip - 2; if (c == 's') (void) fprintf(args.pa_printfile, "s/%02d/%-*s ", ev->ev_cpu, w-3, ev->ev_name); else (void) fprintf(args.pa_printfile, "p/%*s ", w, ev->ev_name); } (void) fflush(args.pa_printfile); } void pmcstat_print_counters(void) { int extra_width; struct pmcstat_ev *ev; pmc_value_t value; extra_width = sizeof(PRINT_HEADER_PREFIX) - 1; STAILQ_FOREACH(ev, &args.pa_events, ev_next) { /* skip sampling mode counters */ if (PMC_IS_SAMPLING_MODE(ev->ev_mode)) continue; if (pmc_read(ev->ev_pmcid, &value) < 0) err(EX_OSERR, "ERROR: Cannot read pmc \"%s\"", ev->ev_name); (void) fprintf(args.pa_printfile, "%*ju ", ev->ev_fieldwidth + extra_width, (uintmax_t) ev->ev_cumulative ? value : (value - ev->ev_saved)); if (ev->ev_cumulative == 0) ev->ev_saved = value; extra_width = 0; } (void) fflush(args.pa_printfile); } /* * Print output */ void pmcstat_print_pmcs(void) { static int linecount = 0; /* check if we need to print a header line */ if (++linecount > pmcstat_displayheight) { (void) fprintf(args.pa_printfile, "\n"); linecount = 1; } if (linecount == 1) pmcstat_print_headers(); (void) fprintf(args.pa_printfile, "\n"); pmcstat_print_counters(); return; } void pmcstat_show_usage(void) { errx(EX_USAGE, "[options] [commandline]\n" "\t Measure process and/or system performance using hardware\n" "\t performance monitoring counters.\n" "\t Options include:\n" "\t -C\t\t (toggle) show cumulative counts\n" "\t -D path\t create profiles in directory \"path\"\n" "\t -E\t\t (toggle) show counts at process exit\n" "\t -F file\t write a system-wide callgraph (Kcachegrind format)" " to \"file\"\n" "\t -G file\t write a system-wide callgraph to \"file\"\n" - "\t -I don't resolve leaf function name, show address instead\n" - "\t -L lwp\t filter on thread id \"lwp\" in post-processing\n" + "\t -I\t\t don't resolve leaf function name, show address instead\n" + "\t -L\t\t list all counters available on this host\n" "\t -M file\t print executable/gmon file map to \"file\"\n" "\t -N\t\t (toggle) capture callchains\n" "\t -O file\t send log output to \"file\"\n" "\t -P spec\t allocate a process-private sampling PMC\n" "\t -R file\t read events from \"file\"\n" "\t -S spec\t allocate a system-wide sampling PMC\n" "\t -T\t\t start in top mode\n" + "\t -U spec \t provide long description of counters matching spec\n" "\t -W\t\t (toggle) show counts per context switch\n" "\t -a file\t print sampled PCs and callgraph to \"file\"\n" "\t -c cpu-list\t set cpus for subsequent system-wide PMCs\n" "\t -d\t\t (toggle) track descendants\n" "\t -e\t\t use wide history counter for gprof(1) output\n" "\t -f spec\t pass \"spec\" to as plugin option\n" "\t -g\t\t produce gprof(1) compatible profiles\n" + "\t -i lwp\t\t filter on thread id \"lwp\" in post-processing\n" "\t -k dir\t\t set the path to the kernel\n" "\t -l secs\t set duration time\n" "\t -m file\t print sampled PCs to \"file\"\n" "\t -n rate\t set sampling rate\n" "\t -o file\t send print output to \"file\"\n" "\t -p spec\t allocate a process-private counting PMC\n" "\t -q\t\t suppress verbosity\n" "\t -r fsroot\t specify FS root directory\n" "\t -s spec\t allocate a system-wide counting PMC\n" "\t -t process-spec attach to running processes matching " "\"process-spec\"\n" + "\t -u spec \t provide short description of counters matching spec\n" "\t -v\t\t increase verbosity\n" "\t -w secs\t set printing time interval\n" "\t -z depth\t limit callchain display depth" ); } /* * At exit handler for top mode */ void pmcstat_topexit(void) { if (!args.pa_toptty) return; /* * Shutdown ncurses. */ clrtoeol(); refresh(); endwin(); } /* * Main */ int main(int argc, char **argv) { cpuset_t cpumask, rootmask; double interval; double duration; int option, npmc; int c, check_driver_stats; int do_callchain, do_descendants, do_logproccsw, do_logprocexit; - int do_print, do_read; + int do_print, do_read, do_listcounters, do_descr, do_long_descr; size_t len; int graphdepth; int pipefd[2], rfd; int use_cumulative_counts; short cf, cb; uint64_t current_sampling_count; - char *end, *tmp; + char *end, *tmp, *event; const char *errmsg, *graphfilename; enum pmcstat_state runstate; struct pmc_driverstats ds_start, ds_end; struct pmcstat_ev *ev; struct sigaction sa; struct kevent kev; struct winsize ws; struct stat sb; char buffer[PATH_MAX]; check_driver_stats = 0; current_sampling_count = 0; do_callchain = 1; + do_descr = 0; do_descendants = 0; + do_long_descr = 0; do_logproccsw = 0; do_logprocexit = 0; + do_listcounters = 0; use_cumulative_counts = 0; graphfilename = "-"; args.pa_required = 0; args.pa_flags = 0; args.pa_verbosity = 1; args.pa_logfd = -1; args.pa_fsroot = ""; args.pa_samplesdir = "."; args.pa_printfile = stderr; args.pa_graphdepth = DEFAULT_CALLGRAPH_DEPTH; args.pa_graphfile = NULL; args.pa_interval = DEFAULT_WAIT_INTERVAL; args.pa_mapfilename = NULL; args.pa_inputpath = NULL; args.pa_outputpath = NULL; args.pa_pplugin = PMCSTAT_PL_NONE; args.pa_plugin = PMCSTAT_PL_NONE; args.pa_ctdumpinstr = 1; args.pa_topmode = PMCSTAT_TOP_DELTA; args.pa_toptty = 0; args.pa_topcolor = 0; args.pa_mergepmc = 0; args.pa_duration = 0.0; STAILQ_INIT(&args.pa_events); SLIST_INIT(&args.pa_targets); bzero(&ds_start, sizeof(ds_start)); bzero(&ds_end, sizeof(ds_end)); ev = NULL; CPU_ZERO(&cpumask); /* Default to using the running system kernel. */ len = 0; if (sysctlbyname("kern.bootfile", NULL, &len, NULL, 0) == -1) err(EX_OSERR, "ERROR: Cannot determine path of running kernel"); args.pa_kernel = malloc(len); if (args.pa_kernel == NULL) errx(EX_SOFTWARE, "ERROR: Out of memory."); if (sysctlbyname("kern.bootfile", args.pa_kernel, &len, NULL, 0) == -1) err(EX_OSERR, "ERROR: Cannot determine path of running kernel"); /* * The initial CPU mask specifies the root mask of this process * which is usually all CPUs in the system. */ if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, sizeof(rootmask), &rootmask) == -1) err(EX_OSERR, "ERROR: Cannot determine the root set of CPUs"); CPU_COPY(&rootmask, &cpumask); while ((option = getopt(argc, argv, - "CD:EF:G:IL:M:NO:P:R:S:TWa:c:def:gk:l:m:n:o:p:qr:s:t:vw:z:")) != -1) + "CD:EF:G:ILM:NO:P:R:S:TU:WZa:c:def:gi:k:l:m:n:o:p:qr:s:t:u:vw:z:")) != -1) switch (option) { case 'a': /* Annotate + callgraph */ args.pa_flags |= FLAG_DO_ANNOTATE; args.pa_plugin = PMCSTAT_PL_ANNOTATE_CG; graphfilename = optarg; break; case 'C': /* cumulative values */ use_cumulative_counts = !use_cumulative_counts; args.pa_required |= FLAG_HAS_COUNTING_PMCS; break; case 'c': /* CPU */ if (optarg[0] == '*' && optarg[1] == '\0') CPU_COPY(&rootmask, &cpumask); else pmcstat_get_cpumask(optarg, &cpumask); args.pa_flags |= FLAGS_HAS_CPUMASK; args.pa_required |= FLAG_HAS_SYSTEM_PMCS; break; case 'D': if (stat(optarg, &sb) < 0) err(EX_OSERR, "ERROR: Cannot stat \"%s\"", optarg); if (!S_ISDIR(sb.st_mode)) errx(EX_USAGE, "ERROR: \"%s\" is not a directory.", optarg); args.pa_samplesdir = optarg; args.pa_flags |= FLAG_HAS_SAMPLESDIR; args.pa_required |= FLAG_DO_GPROF; break; case 'd': /* toggle descendents */ do_descendants = !do_descendants; args.pa_required |= FLAG_HAS_PROCESS_PMCS; break; + case 'E': /* log process exit */ + do_logprocexit = !do_logprocexit; + args.pa_required |= (FLAG_HAS_PROCESS_PMCS | + FLAG_HAS_COUNTING_PMCS | FLAG_HAS_OUTPUT_LOGFILE); + break; + case 'e': /* wide gprof metrics */ args.pa_flags |= FLAG_DO_WIDE_GPROF_HC; break; case 'F': /* produce a system-wide calltree */ args.pa_flags |= FLAG_DO_CALLGRAPHS; args.pa_plugin = PMCSTAT_PL_CALLTREE; graphfilename = optarg; break; case 'f': /* plugins options */ if (args.pa_plugin == PMCSTAT_PL_NONE) err(EX_USAGE, "ERROR: Need -g/-G/-m/-T."); pmcstat_pluginconfigure_log(optarg); break; case 'G': /* produce a system-wide callgraph */ args.pa_flags |= FLAG_DO_CALLGRAPHS; args.pa_plugin = PMCSTAT_PL_CALLGRAPH; graphfilename = optarg; break; case 'g': /* produce gprof compatible profiles */ args.pa_flags |= FLAG_DO_GPROF; args.pa_pplugin = PMCSTAT_PL_CALLGRAPH; args.pa_plugin = PMCSTAT_PL_GPROF; break; case 'I': args.pa_flags |= FLAG_SKIP_TOP_FN_RES; break; + case 'i': + args.pa_flags |= FLAG_FILTER_THREAD_ID; + args.pa_tid = strtol(optarg, &end, 0); + break; + case 'k': /* pathname to the kernel */ free(args.pa_kernel); args.pa_kernel = strdup(optarg); if (args.pa_kernel == NULL) errx(EX_SOFTWARE, "ERROR: Out of memory"); args.pa_required |= FLAG_DO_ANALYSIS; args.pa_flags |= FLAG_HAS_KERNELPATH; break; case 'L': - args.pa_flags |= FLAG_FILTER_THREAD_ID; - args.pa_tid = strtol(optarg, &end, 0); + do_listcounters = 1; break; + case 'l': /* time duration in seconds */ duration = strtod(optarg, &end); if (*end != '\0' || duration <= 0) errx(EX_USAGE, "ERROR: Illegal duration time " "value \"%s\".", optarg); args.pa_flags |= FLAG_HAS_DURATION; args.pa_duration = duration; break; case 'm': args.pa_flags |= FLAG_DO_ANNOTATE; args.pa_plugin = PMCSTAT_PL_ANNOTATE; graphfilename = optarg; break; - case 'E': /* log process exit */ - do_logprocexit = !do_logprocexit; - args.pa_required |= (FLAG_HAS_PROCESS_PMCS | - FLAG_HAS_COUNTING_PMCS | FLAG_HAS_OUTPUT_LOGFILE); - break; - case 'M': /* mapfile */ args.pa_mapfilename = optarg; break; case 'N': do_callchain = !do_callchain; args.pa_required |= FLAG_HAS_SAMPLING_PMCS; break; case 'p': /* process virtual counting PMC */ case 's': /* system-wide counting PMC */ case 'P': /* process virtual sampling PMC */ case 'S': /* system-wide sampling PMC */ if ((ev = malloc(sizeof(*ev))) == NULL) errx(EX_SOFTWARE, "ERROR: Out of memory."); switch (option) { case 'p': ev->ev_mode = PMC_MODE_TC; break; case 's': ev->ev_mode = PMC_MODE_SC; break; case 'P': ev->ev_mode = PMC_MODE_TS; break; case 'S': ev->ev_mode = PMC_MODE_SS; break; } if (option == 'P' || option == 'p') { args.pa_flags |= FLAG_HAS_PROCESS_PMCS; args.pa_required |= (FLAG_HAS_COMMANDLINE | FLAG_HAS_TARGET); } if (option == 'P' || option == 'S') { args.pa_flags |= FLAG_HAS_SAMPLING_PMCS; args.pa_required |= (FLAG_HAS_PIPE | FLAG_HAS_OUTPUT_LOGFILE); } if (option == 'p' || option == 's') args.pa_flags |= FLAG_HAS_COUNTING_PMCS; if (option == 's' || option == 'S') args.pa_flags |= FLAG_HAS_SYSTEM_PMCS; ev->ev_spec = strdup(optarg); if (ev->ev_spec == NULL) errx(EX_SOFTWARE, "ERROR: Out of memory."); if (option == 'S' || option == 'P') - ev->ev_count = current_sampling_count ? current_sampling_count : pmcstat_pmu_sample_rate_get(ev->ev_spec); + ev->ev_count = current_sampling_count ? current_sampling_count : pmc_pmu_sample_rate_get(ev->ev_spec); else ev->ev_count = -1; if (option == 'S' || option == 's') ev->ev_cpu = CPU_FFS(&cpumask) - 1; else ev->ev_cpu = PMC_CPU_ANY; ev->ev_flags = 0; if (do_callchain) ev->ev_flags |= PMC_F_CALLCHAIN; if (do_descendants) ev->ev_flags |= PMC_F_DESCENDANTS; if (do_logprocexit) ev->ev_flags |= PMC_F_LOG_PROCEXIT; if (do_logproccsw) ev->ev_flags |= PMC_F_LOG_PROCCSW; ev->ev_cumulative = use_cumulative_counts; ev->ev_saved = 0LL; ev->ev_pmcid = PMC_ID_INVALID; /* extract event name */ c = strcspn(optarg, ", \t"); ev->ev_name = malloc(c + 1); if (ev->ev_name == NULL) errx(EX_SOFTWARE, "ERROR: Out of memory."); (void) strncpy(ev->ev_name, optarg, c); *(ev->ev_name + c) = '\0'; STAILQ_INSERT_TAIL(&args.pa_events, ev, ev_next); if (option == 's' || option == 'S') { CPU_CLR(ev->ev_cpu, &cpumask); pmcstat_clone_event_descriptor(ev, &cpumask, &args); CPU_SET(ev->ev_cpu, &cpumask); } break; case 'n': /* sampling count */ current_sampling_count = strtol(optarg, &end, 0); if (*end != '\0' || current_sampling_count <= 0) errx(EX_USAGE, "ERROR: Illegal count value \"%s\".", optarg); args.pa_required |= FLAG_HAS_SAMPLING_PMCS; break; case 'o': /* outputfile */ if (args.pa_printfile != NULL && args.pa_printfile != stdout && args.pa_printfile != stderr) (void) fclose(args.pa_printfile); if ((args.pa_printfile = fopen(optarg, "w")) == NULL) errx(EX_OSERR, "ERROR: cannot open \"%s\" for writing.", optarg); args.pa_flags |= FLAG_DO_PRINT; break; case 'O': /* sampling output */ if (args.pa_outputpath) errx(EX_USAGE, "ERROR: option -O may only be specified once."); args.pa_outputpath = optarg; args.pa_flags |= FLAG_HAS_OUTPUT_LOGFILE; break; case 'q': /* quiet mode */ args.pa_verbosity = 0; break; case 'r': /* root FS path */ args.pa_fsroot = optarg; break; case 'R': /* read an existing log file */ if (args.pa_inputpath != NULL) errx(EX_USAGE, "ERROR: option -R may only be specified once."); args.pa_inputpath = optarg; if (args.pa_printfile == stderr) args.pa_printfile = stdout; args.pa_flags |= FLAG_READ_LOGFILE; break; case 't': /* target pid or process name */ pmcstat_find_targets(optarg); args.pa_flags |= FLAG_HAS_TARGET; args.pa_required |= FLAG_HAS_PROCESS_PMCS; break; case 'T': /* top mode */ args.pa_flags |= FLAG_DO_TOP; args.pa_plugin = PMCSTAT_PL_CALLGRAPH; args.pa_ctdumpinstr = 0; args.pa_mergepmc = 1; if (args.pa_printfile == stderr) args.pa_printfile = stdout; break; + case 'u': + do_descr = 1; + event = optarg; + break; + case 'U': + do_long_descr = 1; + event = optarg; + break; case 'v': /* verbose */ args.pa_verbosity++; break; case 'w': /* wait interval */ interval = strtod(optarg, &end); if (*end != '\0' || interval <= 0) errx(EX_USAGE, "ERROR: Illegal wait interval value \"%s\".", optarg); args.pa_flags |= FLAG_HAS_WAIT_INTERVAL; args.pa_interval = interval; break; case 'W': /* toggle LOG_CSW */ do_logproccsw = !do_logproccsw; args.pa_required |= (FLAG_HAS_PROCESS_PMCS | FLAG_HAS_COUNTING_PMCS | FLAG_HAS_OUTPUT_LOGFILE); break; case 'z': graphdepth = strtod(optarg, &end); if (*end != '\0' || graphdepth <= 0) errx(EX_USAGE, "ERROR: Illegal callchain depth \"%s\".", optarg); args.pa_graphdepth = graphdepth; args.pa_required |= FLAG_DO_CALLGRAPHS; break; case '?': default: pmcstat_show_usage(); break; } + if ((do_listcounters | do_descr | do_long_descr) && + pmc_pmu_enabled() == 0) + errx(EX_USAGE, "pmu features not supported on host or hwpmc not loaded"); + if (do_listcounters) { + pmc_pmu_print_counters(); + } else if (do_descr) { + pmc_pmu_print_counter_desc(event); + } else if (do_long_descr) { + pmc_pmu_print_counter_desc_long(event); + } + if (do_listcounters | do_descr | do_long_descr) + exit(0); args.pa_argc = (argc -= optind); args.pa_argv = (argv += optind); /* If we read from logfile and no specified CPU mask use * the maximum CPU count. */ if ((args.pa_flags & FLAG_READ_LOGFILE) && (args.pa_flags & FLAGS_HAS_CPUMASK) == 0) CPU_FILL(&cpumask); args.pa_cpumask = cpumask; /* For selecting CPUs using -R. */ if (argc) /* command line present */ args.pa_flags |= FLAG_HAS_COMMANDLINE; if (args.pa_flags & (FLAG_DO_GPROF | FLAG_DO_CALLGRAPHS | FLAG_DO_ANNOTATE | FLAG_DO_TOP)) args.pa_flags |= FLAG_DO_ANALYSIS; /* * Check invocation syntax. */ /* disallow -O and -R together */ if (args.pa_outputpath && args.pa_inputpath) errx(EX_USAGE, "ERROR: options -O and -R are mutually exclusive."); /* disallow -T and -l together */ if ((args.pa_flags & FLAG_HAS_DURATION) && (args.pa_flags & FLAG_DO_TOP)) errx(EX_USAGE, "ERROR: options -T and -l are mutually " "exclusive."); /* -a and -m require -R */ if (args.pa_flags & FLAG_DO_ANNOTATE && args.pa_inputpath == NULL) errx(EX_USAGE, "ERROR: option %s requires an input file", args.pa_plugin == PMCSTAT_PL_ANNOTATE ? "-m" : "-a"); /* -m option is not allowed combined with -g or -G. */ if (args.pa_flags & FLAG_DO_ANNOTATE && args.pa_flags & (FLAG_DO_GPROF | FLAG_DO_CALLGRAPHS)) errx(EX_USAGE, "ERROR: option -m and -g | -G are mutually exclusive"); if (args.pa_flags & FLAG_READ_LOGFILE) { errmsg = NULL; if (args.pa_flags & FLAG_HAS_COMMANDLINE) errmsg = "a command line specification"; else if (args.pa_flags & FLAG_HAS_TARGET) errmsg = "option -t"; else if (!STAILQ_EMPTY(&args.pa_events)) errmsg = "a PMC event specification"; if (errmsg) errx(EX_USAGE, "ERROR: option -R may not be used with %s.", errmsg); } else if (STAILQ_EMPTY(&args.pa_events)) /* All other uses require a PMC spec. */ pmcstat_show_usage(); /* check for -t pid without a process PMC spec */ if ((args.pa_required & FLAG_HAS_TARGET) && (args.pa_flags & FLAG_HAS_PROCESS_PMCS) == 0) errx(EX_USAGE, "ERROR: option -t requires a process mode PMC to be specified." ); /* check for process-mode options without a command or -t pid */ if ((args.pa_required & FLAG_HAS_PROCESS_PMCS) && (args.pa_flags & (FLAG_HAS_COMMANDLINE | FLAG_HAS_TARGET)) == 0) errx(EX_USAGE, "ERROR: options -d, -E, -p, -P, and -W require a command line or target process." ); /* check for -p | -P without a target process of some sort */ if ((args.pa_required & (FLAG_HAS_COMMANDLINE | FLAG_HAS_TARGET)) && (args.pa_flags & (FLAG_HAS_COMMANDLINE | FLAG_HAS_TARGET)) == 0) errx(EX_USAGE, "ERROR: options -P and -p require a target process or a command line." ); /* check for process-mode options without a process-mode PMC */ if ((args.pa_required & FLAG_HAS_PROCESS_PMCS) && (args.pa_flags & FLAG_HAS_PROCESS_PMCS) == 0) errx(EX_USAGE, "ERROR: options -d, -E, and -W require a process mode PMC to be specified." ); /* check for -c cpu with no system mode PMCs or logfile. */ if ((args.pa_required & FLAG_HAS_SYSTEM_PMCS) && (args.pa_flags & FLAG_HAS_SYSTEM_PMCS) == 0 && (args.pa_flags & FLAG_READ_LOGFILE) == 0) errx(EX_USAGE, "ERROR: option -c requires at least one system mode PMC to be specified." ); /* check for counting mode options without a counting PMC */ if ((args.pa_required & FLAG_HAS_COUNTING_PMCS) && (args.pa_flags & FLAG_HAS_COUNTING_PMCS) == 0) errx(EX_USAGE, "ERROR: options -C, -W and -o require at least one counting mode PMC to be specified." ); /* check for sampling mode options without a sampling PMC spec */ if ((args.pa_required & FLAG_HAS_SAMPLING_PMCS) && (args.pa_flags & FLAG_HAS_SAMPLING_PMCS) == 0) errx(EX_USAGE, "ERROR: options -N, -n and -O require at least one sampling mode PMC to be specified." ); /* check if -g/-G/-m/-T are being used correctly */ if ((args.pa_flags & FLAG_DO_ANALYSIS) && !(args.pa_flags & (FLAG_HAS_SAMPLING_PMCS|FLAG_READ_LOGFILE))) errx(EX_USAGE, "ERROR: options -g/-G/-m/-T require sampling PMCs or -R to be specified." ); /* check if -e was specified without -g */ if ((args.pa_flags & FLAG_DO_WIDE_GPROF_HC) && !(args.pa_flags & FLAG_DO_GPROF)) errx(EX_USAGE, "ERROR: option -e requires gprof mode to be specified." ); /* check if -O was spuriously specified */ if ((args.pa_flags & FLAG_HAS_OUTPUT_LOGFILE) && (args.pa_required & FLAG_HAS_OUTPUT_LOGFILE) == 0) errx(EX_USAGE, "ERROR: option -O is used only with options -E, -P, -S and -W." ); /* -k kernel path require -g/-G/-m/-T or -R */ if ((args.pa_flags & FLAG_HAS_KERNELPATH) && (args.pa_flags & FLAG_DO_ANALYSIS) == 0 && (args.pa_flags & FLAG_READ_LOGFILE) == 0) errx(EX_USAGE, "ERROR: option -k is only used with -g/-R/-m/-T."); /* -D only applies to gprof output mode (-g) */ if ((args.pa_flags & FLAG_HAS_SAMPLESDIR) && (args.pa_flags & FLAG_DO_GPROF) == 0) errx(EX_USAGE, "ERROR: option -D is only used with -g."); /* -M mapfile requires -g or -R */ if (args.pa_mapfilename != NULL && (args.pa_flags & FLAG_DO_GPROF) == 0 && (args.pa_flags & FLAG_READ_LOGFILE) == 0) errx(EX_USAGE, "ERROR: option -M is only used with -g/-R."); /* * Disallow textual output of sampling PMCs if counting PMCs * have also been asked for, mostly because the combined output * is difficult to make sense of. */ if ((args.pa_flags & FLAG_HAS_COUNTING_PMCS) && (args.pa_flags & FLAG_HAS_SAMPLING_PMCS) && ((args.pa_flags & FLAG_HAS_OUTPUT_LOGFILE) == 0)) errx(EX_USAGE, "ERROR: option -O is required if counting and sampling PMCs are specified together." ); /* * Check if 'kerneldir' refers to a file rather than a * directory. If so, use `dirname path` to determine the * kernel directory. */ (void) snprintf(buffer, sizeof(buffer), "%s%s", args.pa_fsroot, args.pa_kernel); if (stat(buffer, &sb) < 0) err(EX_OSERR, "ERROR: Cannot locate kernel \"%s\"", buffer); if (!S_ISREG(sb.st_mode) && !S_ISDIR(sb.st_mode)) errx(EX_USAGE, "ERROR: \"%s\": Unsupported file type.", buffer); if (!S_ISDIR(sb.st_mode)) { tmp = args.pa_kernel; args.pa_kernel = strdup(dirname(args.pa_kernel)); if (args.pa_kernel == NULL) errx(EX_SOFTWARE, "ERROR: Out of memory"); free(tmp); (void) snprintf(buffer, sizeof(buffer), "%s%s", args.pa_fsroot, args.pa_kernel); if (stat(buffer, &sb) < 0) err(EX_OSERR, "ERROR: Cannot stat \"%s\"", buffer); if (!S_ISDIR(sb.st_mode)) errx(EX_USAGE, "ERROR: \"%s\" is not a directory.", buffer); } /* * If we have a callgraph be created, select the outputfile. */ if (args.pa_flags & FLAG_DO_CALLGRAPHS) { if (strcmp(graphfilename, "-") == 0) args.pa_graphfile = args.pa_printfile; else { args.pa_graphfile = fopen(graphfilename, "w"); if (args.pa_graphfile == NULL) err(EX_OSERR, "ERROR: cannot open \"%s\" for writing", graphfilename); } } if (args.pa_flags & FLAG_DO_ANNOTATE) { args.pa_graphfile = fopen(graphfilename, "w"); if (args.pa_graphfile == NULL) err(EX_OSERR, "ERROR: cannot open \"%s\" for writing", graphfilename); } /* if we've been asked to process a log file, skip init */ if ((args.pa_flags & FLAG_READ_LOGFILE) == 0) { if (pmc_init() < 0) err(EX_UNAVAILABLE, "ERROR: Initialization of the pmc(3) library failed" ); if ((npmc = pmc_npmc(0)) < 0) /* assume all CPUs are identical */ err(EX_OSERR, "ERROR: Cannot determine the number of PMCs on CPU %d", 0); } /* Allocate a kqueue */ if ((pmcstat_kq = kqueue()) < 0) err(EX_OSERR, "ERROR: Cannot allocate kqueue"); /* Setup the logfile as the source. */ if (args.pa_flags & FLAG_READ_LOGFILE) { /* * Print the log in textual form if we haven't been * asked to generate profiling information. */ if ((args.pa_flags & FLAG_DO_ANALYSIS) == 0) args.pa_flags |= FLAG_DO_PRINT; pmcstat_log_initialize_logging(); rfd = pmcstat_open_log(args.pa_inputpath, PMCSTAT_OPEN_FOR_READ); if ((args.pa_logparser = pmclog_open(rfd)) == NULL) err(EX_OSERR, "ERROR: Cannot create parser"); if (fcntl(rfd, F_SETFL, O_NONBLOCK) < 0) err(EX_OSERR, "ERROR: fcntl(2) failed"); EV_SET(&kev, rfd, EVFILT_READ, EV_ADD, 0, 0, NULL); if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0) err(EX_OSERR, "ERROR: Cannot register kevent"); } /* * Configure the specified log file or setup a default log * consumer via a pipe. */ if (args.pa_required & FLAG_HAS_OUTPUT_LOGFILE) { if (args.pa_outputpath) args.pa_logfd = pmcstat_open_log(args.pa_outputpath, PMCSTAT_OPEN_FOR_WRITE); else { /* * process the log on the fly by reading it in * through a pipe. */ if (pipe(pipefd) < 0) err(EX_OSERR, "ERROR: pipe(2) failed"); if (fcntl(pipefd[READPIPEFD], F_SETFL, O_NONBLOCK) < 0) err(EX_OSERR, "ERROR: fcntl(2) failed"); EV_SET(&kev, pipefd[READPIPEFD], EVFILT_READ, EV_ADD, 0, 0, NULL); if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0) err(EX_OSERR, "ERROR: Cannot register kevent"); args.pa_logfd = pipefd[WRITEPIPEFD]; args.pa_flags |= FLAG_HAS_PIPE; if ((args.pa_flags & FLAG_DO_TOP) == 0) args.pa_flags |= FLAG_DO_PRINT; args.pa_logparser = pmclog_open(pipefd[READPIPEFD]); } if (pmc_configure_logfile(args.pa_logfd) < 0) err(EX_OSERR, "ERROR: Cannot configure log file"); } /* remember to check for driver errors if we are sampling or logging */ check_driver_stats = (args.pa_flags & FLAG_HAS_SAMPLING_PMCS) || (args.pa_flags & FLAG_HAS_OUTPUT_LOGFILE); /* if (args.pa_flags & FLAG_READ_LOGFILE) { * Allocate PMCs. */ STAILQ_FOREACH(ev, &args.pa_events, ev_next) { if (pmc_allocate(ev->ev_spec, ev->ev_mode, ev->ev_flags, ev->ev_cpu, &ev->ev_pmcid) < 0) err(EX_OSERR, "ERROR: Cannot allocate %s-mode pmc with specification \"%s\"", PMC_IS_SYSTEM_MODE(ev->ev_mode) ? "system" : "process", ev->ev_spec); if (PMC_IS_SAMPLING_MODE(ev->ev_mode) && pmc_set(ev->ev_pmcid, ev->ev_count) < 0) err(EX_OSERR, "ERROR: Cannot set sampling count for PMC \"%s\"", ev->ev_name); } /* compute printout widths */ STAILQ_FOREACH(ev, &args.pa_events, ev_next) { int counter_width; int display_width; int header_width; (void) pmc_width(ev->ev_pmcid, &counter_width); header_width = strlen(ev->ev_name) + 2; /* prefix '%c/' */ display_width = (int) floor(counter_width / 3.32193) + 1; if (PMC_IS_SYSTEM_MODE(ev->ev_mode)) header_width += 3; /* 2 digit CPU number + '/' */ if (header_width > display_width) { ev->ev_fieldskip = 0; ev->ev_fieldwidth = header_width; } else { ev->ev_fieldskip = display_width - header_width; ev->ev_fieldwidth = display_width; } } /* * If our output is being set to a terminal, register a handler * for window size changes. */ if (isatty(fileno(args.pa_printfile))) { if (ioctl(fileno(args.pa_printfile), TIOCGWINSZ, &ws) < 0) err(EX_OSERR, "ERROR: Cannot determine window size"); pmcstat_displayheight = ws.ws_row - 1; pmcstat_displaywidth = ws.ws_col - 1; EV_SET(&kev, SIGWINCH, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0) err(EX_OSERR, "ERROR: Cannot register kevent for SIGWINCH"); args.pa_toptty = 1; } /* * Listen to key input in top mode. */ if (args.pa_flags & FLAG_DO_TOP) { EV_SET(&kev, fileno(stdin), EVFILT_READ, EV_ADD, 0, 0, NULL); if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0) err(EX_OSERR, "ERROR: Cannot register kevent"); } EV_SET(&kev, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0) err(EX_OSERR, "ERROR: Cannot register kevent for SIGINT"); EV_SET(&kev, SIGIO, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0) err(EX_OSERR, "ERROR: Cannot register kevent for SIGIO"); /* * An exec() failure of a forked child is signalled by the * child sending the parent a SIGCHLD. We don't register an * actual signal handler for SIGCHLD, but instead use our * kqueue to pick up the signal. */ EV_SET(&kev, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0) err(EX_OSERR, "ERROR: Cannot register kevent for SIGCHLD"); /* * Setup a timer if we have counting mode PMCs needing to be printed or * top mode plugin is active. */ if (((args.pa_flags & FLAG_HAS_COUNTING_PMCS) && (args.pa_required & FLAG_HAS_OUTPUT_LOGFILE) == 0) || (args.pa_flags & FLAG_DO_TOP)) { EV_SET(&kev, 0, EVFILT_TIMER, EV_ADD, 0, args.pa_interval * 1000, NULL); if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0) err(EX_OSERR, "ERROR: Cannot register kevent for timer"); } /* * Setup a duration timer if we have sampling mode PMCs and * a duration time is set */ if ((args.pa_flags & FLAG_HAS_SAMPLING_PMCS) && (args.pa_flags & FLAG_HAS_DURATION)) { EV_SET(&kev, 0, EVFILT_TIMER, EV_ADD, 0, args.pa_duration * 1000, NULL); if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0) err(EX_OSERR, "ERROR: Cannot register kevent for " "time duration"); } /* attach PMCs to the target process, starting it if specified */ if (args.pa_flags & FLAG_HAS_COMMANDLINE) pmcstat_create_process(pmcstat_sockpair, &args, pmcstat_kq); if (check_driver_stats && pmc_get_driver_stats(&ds_start) < 0) err(EX_OSERR, "ERROR: Cannot retrieve driver statistics"); /* Attach process pmcs to the target process. */ if (args.pa_flags & (FLAG_HAS_TARGET | FLAG_HAS_COMMANDLINE)) { if (SLIST_EMPTY(&args.pa_targets)) errx(EX_DATAERR, "ERROR: No matching target processes."); if (args.pa_flags & FLAG_HAS_PROCESS_PMCS) pmcstat_attach_pmcs(&args); if (pmcstat_kvm) { kvm_close(pmcstat_kvm); pmcstat_kvm = NULL; } } /* start the pmcs */ pmcstat_start_pmcs(); /* start the (commandline) process if needed */ if (args.pa_flags & FLAG_HAS_COMMANDLINE) pmcstat_start_process(pmcstat_sockpair); /* initialize logging */ pmcstat_log_initialize_logging(); /* Handle SIGINT using the kqueue loop */ sa.sa_handler = SIG_IGN; sa.sa_flags = 0; (void) sigemptyset(&sa.sa_mask); if (sigaction(SIGINT, &sa, NULL) < 0) err(EX_OSERR, "ERROR: Cannot install signal handler"); /* * Setup the top mode display. */ if (args.pa_flags & FLAG_DO_TOP) { args.pa_flags &= ~FLAG_DO_PRINT; if (args.pa_toptty) { /* * Init ncurses. */ initscr(); if(has_colors() == TRUE) { args.pa_topcolor = 1; start_color(); use_default_colors(); pair_content(0, &cf, &cb); init_pair(1, COLOR_RED, cb); init_pair(2, COLOR_YELLOW, cb); init_pair(3, COLOR_GREEN, cb); } cbreak(); noecho(); nonl(); nodelay(stdscr, 1); intrflush(stdscr, FALSE); keypad(stdscr, TRUE); clear(); /* Get terminal width / height with ncurses. */ getmaxyx(stdscr, pmcstat_displayheight, pmcstat_displaywidth); pmcstat_displayheight--; pmcstat_displaywidth--; atexit(pmcstat_topexit); } } /* * loop till either the target process (if any) exits, or we * are killed by a SIGINT or we reached the time duration. */ runstate = PMCSTAT_RUNNING; do_print = do_read = 0; do { if ((c = kevent(pmcstat_kq, NULL, 0, &kev, 1, NULL)) <= 0) { if (errno != EINTR) err(EX_OSERR, "ERROR: kevent failed"); else continue; } if (kev.flags & EV_ERROR) errc(EX_OSERR, kev.data, "ERROR: kevent failed"); switch (kev.filter) { case EVFILT_PROC: /* target has exited */ runstate = pmcstat_close_log(&args); do_print = 1; break; case EVFILT_READ: /* log file data is present */ if (kev.ident == (unsigned)fileno(stdin) && (args.pa_flags & FLAG_DO_TOP)) { if (pmcstat_keypress_log()) runstate = pmcstat_close_log(&args); } else { do_read = 0; runstate = pmcstat_process_log(); } break; case EVFILT_SIGNAL: if (kev.ident == SIGCHLD) { /* * The child process sends us a * SIGCHLD if its exec() failed. We * wait for it to exit and then exit * ourselves. */ (void) wait(&c); runstate = PMCSTAT_FINISHED; } else if (kev.ident == SIGIO) { /* * We get a SIGIO if a PMC loses all * of its targets, or if logfile * writes encounter an error. */ runstate = pmcstat_close_log(&args); do_print = 1; /* print PMCs at exit */ } else if (kev.ident == SIGINT) { /* Kill the child process if we started it */ if (args.pa_flags & FLAG_HAS_COMMANDLINE) pmcstat_kill_process(); runstate = pmcstat_close_log(&args); } else if (kev.ident == SIGWINCH) { if (ioctl(fileno(args.pa_printfile), TIOCGWINSZ, &ws) < 0) err(EX_OSERR, "ERROR: Cannot determine window size"); pmcstat_displayheight = ws.ws_row - 1; pmcstat_displaywidth = ws.ws_col - 1; } else assert(0); break; case EVFILT_TIMER: /* time duration reached, exit */ if (args.pa_flags & FLAG_HAS_DURATION) { runstate = PMCSTAT_FINISHED; break; } /* print out counting PMCs */ if ((args.pa_flags & FLAG_DO_TOP) && (args.pa_flags & FLAG_HAS_PIPE) && pmc_flush_logfile() == 0) do_read = 1; do_print = 1; break; } if (do_print && !do_read) { if ((args.pa_required & FLAG_HAS_OUTPUT_LOGFILE) == 0) { pmcstat_print_pmcs(); if (runstate == PMCSTAT_FINISHED && /* final newline */ (args.pa_flags & FLAG_DO_PRINT) == 0) (void) fprintf(args.pa_printfile, "\n"); } if (args.pa_flags & FLAG_DO_TOP) pmcstat_display_log(); do_print = 0; } } while (runstate != PMCSTAT_FINISHED); if ((args.pa_flags & FLAG_DO_TOP) && args.pa_toptty) { pmcstat_topexit(); args.pa_toptty = 0; } /* flush any pending log entries */ if (args.pa_flags & (FLAG_HAS_OUTPUT_LOGFILE | FLAG_HAS_PIPE)) pmc_close_logfile(); pmcstat_cleanup(); /* check if the driver lost any samples or events */ if (check_driver_stats) { if (pmc_get_driver_stats(&ds_end) < 0) err(EX_OSERR, "ERROR: Cannot retrieve driver statistics"); if (ds_start.pm_intr_bufferfull != ds_end.pm_intr_bufferfull && args.pa_verbosity > 0) warnx( "WARNING: sampling was paused at least %u time%s.\n" "Please consider tuning the \"kern.hwpmc.nsamples\" tunable.", ds_end.pm_intr_bufferfull - ds_start.pm_intr_bufferfull, ((ds_end.pm_intr_bufferfull - ds_start.pm_intr_bufferfull) != 1) ? "s" : "" ); if (ds_start.pm_buffer_requests_failed != ds_end.pm_buffer_requests_failed && args.pa_verbosity > 0) warnx( "WARNING: at least %u event%s were discarded while running.\n" "Please consider tuning the \"kern.hwpmc.nbuffers\" tunable.", ds_end.pm_buffer_requests_failed - ds_start.pm_buffer_requests_failed, ((ds_end.pm_buffer_requests_failed - ds_start.pm_buffer_requests_failed) != 1) ? "s" : "" ); } exit(EX_OK); } diff --git a/usr.sbin/pmcstat/pmcstat_log.c b/usr.sbin/pmcstat/pmcstat_log.c index cc3e9c49203f..5f88d274f393 100644 --- a/usr.sbin/pmcstat/pmcstat_log.c +++ b/usr.sbin/pmcstat/pmcstat_log.c @@ -1,749 +1,742 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2007, Joseph Koshy * Copyright (c) 2007 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by A. Joseph Koshy under * sponsorship from the FreeBSD Foundation and Google, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Transform a hwpmc(4) log into human readable form, and into * gprof(1) compatible profiles. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pmcstat.h" #include "pmcstat_log.h" #include "pmcstat_top.h" /* * PUBLIC INTERFACES * * pmcstat_initialize_logging() initialize this module, called first * pmcstat_shutdown_logging() orderly shutdown, called last * pmcstat_open_log() open an eventlog for processing * pmcstat_process_log() print/convert an event log * pmcstat_display_log() top mode display for the log * pmcstat_close_log() finish processing an event log * * IMPLEMENTATION NOTES * * We correlate each 'callchain' or 'sample' entry seen in the event * log back to an executable object in the system. Executable objects * include: * - program executables, * - shared libraries loaded by the runtime loader, * - dlopen()'ed objects loaded by the program, * - the runtime loader itself, * - the kernel and kernel modules. * * Each process that we know about is treated as a set of regions that * map to executable objects. Processes are described by * 'pmcstat_process' structures. Executable objects are tracked by * 'pmcstat_image' structures. The kernel and kernel modules are * common to all processes (they reside at the same virtual addresses * for all processes). Individual processes can have their text * segments and shared libraries loaded at process-specific locations. * * A given executable object can be in use by multiple processes * (e.g., libc.so) and loaded at a different address in each. * pmcstat_pcmap structures track per-image mappings. * * The sample log could have samples from multiple PMCs; we * generate one 'gmon.out' profile per PMC. * * IMPLEMENTATION OF GMON OUTPUT * * Each executable object gets one 'gmon.out' profile, per PMC in * use. Creation of 'gmon.out' profiles is done lazily. The * 'gmon.out' profiles generated for a given sampling PMC are * aggregates of all the samples for that particular executable * object. * * IMPLEMENTATION OF SYSTEM-WIDE CALLGRAPH OUTPUT * * Each active pmcid has its own callgraph structure, described by a * 'struct pmcstat_callgraph'. Given a process id and a list of pc * values, we map each pc value to a tuple (image, symbol), where * 'image' denotes an executable object and 'symbol' is the closest * symbol that precedes the pc value. Each pc value in the list is * also given a 'rank' that reflects its depth in the call stack. */ struct pmcstat_pmcs pmcstat_pmcs = LIST_HEAD_INITIALIZER(pmcstat_pmcs); /* * All image descriptors are kept in a hash table. */ struct pmcstat_image_hash_list pmcstat_image_hash[PMCSTAT_NHASH]; /* * All process descriptors are kept in a hash table. */ struct pmcstat_process_hash_list pmcstat_process_hash[PMCSTAT_NHASH]; struct pmcstat_stats pmcstat_stats; /* statistics */ static int ps_samples_period; /* samples count between top refresh. */ struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */ #include "pmcpl_gprof.h" #include "pmcpl_callgraph.h" #include "pmcpl_annotate.h" #include "pmcpl_annotate_cg.h" #include "pmcpl_calltree.h" static struct pmc_plugins plugins[] = { { .pl_name = "none", }, { .pl_name = "callgraph", .pl_init = pmcpl_cg_init, .pl_shutdown = pmcpl_cg_shutdown, .pl_process = pmcpl_cg_process, .pl_topkeypress = pmcpl_cg_topkeypress, .pl_topdisplay = pmcpl_cg_topdisplay }, { .pl_name = "gprof", .pl_shutdown = pmcpl_gmon_shutdown, .pl_process = pmcpl_gmon_process, .pl_initimage = pmcpl_gmon_initimage, .pl_shutdownimage = pmcpl_gmon_shutdownimage, .pl_newpmc = pmcpl_gmon_newpmc }, { .pl_name = "annotate", .pl_process = pmcpl_annotate_process }, { .pl_name = "calltree", .pl_configure = pmcpl_ct_configure, .pl_init = pmcpl_ct_init, .pl_shutdown = pmcpl_ct_shutdown, .pl_process = pmcpl_ct_process, .pl_topkeypress = pmcpl_ct_topkeypress, .pl_topdisplay = pmcpl_ct_topdisplay }, { .pl_name = "annotate_cg", .pl_process = pmcpl_annotate_cg_process }, { .pl_name = NULL } }; static int pmcstat_mergepmc; int pmcstat_pmcinfilter = 0; /* PMC filter for top mode. */ float pmcstat_threshold = 0.5; /* Cost filter for top mode. */ /* * Prototypes */ static void pmcstat_stats_reset(int _reset_global); /* * PMC count. */ int pmcstat_npmcs; /* * PMC Top mode pause state. */ static int pmcstat_pause; static void pmcstat_stats_reset(int reset_global) { struct pmcstat_pmcrecord *pr; /* Flush PMCs stats. */ LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) { pr->pr_samples = 0; pr->pr_dubious_frames = 0; } ps_samples_period = 0; /* Flush global stats. */ if (reset_global) bzero(&pmcstat_stats, sizeof(struct pmcstat_stats)); } /* * Resolve file name and line number for the given address. */ int pmcstat_image_addr2line(struct pmcstat_image *image, uintfptr_t addr, char *sourcefile, size_t sourcefile_len, unsigned *sourceline, char *funcname, size_t funcname_len) { static int addr2line_warn = 0; char *sep, cmdline[PATH_MAX], imagepath[PATH_MAX]; unsigned l; int fd; if (image->pi_addr2line == NULL) { /* Try default debug file location. */ snprintf(imagepath, sizeof(imagepath), "/usr/lib/debug/%s%s.debug", args.pa_fsroot, pmcstat_string_unintern(image->pi_fullpath)); fd = open(imagepath, O_RDONLY); if (fd < 0) { /* Old kernel symbol path. */ snprintf(imagepath, sizeof(imagepath), "%s%s.symbols", args.pa_fsroot, pmcstat_string_unintern(image->pi_fullpath)); fd = open(imagepath, O_RDONLY); if (fd < 0) { snprintf(imagepath, sizeof(imagepath), "%s%s", args.pa_fsroot, pmcstat_string_unintern( image->pi_fullpath)); } } if (fd >= 0) close(fd); /* * New addr2line support recursive inline function with -i * but the format does not add a marker when no more entries * are available. */ snprintf(cmdline, sizeof(cmdline), "addr2line -Cfe \"%s\"", imagepath); image->pi_addr2line = popen(cmdline, "r+"); if (image->pi_addr2line == NULL) { if (!addr2line_warn) { addr2line_warn = 1; warnx( "WARNING: addr2line is needed for source code information." ); } return (0); } } if (feof(image->pi_addr2line) || ferror(image->pi_addr2line)) { warnx("WARNING: addr2line pipe error"); pclose(image->pi_addr2line); image->pi_addr2line = NULL; return (0); } fprintf(image->pi_addr2line, "%p\n", (void *)addr); if (fgets(funcname, funcname_len, image->pi_addr2line) == NULL) { warnx("WARNING: addr2line function name read error"); return (0); } sep = strchr(funcname, '\n'); if (sep != NULL) *sep = '\0'; if (fgets(sourcefile, sourcefile_len, image->pi_addr2line) == NULL) { warnx("WARNING: addr2line source file read error"); return (0); } sep = strchr(sourcefile, ':'); if (sep == NULL) { warnx("WARNING: addr2line source line separator missing"); return (0); } *sep = '\0'; l = atoi(sep+1); if (l == 0) return (0); *sourceline = l; return (1); } /* * Given a pmcid in use, find its human-readable name. */ const char * pmcstat_pmcid_to_name(pmc_id_t pmcid) { struct pmcstat_pmcrecord *pr; LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) if (pr->pr_pmcid == pmcid) return (pmcstat_string_unintern(pr->pr_pmcname)); return NULL; } /* * Convert PMC index to name. */ const char * pmcstat_pmcindex_to_name(int pmcin) { struct pmcstat_pmcrecord *pr; LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) if (pr->pr_pmcin == pmcin) return pmcstat_string_unintern(pr->pr_pmcname); return NULL; } /* * Return PMC record with given index. */ struct pmcstat_pmcrecord * pmcstat_pmcindex_to_pmcr(int pmcin) { struct pmcstat_pmcrecord *pr; LIST_FOREACH(pr, &pmcstat_pmcs, pr_next) if (pr->pr_pmcin == pmcin) return pr; return NULL; } /* * Print log entries as text. */ static int pmcstat_print_log(void) { struct pmclog_ev ev; uint32_t npc; while (pmclog_read(args.pa_logparser, &ev) == 0) { assert(ev.pl_state == PMCLOG_OK); switch (ev.pl_type) { case PMCLOG_TYPE_CALLCHAIN: PMCSTAT_PRINT_ENTRY("callchain", "%d 0x%x %d %d %c", ev.pl_u.pl_cc.pl_pid, ev.pl_u.pl_cc.pl_pmcid, PMC_CALLCHAIN_CPUFLAGS_TO_CPU(ev.pl_u.pl_cc. \ pl_cpuflags), ev.pl_u.pl_cc.pl_npc, PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(ev.pl_u.pl_cc.\ pl_cpuflags) ? 'u' : 's'); for (npc = 0; npc < ev.pl_u.pl_cc.pl_npc; npc++) PMCSTAT_PRINT_ENTRY("...", "%p", (void *) ev.pl_u.pl_cc.pl_pc[npc]); break; case PMCLOG_TYPE_CLOSELOG: PMCSTAT_PRINT_ENTRY("closelog",); break; case PMCLOG_TYPE_DROPNOTIFY: PMCSTAT_PRINT_ENTRY("drop",); break; case PMCLOG_TYPE_INITIALIZE: PMCSTAT_PRINT_ENTRY("initlog","0x%x \"%s\"", ev.pl_u.pl_i.pl_version, pmc_name_of_cputype(ev.pl_u.pl_i.pl_arch)); if ((ev.pl_u.pl_i.pl_version & 0xFF000000) != PMC_VERSION_MAJOR << 24) warnx( "WARNING: Log version 0x%x != expected version 0x%x.", ev.pl_u.pl_i.pl_version, PMC_VERSION); break; case PMCLOG_TYPE_MAP_IN: PMCSTAT_PRINT_ENTRY("map-in","%d %p \"%s\"", ev.pl_u.pl_mi.pl_pid, (void *) ev.pl_u.pl_mi.pl_start, ev.pl_u.pl_mi.pl_pathname); break; case PMCLOG_TYPE_MAP_OUT: PMCSTAT_PRINT_ENTRY("map-out","%d %p %p", ev.pl_u.pl_mo.pl_pid, (void *) ev.pl_u.pl_mo.pl_start, (void *) ev.pl_u.pl_mo.pl_end); break; - case PMCLOG_TYPE_PCSAMPLE: - PMCSTAT_PRINT_ENTRY("sample","0x%x %d %p %c", - ev.pl_u.pl_s.pl_pmcid, - ev.pl_u.pl_s.pl_pid, - (void *) ev.pl_u.pl_s.pl_pc, - ev.pl_u.pl_s.pl_usermode ? 'u' : 's'); - break; case PMCLOG_TYPE_PMCALLOCATE: PMCSTAT_PRINT_ENTRY("allocate","0x%x \"%s\" 0x%x", ev.pl_u.pl_a.pl_pmcid, ev.pl_u.pl_a.pl_evname, ev.pl_u.pl_a.pl_flags); break; case PMCLOG_TYPE_PMCALLOCATEDYN: PMCSTAT_PRINT_ENTRY("allocatedyn","0x%x \"%s\" 0x%x", ev.pl_u.pl_ad.pl_pmcid, ev.pl_u.pl_ad.pl_evname, ev.pl_u.pl_ad.pl_flags); break; case PMCLOG_TYPE_PMCATTACH: PMCSTAT_PRINT_ENTRY("attach","0x%x %d \"%s\"", ev.pl_u.pl_t.pl_pmcid, ev.pl_u.pl_t.pl_pid, ev.pl_u.pl_t.pl_pathname); break; case PMCLOG_TYPE_PMCDETACH: PMCSTAT_PRINT_ENTRY("detach","0x%x %d", ev.pl_u.pl_d.pl_pmcid, ev.pl_u.pl_d.pl_pid); break; case PMCLOG_TYPE_PROCCSW: PMCSTAT_PRINT_ENTRY("cswval","0x%x %d %jd", ev.pl_u.pl_c.pl_pmcid, ev.pl_u.pl_c.pl_pid, ev.pl_u.pl_c.pl_value); break; case PMCLOG_TYPE_PROCEXEC: PMCSTAT_PRINT_ENTRY("exec","0x%x %d %p \"%s\"", ev.pl_u.pl_x.pl_pmcid, ev.pl_u.pl_x.pl_pid, (void *) ev.pl_u.pl_x.pl_entryaddr, ev.pl_u.pl_x.pl_pathname); break; case PMCLOG_TYPE_PROCEXIT: PMCSTAT_PRINT_ENTRY("exitval","0x%x %d %jd", ev.pl_u.pl_e.pl_pmcid, ev.pl_u.pl_e.pl_pid, ev.pl_u.pl_e.pl_value); break; case PMCLOG_TYPE_PROCFORK: PMCSTAT_PRINT_ENTRY("fork","%d %d", ev.pl_u.pl_f.pl_oldpid, ev.pl_u.pl_f.pl_newpid); break; case PMCLOG_TYPE_USERDATA: PMCSTAT_PRINT_ENTRY("userdata","0x%x", ev.pl_u.pl_u.pl_userdata); break; case PMCLOG_TYPE_SYSEXIT: PMCSTAT_PRINT_ENTRY("exit","%d", ev.pl_u.pl_se.pl_pid); break; default: fprintf(args.pa_printfile, "unknown event (type %d).\n", ev.pl_type); } } if (ev.pl_state == PMCLOG_EOF) return (PMCSTAT_FINISHED); else if (ev.pl_state == PMCLOG_REQUIRE_DATA) return (PMCSTAT_RUNNING); errx(EX_DATAERR, "ERROR: event parsing failed (record %jd, offset 0x%jx).", (uintmax_t) ev.pl_count + 1, ev.pl_offset); /*NOTREACHED*/ } /* * Public Interfaces. */ /* * Process a log file in offline analysis mode. */ int pmcstat_process_log(void) { /* * If analysis has not been asked for, just print the log to * the current output file. */ if (args.pa_flags & FLAG_DO_PRINT) return (pmcstat_print_log()); else return (pmcstat_analyze_log(&args, plugins, &pmcstat_stats, pmcstat_kernproc, pmcstat_mergepmc, &pmcstat_npmcs, &ps_samples_period)); } /* * Refresh top display. */ static void pmcstat_refresh_top(void) { int v_attrs; float v; char pmcname[40]; struct pmcstat_pmcrecord *pmcpr; /* If in pause mode do not refresh display. */ if (pmcstat_pause) return; /* Wait until PMC pop in the log. */ pmcpr = pmcstat_pmcindex_to_pmcr(pmcstat_pmcinfilter); if (pmcpr == NULL) return; /* Format PMC name. */ if (pmcstat_mergepmc) snprintf(pmcname, sizeof(pmcname), "[%s]", pmcstat_string_unintern(pmcpr->pr_pmcname)); else snprintf(pmcname, sizeof(pmcname), "%s.%d", pmcstat_string_unintern(pmcpr->pr_pmcname), pmcstat_pmcinfilter); /* Format samples count. */ if (ps_samples_period > 0) v = (pmcpr->pr_samples * 100.0) / ps_samples_period; else v = 0.; v_attrs = PMCSTAT_ATTRPERCENT(v); PMCSTAT_PRINTBEGIN(); PMCSTAT_PRINTW("PMC: %s Samples: %u ", pmcname, pmcpr->pr_samples); PMCSTAT_ATTRON(v_attrs); PMCSTAT_PRINTW("(%.1f%%) ", v); PMCSTAT_ATTROFF(v_attrs); PMCSTAT_PRINTW(", %u unresolved\n\n", pmcpr->pr_dubious_frames); if (plugins[args.pa_plugin].pl_topdisplay != NULL) plugins[args.pa_plugin].pl_topdisplay(); PMCSTAT_PRINTEND(); } /* * Find the next pmc index to display. */ static void pmcstat_changefilter(void) { int pmcin; struct pmcstat_pmcrecord *pmcr; /* * Find the next merge target. */ if (pmcstat_mergepmc) { pmcin = pmcstat_pmcinfilter; do { pmcr = pmcstat_pmcindex_to_pmcr(pmcstat_pmcinfilter); if (pmcr == NULL || pmcr == pmcr->pr_merge) break; pmcstat_pmcinfilter++; if (pmcstat_pmcinfilter >= pmcstat_npmcs) pmcstat_pmcinfilter = 0; } while (pmcstat_pmcinfilter != pmcin); } } /* * Top mode keypress. */ int pmcstat_keypress_log(void) { int c, ret = 0; WINDOW *w; w = newwin(1, 0, 1, 0); c = wgetch(w); wprintw(w, "Key: %c => ", c); switch (c) { case 'c': wprintw(w, "enter mode 'd' or 'a' => "); c = wgetch(w); if (c == 'd') { args.pa_topmode = PMCSTAT_TOP_DELTA; wprintw(w, "switching to delta mode"); } else { args.pa_topmode = PMCSTAT_TOP_ACCUM; wprintw(w, "switching to accumulation mode"); } break; case 'm': pmcstat_mergepmc = !pmcstat_mergepmc; /* * Changing merge state require data reset. */ if (plugins[args.pa_plugin].pl_shutdown != NULL) plugins[args.pa_plugin].pl_shutdown(NULL); pmcstat_stats_reset(0); if (plugins[args.pa_plugin].pl_init != NULL) plugins[args.pa_plugin].pl_init(); /* Update filter to be on a merge target. */ pmcstat_changefilter(); wprintw(w, "merge PMC %s", pmcstat_mergepmc ? "on" : "off"); break; case 'n': /* Close current plugin. */ if (plugins[args.pa_plugin].pl_shutdown != NULL) plugins[args.pa_plugin].pl_shutdown(NULL); /* Find next top display available. */ do { args.pa_plugin++; if (plugins[args.pa_plugin].pl_name == NULL) args.pa_plugin = 0; } while (plugins[args.pa_plugin].pl_topdisplay == NULL); /* Open new plugin. */ pmcstat_stats_reset(0); if (plugins[args.pa_plugin].pl_init != NULL) plugins[args.pa_plugin].pl_init(); wprintw(w, "switching to plugin %s", plugins[args.pa_plugin].pl_name); break; case 'p': pmcstat_pmcinfilter++; if (pmcstat_pmcinfilter >= pmcstat_npmcs) pmcstat_pmcinfilter = 0; pmcstat_changefilter(); wprintw(w, "switching to PMC %s.%d", pmcstat_pmcindex_to_name(pmcstat_pmcinfilter), pmcstat_pmcinfilter); break; case ' ': pmcstat_pause = !pmcstat_pause; if (pmcstat_pause) wprintw(w, "pause => press space again to continue"); break; case 'q': wprintw(w, "exiting..."); ret = 1; break; default: if (plugins[args.pa_plugin].pl_topkeypress != NULL) if (plugins[args.pa_plugin].pl_topkeypress(c, (void *)w)) ret = 1; } wrefresh(w); delwin(w); return ret; } /* * Top mode display. */ void pmcstat_display_log(void) { pmcstat_refresh_top(); /* Reset everythings if delta mode. */ if (args.pa_topmode == PMCSTAT_TOP_DELTA) { if (plugins[args.pa_plugin].pl_shutdown != NULL) plugins[args.pa_plugin].pl_shutdown(NULL); pmcstat_stats_reset(0); if (plugins[args.pa_plugin].pl_init != NULL) plugins[args.pa_plugin].pl_init(); } } /* * Configure a plugins. */ void pmcstat_pluginconfigure_log(char *opt) { if (strncmp(opt, "threshold=", 10) == 0) { pmcstat_threshold = atof(opt+10); } else { if (plugins[args.pa_plugin].pl_configure != NULL) { if (!plugins[args.pa_plugin].pl_configure(opt)) err(EX_USAGE, "ERROR: unknown option <%s>.", opt); } } } void pmcstat_log_shutdown_logging(void) { pmcstat_shutdown_logging(&args, plugins, &pmcstat_stats); } void pmcstat_log_initialize_logging(void) { pmcstat_initialize_logging(&pmcstat_kernproc, &args, plugins, &pmcstat_npmcs, &pmcstat_mergepmc); }