diff options
Diffstat (limited to 'libpp')
41 files changed, 0 insertions, 7024 deletions
diff --git a/libpp/Makefile.am b/libpp/Makefile.am deleted file mode 100644 index 07a7fdd..0000000 --- a/libpp/Makefile.am +++ /dev/null @@ -1,52 +0,0 @@ -AM_CPPFLAGS = \ - -I ${top_srcdir}/libop \ - -I ${top_srcdir}/libutil \ - -I ${top_srcdir}/libdb \ - -I ${top_srcdir}/libopt++ \ - -I ${top_srcdir}/libutil++ \ - -I ${top_srcdir}/libop++ \ - -I ${top_srcdir}/libregex - -AM_CXXFLAGS = @OP_CXXFLAGS@ - -noinst_LIBRARIES = libpp.a -libpp_a_SOURCES = \ - arrange_profiles.cpp \ - arrange_profiles.h \ - callgraph_container.h \ - callgraph_container.cpp \ - diff_container.cpp \ - diff_container.h \ - filename_spec.cpp \ - filename_spec.h \ - format_flags.h \ - format_output.cpp \ - format_output.h \ - image_errors.h \ - image_errors.cpp \ - locate_images.cpp \ - locate_images.h \ - name_storage.cpp \ - name_storage.h \ - op_header.cpp \ - op_header.h \ - symbol.cpp \ - symbol.h \ - parse_filename.cpp \ - parse_filename.h \ - populate.h \ - populate.cpp \ - profile.cpp \ - profile.h \ - profile_container.cpp \ - profile_container.h \ - profile_spec.cpp \ - profile_spec.h \ - sample_container.cpp \ - sample_container.h \ - symbol_container.cpp \ - symbol_container.h \ - symbol_functors.cpp \ - symbol_functors.h \ - symbol_sort.cpp \ - symbol_sort.h diff --git a/libpp/Makefile.in b/libpp/Makefile.in deleted file mode 100644 index ffbb3cf..0000000 --- a/libpp/Makefile.in +++ /dev/null @@ -1,513 +0,0 @@ -# Makefile.in generated by automake 1.9.5 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005 Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -SOURCES = $(libpp_a_SOURCES) - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -top_builddir = .. -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -INSTALL = @INSTALL@ -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -subdir = libpp -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/binutils.m4 \ - $(top_srcdir)/m4/builtinexpect.m4 \ - $(top_srcdir)/m4/compileroption.m4 \ - $(top_srcdir)/m4/configmodule.m4 \ - $(top_srcdir)/m4/copyifchange.m4 $(top_srcdir)/m4/docbook.m4 \ - $(top_srcdir)/m4/extradirs.m4 $(top_srcdir)/m4/findkernel.m4 \ - $(top_srcdir)/m4/kerneloption.m4 \ - $(top_srcdir)/m4/kernelversion.m4 \ - $(top_srcdir)/m4/mallocattribute.m4 \ - $(top_srcdir)/m4/poptconst.m4 \ - $(top_srcdir)/m4/precompiledheader.m4 $(top_srcdir)/m4/qt.m4 \ - $(top_srcdir)/m4/resultyn.m4 $(top_srcdir)/m4/sstream.m4 \ - $(top_srcdir)/m4/typedef.m4 $(top_srcdir)/configure.in -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -LIBRARIES = $(noinst_LIBRARIES) -AR = ar -ARFLAGS = cru -libpp_a_AR = $(AR) $(ARFLAGS) -libpp_a_LIBADD = -am_libpp_a_OBJECTS = arrange_profiles.$(OBJEXT) \ - callgraph_container.$(OBJEXT) diff_container.$(OBJEXT) \ - filename_spec.$(OBJEXT) format_output.$(OBJEXT) \ - image_errors.$(OBJEXT) locate_images.$(OBJEXT) \ - name_storage.$(OBJEXT) op_header.$(OBJEXT) symbol.$(OBJEXT) \ - parse_filename.$(OBJEXT) populate.$(OBJEXT) profile.$(OBJEXT) \ - profile_container.$(OBJEXT) profile_spec.$(OBJEXT) \ - sample_container.$(OBJEXT) symbol_container.$(OBJEXT) \ - symbol_functors.$(OBJEXT) symbol_sort.$(OBJEXT) -libpp_a_OBJECTS = $(am_libpp_a_OBJECTS) -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -CXXLD = $(CXX) -CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ - -o $@ -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -SOURCES = $(libpp_a_SOURCES) -DIST_SOURCES = $(libpp_a_SOURCES) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMDEP_FALSE = @AMDEP_FALSE@ -AMDEP_TRUE = @AMDEP_TRUE@ -AMTAR = @AMTAR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BFD_LIBS = @BFD_LIBS@ -CAT_ENTRY_END = @CAT_ENTRY_END@ -CAT_ENTRY_START = @CAT_ENTRY_START@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DATE = @DATE@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DOCBOOK_ROOT = @DOCBOOK_ROOT@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -EXTRA_CFLAGS_MODULE = @EXTRA_CFLAGS_MODULE@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -KINC = @KINC@ -KSRC = @KSRC@ -KVERS = @KVERS@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBERTY_LIBS = @LIBERTY_LIBS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MOC = @MOC@ -MODINSTALLDIR = @MODINSTALLDIR@ -OBJEXT = @OBJEXT@ -OPROFILE_DIR = @OPROFILE_DIR@ -OPROFILE_MODULE_ARCH = @OPROFILE_MODULE_ARCH@ -OP_CFLAGS = @OP_CFLAGS@ -OP_CXXFLAGS = @OP_CXXFLAGS@ -OP_DOCDIR = @OP_DOCDIR@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -POPT_LIBS = @POPT_LIBS@ -PTRDIFF_T_TYPE = @PTRDIFF_T_TYPE@ -QT_INCLUDES = @QT_INCLUDES@ -QT_LDFLAGS = @QT_LDFLAGS@ -QT_LIB = @QT_LIB@ -QT_VERSION = @QT_VERSION@ -RANLIB = @RANLIB@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -SIZE_T_TYPE = @SIZE_T_TYPE@ -STRIP = @STRIP@ -UIC = @UIC@ -VERSION = @VERSION@ -XML_CATALOG = @XML_CATALOG@ -XSLTPROC = @XSLTPROC@ -XSLTPROC_FLAGS = @XSLTPROC_FLAGS@ -X_CFLAGS = @X_CFLAGS@ -X_EXTRA_LIBS = @X_EXTRA_LIBS@ -X_LIBS = @X_LIBS@ -X_PRE_LIBS = @X_PRE_LIBS@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_RANLIB = @ac_ct_RANLIB@ -ac_ct_STRIP = @ac_ct_STRIP@ -am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ -am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ -am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ -am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build_alias = @build_alias@ -datadir = @datadir@ -enable_abi_FALSE = @enable_abi_FALSE@ -enable_abi_TRUE = @enable_abi_TRUE@ -exec_prefix = @exec_prefix@ -have_qt_FALSE = @have_qt_FALSE@ -have_qt_TRUE = @have_qt_TRUE@ -have_xsltproc_FALSE = @have_xsltproc_FALSE@ -have_xsltproc_TRUE = @have_xsltproc_TRUE@ -host_alias = @host_alias@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -kernel_support_FALSE = @kernel_support_FALSE@ -kernel_support_TRUE = @kernel_support_TRUE@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -topdir = @topdir@ -AM_CPPFLAGS = \ - -I ${top_srcdir}/libop \ - -I ${top_srcdir}/libutil \ - -I ${top_srcdir}/libdb \ - -I ${top_srcdir}/libopt++ \ - -I ${top_srcdir}/libutil++ \ - -I ${top_srcdir}/libop++ \ - -I ${top_srcdir}/libregex - -AM_CXXFLAGS = @OP_CXXFLAGS@ -noinst_LIBRARIES = libpp.a -libpp_a_SOURCES = \ - arrange_profiles.cpp \ - arrange_profiles.h \ - callgraph_container.h \ - callgraph_container.cpp \ - diff_container.cpp \ - diff_container.h \ - filename_spec.cpp \ - filename_spec.h \ - format_flags.h \ - format_output.cpp \ - format_output.h \ - image_errors.h \ - image_errors.cpp \ - locate_images.cpp \ - locate_images.h \ - name_storage.cpp \ - name_storage.h \ - op_header.cpp \ - op_header.h \ - symbol.cpp \ - symbol.h \ - parse_filename.cpp \ - parse_filename.h \ - populate.h \ - populate.cpp \ - profile.cpp \ - profile.h \ - profile_container.cpp \ - profile_container.h \ - profile_spec.cpp \ - profile_spec.h \ - sample_container.cpp \ - sample_container.h \ - symbol_container.cpp \ - symbol_container.h \ - symbol_functors.cpp \ - symbol_functors.h \ - symbol_sort.cpp \ - symbol_sort.h - -all: all-am - -.SUFFIXES: -.SUFFIXES: .cpp .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libpp/Makefile'; \ - cd $(top_srcdir) && \ - $(AUTOMAKE) --foreign libpp/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -clean-noinstLIBRARIES: - -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) -libpp.a: $(libpp_a_OBJECTS) $(libpp_a_DEPENDENCIES) - -rm -f libpp.a - $(libpp_a_AR) libpp.a $(libpp_a_OBJECTS) $(libpp_a_LIBADD) - $(RANLIB) libpp.a - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arrange_profiles.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callgraph_container.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/diff_container.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filename_spec.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format_output.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/image_errors.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/locate_images.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/name_storage.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/op_header.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse_filename.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/populate.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profile.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profile_container.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profile_spec.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sample_container.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symbol.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symbol_container.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symbol_functors.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symbol_sort.Po@am__quote@ - -.cpp.o: -@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ -@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< - -.cpp.obj: -@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ -@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` -uninstall-info-am: - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$tags $$unique; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - tags=; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ - test -z "$(CTAGS_ARGS)$$tags$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$tags $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && cd $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) $$here - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ - list='$(DISTFILES)'; for file in $$list; do \ - case $$file in \ - $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ - $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ - esac; \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test "$$dir" != "$$file" && test "$$dir" != "."; then \ - dir="/$$dir"; \ - $(mkdir_p) "$(distdir)$$dir"; \ - else \ - dir=''; \ - fi; \ - if test -d $$d/$$file; then \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ - fi; \ - cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ - else \ - test -f $(distdir)/$$file \ - || cp -p $$d/$$file $(distdir)/$$file \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LIBRARIES) -installdirs: -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -info: info-am - -info-am: - -install-data-am: - -install-exec-am: - -install-info: install-info-am - -install-man: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-info-am - -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ - clean-noinstLIBRARIES ctags distclean distclean-compile \ - distclean-generic distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-exec install-exec-am install-info \ - install-info-am install-man install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ - uninstall-am uninstall-info-am - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/libpp/arrange_profiles.cpp b/libpp/arrange_profiles.cpp deleted file mode 100644 index 4b21eb6..0000000 --- a/libpp/arrange_profiles.cpp +++ /dev/null @@ -1,776 +0,0 @@ -/** - * @file arrange_profiles.cpp - * Classify and process a list of candidate sample files - * into merged sets and classes. - * - * @remark Copyright 2003 OProfile authors - * @remark Read the file COPYING - * - * @author John Levon - */ - -#include <algorithm> -#include <cstdlib> -#include <iostream> -#include <iterator> -#include <map> -#include <set> - -#include "string_manip.h" -#include "op_header.h" -#include "op_exception.h" - -#include "arrange_profiles.h" -#include "parse_filename.h" -#include "locate_images.h" - -using namespace std; - -namespace { - -int numeric_compare(string const & lhs, string const & rhs) -{ - if (lhs == "all" && rhs == "all") - return 0; - // we choose an order arbitrarily - if (lhs == "all") - return 1; - if (rhs == "all") - return -1; - unsigned int lhsval = op_lexical_cast<unsigned int>(lhs); - unsigned int rhsval = op_lexical_cast<unsigned int>(rhs); - if (lhsval == rhsval) - return 0; - if (lhsval < rhsval) - return -1; - return 1; -} - -} // anonymous namespace - - -// global to fix some C++ obscure corner case. -bool operator<(profile_class const & lhs, - profile_class const & rhs) -{ - profile_template const & lt = lhs.ptemplate; - profile_template const & rt = rhs.ptemplate; - - int comp = numeric_compare(lt.cpu, rt.cpu); - if (comp) - return comp < 0; - - comp = numeric_compare(lt.tgid, rt.tgid); - if (comp) - return comp < 0; - - comp = numeric_compare(lt.tid, rt.tid); - if (comp) - return comp < 0; - - comp = numeric_compare(lt.unitmask, rt.unitmask); - if (comp) - return comp < 0; - - if (lt.event == rt.event) - return lt.count < rt.count; - return lt.event < rt.event; -} - -namespace { - -struct axis_t { - string name; - string suggestion; -} axes[AXIS_MAX] = { - { "event", "specify event:, count: or unitmask: (see also --merge=unitmask)" }, - { "tgid", "specify tgid: or --merge tgid" }, - { "tid", "specify tid: or --merge tid" }, - { "cpu", "specify cpu: or --merge cpu" }, -}; - - -bool profile_classes::matches(profile_classes const & classes) -{ - if (v.size() != classes.v.size()) - return false; - - axis_types const axis2 = classes.axis; - - switch (axis) { - case AXIS_EVENT: - break; - case AXIS_TGID: - case AXIS_TID: - return axis2 == AXIS_TID || axis2 == AXIS_TGID; - case AXIS_CPU: - return axis2 == AXIS_CPU; - case AXIS_MAX: - return false; - } - - // check that the events match (same event, count) - - vector<profile_class>::const_iterator it1 = v.begin(); - vector<profile_class>::const_iterator end1 = v.end(); - vector<profile_class>::const_iterator it2 = classes.v.begin(); - - while (it1 != end1) { - if (it1->ptemplate.event != it2->ptemplate.event) - return false; - if (it1->ptemplate.count != it2->ptemplate.count) - return false; - // differing unit mask is considered comparable - ++it1; - ++it2; - } - - return true; -} - - -/// We have more than one axis of classification, tell the user. -void report_error(profile_classes const & classes, axis_types newaxis) -{ - string str = "Already displaying results for parameter "; - str += axes[classes.axis].name; - str += " with values:\n"; - vector<profile_class>::const_iterator it = classes.v.begin(); - vector<profile_class>::const_iterator const end = classes.v.end(); - - // We show error for the first conflicting axis but on this - // axis we can get only a few different it->name, we display only - // these different name. - set <string> name_seen; - size_t i = 5; - for (; it != end && i; ++it) { - if (name_seen.find(it->name) == name_seen.end()) { - name_seen.insert(it->name); - str += it->name + ","; - --i; - } - } - - if (!i) { - str += " and "; - str += op_lexical_cast<string>(classes.v.size() - 5); - str += " more,"; - } - - str += "\nwhich conflicts with parameter "; - str += axes[newaxis].name += ".\n"; - str += "Suggestion: "; - str += axes[classes.axis].suggestion; - throw op_fatal_error(str); -} - - -/** - * check that two different axes are OK - this is only - * allowed if they are TGID,TID and for each class, - * tid == tgid - */ -bool allow_axes(profile_classes const & classes, axis_types newaxis) -{ - // No previous axis - OK - if (classes.axis == AXIS_MAX) - return true; - - if (classes.axis != AXIS_TID && classes.axis != AXIS_TGID) - return false; - - if (newaxis != AXIS_TID && newaxis != AXIS_TGID) - return false; - - vector<profile_class>::const_iterator it = classes.v.begin(); - vector<profile_class>::const_iterator const end = classes.v.end(); - - for (; it != end; ++it) { - if (it->ptemplate.tgid != it->ptemplate.tid) - return false; - } - - return true; -} - - -/// find the first sample file header in the class -opd_header const get_first_header(profile_class const & pclass) -{ - profile_set const & profile = *(pclass.profiles.begin()); - - string file; - - // could be only one main app, with no samples for the main image - if (profile.files.empty()) { - profile_dep_set const & dep = *(profile.deps.begin()); - list<profile_sample_files> const & files = dep.files; - profile_sample_files const & sample_files = *(files.begin()); - if (!sample_files.sample_filename.empty()) - file = sample_files.sample_filename; - else - file = *sample_files.cg_files.begin(); - } else { - profile_sample_files const & sample_files - = *(profile.files.begin()); - if (!sample_files.sample_filename.empty()) - file = sample_files.sample_filename; - else - file = *sample_files.cg_files.begin(); - } - - return read_header(file); -} - -/// merge sample file header in the profile_sample_files -void merge_header(profile_sample_files const & files, opd_header & header) -{ - if (!files.sample_filename.empty()) { - opd_header const temp = read_header(files.sample_filename); - header.ctr_um |= temp.ctr_um; - } - - list<string>::const_iterator it = files.cg_files.begin(); - list<string>::const_iterator const end = files.cg_files.end(); - for ( ; it != end; ++it) { - opd_header const temp = read_header(*it); - header.ctr_um |= temp.ctr_um; - } -} - -/// merge sample file header in the class -opd_header const get_header(profile_class const & pclass, - merge_option const & merge_by) -{ - opd_header header = get_first_header(pclass); - - if (!merge_by.unitmask) - return header; - - profile_set const & profile = *(pclass.profiles.begin()); - - typedef list<profile_sample_files>::const_iterator citerator; - - citerator it = profile.files.begin(); - citerator const end = profile.files.end(); - for ( ; it != end; ++it) { - merge_header(*it, header); - } - - list<profile_dep_set>::const_iterator dep_it = profile.deps.begin(); - list<profile_dep_set>::const_iterator dep_end = profile.deps.end(); - for ( ; dep_it != dep_end; ++dep_it) { - citerator it = dep_it->files.begin(); - citerator const end = dep_it->files.end(); - for ( ; it != end; ++it) { - merge_header(*it, header); - } - } - - return header; -} - - -/// Give human-readable names to each class. -void name_classes(profile_classes & classes, merge_option const & merge_by) -{ - opd_header header = get_header(classes.v[0], merge_by); - - classes.event = describe_header(header); - classes.cpuinfo = describe_cpu(header); - - // If we're splitting on event anyway, clear out the - // global event name - if (classes.axis == AXIS_EVENT) - classes.event.erase(); - - vector<profile_class>::iterator it = classes.v.begin(); - vector<profile_class>::iterator const end = classes.v.end(); - - for (; it != end; ++it) { - it->name = axes[classes.axis].name + ":"; - switch (classes.axis) { - case AXIS_EVENT: - it->name = it->ptemplate.event - + ":" + it->ptemplate.count; - header = get_header(*it, merge_by); - it->longname = describe_header(header); - break; - case AXIS_TGID: - it->name += it->ptemplate.tgid; - it->longname = "Processes with a thread group ID of "; - it->longname += it->ptemplate.tgid; - break; - case AXIS_TID: - it->name += it->ptemplate.tid; - it->longname = "Processes with a thread ID of "; - it->longname += it->ptemplate.tid; - break; - case AXIS_CPU: - it->name += it->ptemplate.cpu; - it->longname = "Samples on CPU " + it->ptemplate.cpu; - break; - case AXIS_MAX:; - } - } -} - - -/** - * Name and verify classes. - */ -void identify_classes(profile_classes & classes, - merge_option const & merge_by) -{ - profile_template & ptemplate = classes.v[0].ptemplate; - bool changed[AXIS_MAX] = { false, }; - - vector<profile_class>::iterator it = classes.v.begin(); - ++it; - vector<profile_class>::iterator end = classes.v.end(); - - // only one class, name it after the event - if (it == end) { - changed[AXIS_EVENT] = true; - } - - for (; it != end; ++it) { - if (it->ptemplate.event != ptemplate.event - || it->ptemplate.count != ptemplate.count - // unit mask are mergeable - || (!merge_by.unitmask - && it->ptemplate.unitmask != ptemplate.unitmask)) - changed[AXIS_EVENT] = true; - - // we need the merge checks here because each - // template is filled in from the first non - // matching profile, so just because they differ - // doesn't mean it's the axis we care about - if (!merge_by.tgid && it->ptemplate.tgid != ptemplate.tgid) - changed[AXIS_TGID] = true; - - if (!merge_by.tid && it->ptemplate.tid != ptemplate.tid) - changed[AXIS_TID] = true; - - if (!merge_by.cpu && it->ptemplate.cpu != ptemplate.cpu) - changed[AXIS_CPU] = true; - } - - classes.axis = AXIS_MAX; - - for (size_t i = 0; i < AXIS_MAX; ++i) { - if (!changed[i]) - continue; - - if (!allow_axes(classes, axis_types(i))) - report_error(classes, axis_types(i)); - classes.axis = axis_types(i); - /* do this early for report_error */ - name_classes(classes, merge_by); - } - - if (classes.axis == AXIS_MAX) { - cerr << "Internal error - no equivalence class axis" << endl; - abort(); - } -} - - -/// construct a class template from a profile -profile_template const -template_from_profile(parsed_filename const & parsed, - merge_option const & merge_by) -{ - profile_template ptemplate; - - ptemplate.event = parsed.event; - ptemplate.count = parsed.count; - - if (!merge_by.unitmask) - ptemplate.unitmask = parsed.unitmask; - if (!merge_by.tgid) - ptemplate.tgid = parsed.tgid; - if (!merge_by.tid) - ptemplate.tid = parsed.tid; - if (!merge_by.cpu) - ptemplate.cpu = parsed.cpu; - return ptemplate; -} - - -/** - * Find a matching class the sample file could go in, or generate - * a new class if needed. - * This is the heart of the merging and classification process. - * The returned value is non-const reference but the ptemplate member - * must be considered as const - */ -profile_class & find_class(set<profile_class> & classes, - parsed_filename const & parsed, - merge_option const & merge_by) -{ - profile_class cls; - cls.ptemplate = template_from_profile(parsed, merge_by); - - pair<set<profile_class>::iterator, bool> ret = classes.insert(cls); - - return const_cast<profile_class &>(*ret.first); -} - -/** - * Sanity check : we can't overwrite sample_filename, if we abort here it means - * we fail to detect that parsed sample filename for two distinct samples - * filename must go in two distinct profile_sample_files. This assumption is - * false for callgraph samples files so this function is only called for non cg - * files. - */ -void sanitize_profile_sample_files(profile_sample_files const & sample_files, - parsed_filename const & parsed) -{ - // We can't allow to overwrite sample_filename. - if (!sample_files.sample_filename.empty()) { - ostringstream out; - out << "sanitize_profile_sample_files(): sample file " - << "parsed twice ?\nsample_filename:\n" - << sample_files.sample_filename << endl - << parsed << endl; - throw op_fatal_error(out.str()); - } -} - - -/** - * Add a sample filename (either cg or non cg files) to this profile. - */ -void -add_to_profile_sample_files(profile_sample_files & sample_files, - parsed_filename const & parsed) -{ - if (parsed.cg_image.empty()) { - // We can't allow to overwrite sample_filename. - sanitize_profile_sample_files(sample_files, parsed); - - sample_files.sample_filename = parsed.filename; - } else { - sample_files.cg_files.push_back(parsed.filename); - } -} - - -/** - * we need to fix cg filename: a callgraph filename can occur before the binary - * non callgraph samples filename occur so we must search. - */ -profile_sample_files & -find_profile_sample_files(list<profile_sample_files> & files, - parsed_filename const & parsed) -{ - list<profile_sample_files>::iterator it; - list<profile_sample_files>::iterator const end = files.end(); - for (it = files.begin(); it != end; ++it) { - if (!it->sample_filename.empty()) { - parsed_filename psample_filename = - parse_filename(it->sample_filename); - if (psample_filename.lib_image == parsed.lib_image && - psample_filename.image == parsed.image && - psample_filename.profile_spec_equal(parsed)) - return *it; - } - - list<string>::const_iterator cit; - list<string>::const_iterator const cend = it->cg_files.end(); - for (cit = it->cg_files.begin(); cit != cend; ++cit) { - parsed_filename pcg_filename = parse_filename(*cit); - if (pcg_filename.lib_image == parsed.lib_image && - pcg_filename.image == parsed.image && - pcg_filename.profile_spec_equal(parsed)) - return *it; - } - } - - // not found, create a new one - files.push_back(profile_sample_files()); - return files.back(); -} - - -/** - * Add a profile to particular profile set. If the new profile is - * a dependent image, it gets added to the dep list, or just placed - * on the normal list of profiles otherwise. - */ -void -add_to_profile_set(profile_set & set, parsed_filename const & parsed, bool merge_by_lib) -{ - if (parsed.image == parsed.lib_image && !merge_by_lib) { - profile_sample_files & sample_files = - find_profile_sample_files(set.files, parsed); - add_to_profile_sample_files(sample_files, parsed); - return; - } - - list<profile_dep_set>::iterator it = set.deps.begin(); - list<profile_dep_set>::iterator const end = set.deps.end(); - - for (; it != end; ++it) { - if (it->lib_image == parsed.lib_image && !merge_by_lib) { - profile_sample_files & sample_files = - find_profile_sample_files(it->files, parsed); - add_to_profile_sample_files(sample_files, parsed); - return; - } - } - - profile_dep_set depset; - depset.lib_image = parsed.lib_image; - profile_sample_files & sample_files = - find_profile_sample_files(depset.files, parsed); - add_to_profile_sample_files(sample_files, parsed); - set.deps.push_back(depset); -} - - -/** - * Add a profile to a particular equivalence class. The previous matching - * will have ensured the profile "fits", so now it's just a matter of - * finding which sample file list it needs to go on. - */ -void add_profile(profile_class & pclass, parsed_filename const & parsed, bool merge_by_lib) -{ - list<profile_set>::iterator it = pclass.profiles.begin(); - list<profile_set>::iterator const end = pclass.profiles.end(); - - for (; it != end; ++it) { - if (it->image == parsed.image) { - add_to_profile_set(*it, parsed, merge_by_lib); - return; - } - } - - profile_set set; - set.image = parsed.image; - add_to_profile_set(set, parsed, merge_by_lib); - pclass.profiles.push_back(set); -} - -} // anon namespace - - -profile_classes const -arrange_profiles(list<string> const & files, merge_option const & merge_by) -{ - set<profile_class> temp_classes; - - list<string>::const_iterator it = files.begin(); - list<string>::const_iterator const end = files.end(); - - for (; it != end; ++it) { - parsed_filename parsed = parse_filename(*it); - - if (parsed.lib_image.empty()) - parsed.lib_image = parsed.image; - - // This simplifies the add of the profile later, - // if we're lib-merging, then the app_image cannot - // matter. After this, any non-dependent has - // image == lib_image - if (merge_by.lib) - parsed.image = parsed.lib_image; - - profile_class & pclass = - find_class(temp_classes, parsed, merge_by); - add_profile(pclass, parsed, merge_by.lib); - } - - profile_classes classes; - copy(temp_classes.begin(), temp_classes.end(), - back_inserter(classes.v)); - - if (classes.v.empty()) - return classes; - - // sort by template for nicely ordered columns - stable_sort(classes.v.begin(), classes.v.end()); - - // name and check - identify_classes(classes, merge_by); - - return classes; -} - - -ostream & operator<<(ostream & out, profile_sample_files const & sample_files) -{ - out << "sample_filename: " << sample_files.sample_filename << endl; - out << "callgraph filenames:\n"; - copy(sample_files.cg_files.begin(), sample_files.cg_files.end(), - ostream_iterator<string>(out, "\n")); - return out; -} - -ostream & operator<<(ostream & out, profile_dep_set const & pdep_set) -{ - out << "lib_image: " << pdep_set.lib_image << endl; - - list<profile_sample_files>::const_iterator it; - list<profile_sample_files>::const_iterator const end = - pdep_set.files.end(); - size_t i = 0; - for (it = pdep_set.files.begin(); it != end; ++it) - out << "profile_sample_files #" << i++ << ":\n" << *it; - - return out; -} - -ostream & operator<<(ostream & out, profile_set const & pset) -{ - out << "image: " << pset.image << endl; - - list<profile_sample_files>::const_iterator it; - list<profile_sample_files>::const_iterator const end = - pset.files.end(); - size_t i = 0; - for (it = pset.files.begin(); it != end; ++it) - out << "profile_sample_files #" << i++ << ":\n" << *it; - - list<profile_dep_set>::const_iterator cit; - list<profile_dep_set>::const_iterator const cend = pset.deps.end(); - i = 0; - for (cit = pset.deps.begin(); cit != cend; ++cit) - out << "profile_dep_set #" << i++ << ":\n" << *cit; - - return out; -} - -ostream & operator<<(ostream & out, profile_template const & ptemplate) -{ - out << "event: " << ptemplate.event << endl - << "count: " << ptemplate.count << endl - << "unitmask: " << ptemplate.unitmask << endl - << "tgid: " << ptemplate.tgid << endl - << "tid: " << ptemplate.tid << endl - << "cpu: " << ptemplate.cpu << endl; - return out; -} - -ostream & operator<<(ostream & out, profile_class const & pclass) -{ - out << "name: " << pclass.name << endl - << "longname: " << pclass.longname << endl - << "ptemplate:\n" << pclass.ptemplate; - - size_t i = 0; - list<profile_set>::const_iterator it; - list<profile_set>::const_iterator const end = pclass.profiles.end(); - for (it = pclass.profiles.begin(); it != end; ++it) - out << "profiles_set #" << i++ << ":\n" << *it; - - return out; -} - -ostream & operator<<(ostream & out, profile_classes const & pclasses) -{ - out << "event: " << pclasses.event << endl - << "cpuinfo: " << pclasses.cpuinfo << endl; - - for (size_t i = 0; i < pclasses.v.size(); ++i) - out << "class #" << i << ":\n" << pclasses.v[i]; - - return out; -} - - -namespace { - -/// add the files to group of image sets -void add_to_group(image_group_set & group, string const & app_image, - list<profile_sample_files> const & files) -{ - image_set set; - set.app_image = app_image; - set.files = files; - group.push_back(set); -} - - -typedef map<string, inverted_profile> app_map_t; - - -inverted_profile & -get_iprofile(app_map_t & app_map, string const & image, size_t nr_classes) -{ - app_map_t::iterator ait = app_map.find(image); - if (ait != app_map.end()) - return ait->second; - - inverted_profile ip; - ip.image = image; - ip.groups.resize(nr_classes); - app_map[image] = ip; - return app_map[image]; -} - - -/// Pull out all the images, removing any we can't access. -void -verify_and_fill(string archive_path, app_map_t & app_map, - list<inverted_profile> & plist, extra_images const & extra) -{ - app_map_t::iterator it = app_map.begin(); - app_map_t::iterator const end = app_map.end(); - - for (; it != end; ++it) { - plist.push_back(it->second); - inverted_profile & ip = plist.back(); - ip.image = find_image_path(archive_path, ip.image, extra, - ip.error); - } -} - -} // anon namespace - - -list<inverted_profile> const -invert_profiles(string archive_path, profile_classes const & classes, - extra_images const & extra) -{ - app_map_t app_map; - - size_t nr_classes = classes.v.size(); - - for (size_t i = 0; i < nr_classes; ++i) { - list<profile_set>::const_iterator pit - = classes.v[i].profiles.begin(); - list<profile_set>::const_iterator pend - = classes.v[i].profiles.end(); - - for (; pit != pend; ++pit) { - // files can be empty if samples for a lib image - // but none for the main image. Deal with it here - // rather than later. - if (pit->files.size()) { - inverted_profile & ip = get_iprofile(app_map, - pit->image, nr_classes); - add_to_group(ip.groups[i], pit->image, pit->files); - } - - list<profile_dep_set>::const_iterator dit - = pit->deps.begin(); - list<profile_dep_set>::const_iterator const dend - = pit->deps.end(); - - for (; dit != dend; ++dit) { - inverted_profile & ip = get_iprofile(app_map, - dit->lib_image, nr_classes); - add_to_group(ip.groups[i], pit->image, - dit->files); - } - } - } - - list<inverted_profile> inverted_list; - - verify_and_fill(archive_path, app_map, inverted_list, extra); - - return inverted_list; -} diff --git a/libpp/arrange_profiles.h b/libpp/arrange_profiles.h deleted file mode 100644 index 3f71305..0000000 --- a/libpp/arrange_profiles.h +++ /dev/null @@ -1,245 +0,0 @@ -/** - * @file arrange_profiles.h - * Classify and process a list of candidate sample files - * into merged sets and classes. - * - * @remark Copyright 2003 OProfile authors - * @remark Read the file COPYING - * - * @author John Levon - */ - -#ifndef ARRANGE_PROFILES_H -#define ARRANGE_PROFILES_H - -#include <string> -#include <list> -#include <vector> -#include <iosfwd> - -#include "image_errors.h" - -/** - * store merging options options used to classify profiles - */ -struct merge_option { - bool cpu; - bool lib; - bool tid; - bool tgid; - bool unitmask; -}; - - -/** - * This describes which parameters are set for each - * equivalence class. - */ -struct profile_template { - std::string event; - std::string count; - std::string unitmask; - std::string tgid; - std::string tid; - std::string cpu; -}; - - -/** - * A samples filename + its associated callgraph sample filename. - */ -struct profile_sample_files { - /** - * This member can be empty since it is possible to get callgraph - * w/o any samples to the binary. e.g an application which defer all - * works to shared library but if arrange_profiles receive a sample - * file list filtered from cg file sample_filename can't be empty - */ - std::string sample_filename; - /** - * List of callgraph sample filename. If the {dep} part of - * cg_filename != {cg} part it's a cross binary samples file. - */ - std::list<std::string> cg_files; -}; - - -/** - * A number of profiles files that are all dependent on - * the same main (application) profile, for the same - * dependent image. - */ -struct profile_dep_set { - /// which dependent image is this set for - std::string lib_image; - - /// the actual sample files optionnaly including callgraph sample files - std::list<profile_sample_files> files; -}; - -/** - * A number of profile files all for the same binary with the same - * profile specification (after merging). Includes the set of dependent - * profile files, if any. - * - * For example, we could have image == "/bin/bash", where files - * contains all profiles against /bin/bash, and deps contains - * the sample file list for /lib/libc.so, /lib/ld.so etc. - */ -struct profile_set { - std::string image; - - /// the actual sample files for the main image and the asociated - /// callgraph files - std::list<profile_sample_files> files; - - /// all profile files dependent on the main image - std::list<profile_dep_set> deps; -}; - - -/** - * A class collection of profiles. This is an equivalence class and - * will correspond to columnar output of opreport. - */ -struct profile_class { - std::list<profile_set> profiles; - - /// human-readable column name - std::string name; - - /// human-readable long name - std::string longname; - - /// merging matches against this - profile_template ptemplate; -}; - - -/** - * The "axis" says what we've used to split the sample - * files into the classes. Only one is allowed. - */ -enum axis_types { - AXIS_EVENT, - AXIS_TGID, - AXIS_TID, - AXIS_CPU, - AXIS_MAX -}; - - -struct profile_classes { - /** - * This is only set if we're not classifying on event/count - * anyway - if we're classifying on event/count, then we'll - * already output the details of each class's event/count. - * - * It's only used when classifying by CPU, tgid etc. so the - * user can still see what perfctr event was used. - */ - std::string event; - - /// CPU info - std::string cpuinfo; - - /// the actual classes - std::vector<profile_class> v; - - /// the axis of the classes - axis_types axis; - - /// is this class set comparable with another? - bool matches(profile_classes const & classes); -}; - - -std::ostream & operator<<(std::ostream &, profile_sample_files const &); -std::ostream & operator<<(std::ostream &, profile_dep_set const &); -std::ostream & operator<<(std::ostream &, profile_set const &); -std::ostream & operator<<(std::ostream &, profile_template const &); -std::ostream & operator<<(std::ostream &, profile_class const &); -std::ostream & operator<<(std::ostream &, profile_classes const &); - - -/** - * Take a list of sample filenames, and process them into a set of - * classes containing profile_sets. Merging is done at this stage - * as well as attaching dependent profiles to the main image. - * - * The classes correspond to the columns you'll get in opreport: - * this can be a number of events, or different CPUs, etc. - */ -profile_classes const -arrange_profiles(std::list<std::string> const & files, - merge_option const & merge_by); - - -/** - * A set of sample files where the image binary to open - * are all the same. - */ -struct image_set { - /// this is main app image, *not* necessarily - /// the one we need to open - std::string app_image; - - /// the sample files - std::list<profile_sample_files> files; -}; - -typedef std::list<image_set> image_group_set; - -/** - * All sample files where the binary image to open is - * the same. - * - * This is the "inverse" to some degree of profile_set. - * For example, here we might have image = "/lib/libc.so", - * with groups being the profile classifications - * tgid:404, tgid:301, etc. - * - * Within each group there's a number of image_sets. - * All the sample files listed within the image_sets - * are still for /lib/libc.so, but they may have - * different app_image values, e.g. /bin/bash. - * We need to keep track of the app_image values to - * make opreport give the right info in the "app" - * column. - */ -struct inverted_profile { - inverted_profile() : error(image_ok) {} - /// the image to open - std::string image; - - /// an error found in reading the image - mutable image_error error; - - /// all sample files with data for the above image - std::vector<image_group_set> groups; -}; - - -class extra_images; - -/** - * Invert the profile set. For opreport -l, opannotate etc., - * processing the profile_classes directly is slow, because - * we end up opening BFDs multiple times (for each class, - * dependent images etc.). This function returns an inverted - * set of sample files, where the primary sort is on the binary - * image to open. - * - * Thus each element in the returned list is for exactly one - * binary file that we're going to bfd_openr(). Attached to that - * is the actual sample files we need to process for that binary - * file. In order to get the output right, these have to be - * marked with the profile class they're from (hence the groups - * vector), and the app image that owned the sample file, if - * applicable (hence image_set). - */ -std::list<inverted_profile> const -invert_profiles(std::string archive_path, profile_classes const & classes, - extra_images const & extra); - -#endif /* !ARRANGE_PROFILES_H */ diff --git a/libpp/callgraph_container.cpp b/libpp/callgraph_container.cpp deleted file mode 100644 index b9b1a49..0000000 --- a/libpp/callgraph_container.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/** - * @file callgraph_container.cpp - * Container associating symbols and caller/caller symbols - * - * @remark Copyright 2004 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#include <cstdlib> - -#include <map> -#include <set> -#include <algorithm> -#include <iterator> -#include <string> -#include <iostream> -#include <numeric> - -#include "callgraph_container.h" -#include "cverb.h" -#include "parse_filename.h" -#include "profile_container.h" -#include "arrange_profiles.h" -#include "populate.h" -#include "string_filter.h" -#include "op_bfd.h" -#include "op_sample_file.h" -#include "locate_images.h" - -using namespace std; - -namespace { - -bool operator==(cg_symbol const & lhs, cg_symbol const & rhs) -{ - less_symbol cmp_symb; - return !cmp_symb(lhs, rhs) && !cmp_symb(rhs, lhs); -} - - -// we store {caller,callee} inside a single u64 -odb_key_t caller_to_key(u32 value) -{ - return odb_key_t(value) << 32; -} - - -u32 key_to_callee(odb_key_t key) -{ - return key & 0xffffffff; -} - - -bool compare_by_callee_vma(pair<odb_key_t, odb_value_t> const & lhs, - pair<odb_key_t, odb_value_t> const & rhs) -{ - return (key_to_callee(lhs.first)) < (key_to_callee(rhs.first)); -} - - -/* - * We need 2 comparators for callgraph to get the desired output: - * - * caller_with_few_samples - * caller_with_many_samples - * function_with_many_samples - * callee_with_many_samples - * callee_with_few_samples - */ - -bool -compare_arc_count(symbol_entry const & lhs, symbol_entry const & rhs) -{ - return lhs.sample.counts[0] < rhs.sample.counts[0]; -} - - -bool -compare_arc_count_reverse(symbol_entry const & lhs, symbol_entry const & rhs) -{ - return rhs.sample.counts[0] < lhs.sample.counts[0]; -} - - -// find the nearest bfd symbol for the given file offset and check it's -// in range -op_bfd_symbol const * -get_symbol_by_filepos(op_bfd const & bfd, u32 bfd_offset, - vma_t offset, symbol_index_t & i) -{ - offset += bfd_offset; - op_bfd_symbol tmpsym(offset, 0, string()); - - // sorted by filepos so this will find the nearest - vector<op_bfd_symbol>::const_iterator it = - upper_bound(bfd.syms.begin(), bfd.syms.end(), tmpsym); - - if (it != bfd.syms.begin()) - --it; - - if (it == bfd.syms.end()) { - cerr << "get_symbol_by_filepos: no symbols at all?" << endl; - abort(); - } - - // if the offset is past the end of the symbol, we didn't find one - u32 const end_offset = it->size() + it->filepos(); - - if (offset >= end_offset) { - // let's be verbose for now - cerr << "warning: dropping hyperspace sample at offset " - << hex << offset << " >= " << end_offset - << " for binary " << bfd.get_filename() << dec << endl; - return NULL; - } - - i = distance(bfd.syms.begin(), it); - return &(*it); -} - - -/// temporary caller and callee data held during processing -class call_data { -public: - call_data(profile_container const & p, profile_t const & pr, - op_bfd const & bfd, u32 boff, image_name_id iid, - image_name_id aid, bool debug_info) - : pc(p), profile(pr), b(bfd), boffset(boff), image(iid), - app(aid), debug(debug_info) {} - - /// point to a caller symbol - void caller_sym(symbol_index_t i) { - sym = symbol_entry(); - - unsigned long start; - unsigned long end; - b.get_symbol_range(i, start, end); - - samples.clear(); - - // see profile_t::samples_range() for why we need this check - if (start > boffset) { - profile_t::iterator_pair p_it = profile.samples_range( - caller_to_key(start - boffset), - caller_to_key(end - boffset)); - - // Our odb_key_t contain (from_eip << 32 | to_eip), - // the range of keys we selected above contains one - // caller but different callees, and due to the - // ordering callee offsets are not consecutive: so - // we must sort them first. - - for (; p_it.first != p_it.second; ++p_it.first) { - samples.push_back(make_pair(p_it.first.vma(), - p_it.first.count())); - } - - sort(samples.begin(), samples.end(), - compare_by_callee_vma); - } - - sym.size = end - start; - sym.name = symbol_names.create(b.syms[i].name()); - sym.sample.vma = b.sym_offset(i, start) + b.syms[i].vma(); - - finish_sym(i, start); - - if (cverb << vdebug) { - cverb << vdebug << hex << "Caller sym: " - << b.syms[i].name() << " filepos " << start - << "-" << end << dec << endl; - } - } - - /// point to a callee symbol - bool callee_sym(u32 off) { - sym = symbol_entry(); - - symbol_index_t i; - op_bfd_symbol const * bfdsym = - get_symbol_by_filepos(b, boffset, off, i); - - if (!bfdsym) - return false; - - callee_end = bfdsym->size() + bfdsym->filepos() - boffset; - - sym.size = bfdsym->size(); - sym.name = symbol_names.create(bfdsym->name()); - sym.sample.vma = bfdsym->vma(); - - finish_sym(i, bfdsym->filepos()); - - if (cverb << vdebug) { - cverb << vdebug << hex << "Callee sym: " - << bfdsym->name() << " filepos " - << bfdsym->filepos() << "-" - << (bfdsym->filepos() + bfdsym->size()) - << dec << endl; - } - return true; - } - - void verbose_bfd(string const & prefix) const { - cverb << vdebug << prefix << " " << b.get_filename() - << " offset " << boffset << " app " - << image_names.name(app) << endl; - } - - typedef vector<pair<odb_key_t, odb_value_t> > samples_t; - - typedef samples_t::const_iterator const_iterator; - - samples_t samples; - symbol_entry sym; - u32 callee_end; - -private: - /// fill in the rest of the sym - void finish_sym(symbol_index_t i, unsigned long start) { - sym.image_name = image; - sym.app_name = app; - symbol_entry const * self = pc.find(sym); - if (self) - sym.sample.counts = self->sample.counts; - - if (debug) { - string filename; - file_location & loc = sym.sample.file_loc; - if (b.get_linenr(i, start, filename, loc.linenr)) - loc.filename = debug_names.create(filename); - } - } - - profile_container const & pc; - profile_t const & profile; - op_bfd const & b; - u32 boffset; - image_name_id image; - image_name_id app; - bool debug; -}; - - -/// accumulate all samples for a given caller/callee pair -u32 -accumulate_callee(call_data::const_iterator & it, call_data::const_iterator end, - u32 callee_end) -{ - u32 count = 0; - call_data::const_iterator const start = it; - - while (it != end) { - u32 offset = key_to_callee(it->first); - - if (cverb << (vdebug & vlevel1)) { - cverb << (vdebug & vlevel1) << hex << "offset: " - << offset << dec << endl; - } - - // stop if we pass the end of the callee - if (offset >= callee_end) - break; - - count += it->second; - ++it; - } - - // If we haven't advanced at all, then we'll get - // an infinite loop, so we must abort. - if (it == start) { - cerr << "failure to advance iterator\n"; - abort(); - } - - return count; -} - - -} // anonymous namespace - - -void arc_recorder:: -add(symbol_entry const & caller, symbol_entry const * callee, - count_array_t const & arc_count) -{ - cg_data & data = sym_map[caller]; - - // If we have a callee, add it to the caller's list, then - // add the caller to the callee's list. - if (callee) { - data.callees[*callee] += arc_count; - - cg_data & callee_data = sym_map[*callee]; - - callee_data.callers[caller] += arc_count; - } -} - - -void arc_recorder::process_children(cg_symbol & sym, double threshold) -{ - // generate the synthetic self entry for the symbol - symbol_entry self = sym; - - self.name = symbol_names.create(symbol_names.demangle(self.name) - + " [self]"); - - sym.total_callee_count += self.sample.counts; - sym.callees.push_back(self); - - sort(sym.callers.begin(), sym.callers.end(), compare_arc_count); - sort(sym.callees.begin(), sym.callees.end(), compare_arc_count_reverse); - - // FIXME: this relies on sort always being sample count - - cg_symbol::children::iterator cit = sym.callers.begin(); - cg_symbol::children::iterator cend = sym.callers.end(); - - while (cit != cend && op_ratio(cit->sample.counts[0], - sym.total_caller_count[0]) < threshold) - ++cit; - - if (cit != cend) - sym.callers.erase(sym.callers.begin(), cit); - - cit = sym.callees.begin(); - cend = sym.callees.end(); - - while (cit != cend && op_ratio(cit->sample.counts[0], - sym.total_callee_count[0]) >= threshold) - ++cit; - - if (cit != cend) - sym.callees.erase(cit, sym.callees.end()); -} - - -void arc_recorder:: -process(count_array_t total, double threshold, - string_filter const & sym_filter) -{ - map_t::const_iterator it; - map_t::const_iterator end = sym_map.end(); - - for (it = sym_map.begin(); it != end; ++it) { - cg_symbol sym((*it).first); - cg_data const & data = (*it).second; - - // threshold out the main symbol if needed - if (op_ratio(sym.sample.counts[0], total[0]) < threshold) - continue; - - // FIXME: slow? - if (!sym_filter.match(symbol_names.demangle(sym.name))) - continue; - - cg_data::children::const_iterator cit; - cg_data::children::const_iterator cend = data.callers.end(); - - for (cit = data.callers.begin(); cit != cend; ++cit) { - symbol_entry csym = cit->first; - csym.sample.counts = cit->second; - sym.callers.push_back(csym); - sym.total_caller_count += cit->second; - } - - cend = data.callees.end(); - - for (cit = data.callees.begin(); cit != cend; ++cit) { - symbol_entry csym = cit->first; - csym.sample.counts = cit->second; - sym.callees.push_back(csym); - sym.total_callee_count += cit->second; - } - - process_children(sym, threshold); - - cg_syms.push_back(sym); - } -} - - -cg_collection arc_recorder::get_symbols() const -{ - return cg_syms; -} - - -void callgraph_container::populate(string const & archive_path, - list<inverted_profile> const & iprofiles, - extra_images const & extra, bool debug_info, double threshold, - bool merge_lib, string_filter const & sym_filter) -{ - // non callgraph samples container, we record sample at symbol level - // not at vma level. - profile_container pc(debug_info, false); - - list<inverted_profile>::const_iterator it; - list<inverted_profile>::const_iterator const end = iprofiles.end(); - for (it = iprofiles.begin(); it != end; ++it) { - // populate_caller_image take care about empty sample filename - populate_for_image(archive_path, pc, *it, sym_filter, 0); - } - - add_symbols(pc); - - total_count = pc.samples_count(); - - for (it = iprofiles.begin(); it != end; ++it) { - for (size_t i = 0; i < it->groups.size(); ++i) { - populate(archive_path, it->groups[i], it->image, extra, - i, pc, debug_info, merge_lib); - } - } - - recorder.process(total_count, threshold / 100.0, sym_filter); -} - - -void callgraph_container::populate(string const & archive_path, - list<image_set> const & lset, - string const & app_image, extra_images const & extra, size_t pclass, - profile_container const & pc, bool debug_info, bool merge_lib) -{ - list<image_set>::const_iterator lit; - list<image_set>::const_iterator const lend = lset.end(); - for (lit = lset.begin(); lit != lend; ++lit) { - list<profile_sample_files>::const_iterator pit; - list<profile_sample_files>::const_iterator pend - = lit->files.end(); - for (pit = lit->files.begin(); pit != pend; ++pit) { - populate(archive_path, pit->cg_files, app_image, - extra, pclass, pc, debug_info, merge_lib); - } - } -} - - -void callgraph_container::populate(string const & archive_path, - list<string> const & cg_files, - string const & app_image, extra_images const & extra, size_t pclass, - profile_container const & pc, bool debug_info, bool merge_lib) -{ - list<string>::const_iterator it; - list<string>::const_iterator const end = cg_files.end(); - for (it = cg_files.begin(); it != end; ++it) { - cverb << vdebug << "samples file : " << *it << endl; - - parsed_filename caller_file = parse_filename(*it); - string const app_name = caller_file.image; - - image_error error; - string caller_binary = - find_image_path(archive_path, caller_file.lib_image, - extra, error); - - if (error != image_ok) - report_image_error(archive_path + caller_file.lib_image, - error, false); - - bool caller_bfd_ok = true; - op_bfd caller_bfd(archive_path, caller_binary, - string_filter(), caller_bfd_ok); - if (!caller_bfd_ok) - report_image_error(caller_binary, - image_format_failure, false); - - parsed_filename callee_file = parse_filename(*it); - - string callee_binary = - find_image_path(archive_path, callee_file.cg_image, - extra, error); - if (error != image_ok) - report_image_error(callee_file.cg_image, error, false); - - bool callee_bfd_ok = true; - op_bfd callee_bfd(archive_path, callee_binary, - string_filter(), callee_bfd_ok); - if (!callee_bfd_ok) - report_image_error(callee_binary, - image_format_failure, false); - - profile_t profile; - // We can't use start_offset support in profile_t, give - // it a zero offset and we will fix that in add() - profile.add_sample_file(*it); - add(profile, caller_bfd, caller_bfd_ok, callee_bfd, - merge_lib ? app_image : app_name, pc, - debug_info, pclass); - } -} - - -void callgraph_container:: -add(profile_t const & profile, op_bfd const & caller_bfd, bool caller_bfd_ok, - op_bfd const & callee_bfd, string const & app_name, - profile_container const & pc, bool debug_info, size_t pclass) -{ - string const image_name = caller_bfd.get_filename(); - - opd_header const & header = profile.get_header(); - - // We can't use kernel sample file w/o the binary else we will - // use it with a zero offset, the code below will abort because - // we will get incorrect callee sub-range and out of range - // callee vma. FIXME - if (header.is_kernel && !caller_bfd_ok) - return; - - // We must handle start_offset, this offset can be different for the - // caller and the callee: kernel sample traversing the syscall barrier. - u32 caller_offset = 0; - - if (header.is_kernel || header.anon_start) { - caller_offset = caller_bfd.get_start_offset(header.anon_start); - } - - u32 callee_offset = 0; - - if (header.cg_to_is_kernel || header.cg_to_anon_start) { - callee_offset = - callee_bfd.get_start_offset(header.cg_to_anon_start); - } - - image_name_id image_id = image_names.create(image_name); - image_name_id callee_image_id = image_names.create(callee_bfd.get_filename()); - image_name_id app_id = image_names.create(app_name); - - call_data caller(pc, profile, caller_bfd, caller_offset, image_id, - app_id, debug_info); - call_data callee(pc, profile, callee_bfd, callee_offset, - callee_image_id, app_id, debug_info); - - if (cverb << vdebug) { - caller.verbose_bfd("Caller:"); - callee.verbose_bfd("Callee:"); - } - - // For each symbol in the caller bfd, process all arcs to - // callee bfd symbols - - for (symbol_index_t i = 0; i < caller_bfd.syms.size(); ++i) { - - caller.caller_sym(i); - - call_data::const_iterator dit = caller.samples.begin(); - call_data::const_iterator dend = caller.samples.end(); - while (dit != dend) { - // if we can't find the callee, skip an arc - if (!callee.callee_sym(key_to_callee(dit->first))) { - ++dit; - continue; - } - - count_array_t arc_count; - arc_count[pclass] = - accumulate_callee(dit, dend, callee.callee_end); - - recorder.add(caller.sym, &callee.sym, arc_count); - } - } -} - - -void callgraph_container::add_symbols(profile_container const & pc) -{ - symbol_container::symbols_t::iterator it; - symbol_container::symbols_t::iterator const end = pc.end_symbol(); - - for (it = pc.begin_symbol(); it != end; ++it) - recorder.add(*it, 0, count_array_t()); -} - - -column_flags callgraph_container::output_hint() const -{ - column_flags output_hints = cf_none; - - // FIXME: costly: must we access directly recorder map ? - cg_collection syms = recorder.get_symbols(); - - cg_collection::const_iterator it; - cg_collection::const_iterator const end = syms.end(); - for (it = syms.begin(); it != end; ++it) - output_hints = it->output_hint(output_hints); - - return output_hints; -} - - -count_array_t callgraph_container::samples_count() const -{ - return total_count; -} - - -cg_collection callgraph_container::get_symbols() const -{ - return recorder.get_symbols(); -} diff --git a/libpp/callgraph_container.h b/libpp/callgraph_container.h deleted file mode 100644 index 7b8ee6e..0000000 --- a/libpp/callgraph_container.h +++ /dev/null @@ -1,172 +0,0 @@ -/** - * @file callgraph_container.h - * Container associating symbols and caller/caller symbols - * - * @remark Copyright 2004 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#ifndef CALLGRAPH_CONTAINER_H -#define CALLGRAPH_CONTAINER_H - -#include <set> -#include <vector> -#include <string> - -#include "symbol.h" -#include "symbol_functors.h" -#include "string_filter.h" - -class profile_container; -class inverted_profile; -class profile_t; -class extra_images; -class image_set; -class op_bfd; - - -/** - * During building a callgraph_container we store all caller/callee - * relationship in this container. - * - * An "arc" is simply a description of a call from one function to - * another. - */ -class arc_recorder { -public: - ~arc_recorder() {} - - /** - * Add a symbol arc. - * @param caller The calling symbol - * @param callee The called symbol - * @param arc_count profile data for the arcs - * - * If the callee is NULL, only the caller is added to the main - * list. This is used to initially populate the recorder with - * the symbols. - */ - void add(symbol_entry const & caller, symbol_entry const * callee, - count_array_t const & arc_count); - - /// return all the cg symbols - cg_collection get_symbols() const; - - /** - * After population, build the final output, and do - * thresholding. - */ - void process(count_array_t total, double threshold, - string_filter const & filter); - -private: - /** - * Internal structure used during collation. We use a map to - * allow quick lookup of children (we'll do this several times - * if we have more than one profile class). Each child maps from - * the symbol to the relevant arc data. - */ - struct cg_data { - cg_data() {} - - typedef std::map<symbol_entry, count_array_t, less_symbol> children; - - /// callers of this symbol - children callers; - /// callees of this symbol - children callees; - }; - - /** - * Sort and threshold callers and callees. - */ - void process_children(cg_symbol & sym, double threshold); - - typedef std::map<symbol_entry, cg_data, less_symbol> map_t; - - /// all the symbols (used during processing) - map_t sym_map; - - /// final output data - cg_collection cg_syms; -}; - - -/** - * Store all callgraph information for the given profiles - */ -class callgraph_container { -public: - /** - * Populate the container, must be called once only. - * @param archive_path oparchive prefix path - * @param iprofiles sample file list including callgraph files. - * @param extra extra image list to fixup binary name. - * @param debug_info true if we must record linenr information - * @param threshold ignore sample percent below this threshold - * @param merge_lib merge library samples - * @param sym_filter symbol filter - * - * Currently all errors core dump. - * FIXME: consider if this should be a ctor - */ - void populate(std::string const & archive_path, - std::list<inverted_profile> const & iprofiles, - extra_images const & extra, bool debug_info, - double threshold, bool merge_lib, - string_filter const & sym_filter); - - /// return hint on how data must be displayed. - column_flags output_hint() const; - - /// return the total number of samples. - count_array_t samples_count() const; - - // return all the cg symbols - cg_collection get_symbols() const; - -private: - /** - * Record caller/callee for one cg file - * @param profile one callgraph file stored in a profile_t - * @param caller_bfd the caller bfd - * @param bfd_caller_ok true if we succefully open the binary - * @param callee_bfd the callee bfd - * @param app_name the owning application - * @param pc the profile_container holding all non cg samples. - * @param debug_info record linenr debug information - * @param pclass profile class nr - */ - void add(profile_t const & profile, op_bfd const & caller_bfd, - bool bfd_caller_ok, op_bfd const & callee_bfd, - std::string const & app_name, - profile_container const & pc, bool debug_info, - size_t pclass); - - void populate(std::string const & archive_path, - std::list<image_set> const & lset, - std::string const & app_image, - extra_images const & extra, size_t pclass, - profile_container const & pc, bool debug_info, - bool merge_lib); - void populate(std::string const & archive_path, - std::list<std::string> const & cg_files, - std::string const & app_image, - extra_images const & extra, size_t pclass, - profile_container const & pc, bool debug_info, - bool merge_lib); - - /// record all main symbols - void add_symbols(profile_container const & pc); - - /// Cached value of samples count. - count_array_t total_count; - - /// A structured representation of the callgraph. - arc_recorder recorder; -}; - -#endif /* !CALLGRAPH_CONTAINER_H */ diff --git a/libpp/diff_container.cpp b/libpp/diff_container.cpp deleted file mode 100644 index 7762916..0000000 --- a/libpp/diff_container.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/** - * @file diff_container.cpp - * Container for diffed symbols - * - * @remark Copyright 2005 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -/* older glibc has C99 INFINITY in _GNU_SOURCE */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include "diff_container.h" - -#include <cmath> - -using namespace std; - - -namespace { - - -/// a comparator suitable for diffing symbols -bool rough_less(symbol_entry const & lhs, symbol_entry const & rhs) -{ - if (lhs.image_name != rhs.image_name) - return lhs.image_name < rhs.image_name; - - if (lhs.app_name != rhs.app_name) - return lhs.app_name < rhs.app_name; - - if (lhs.name != rhs.name) - return lhs.name < rhs.name; - - return false; -} - - -/// possibly add a diff sym -void -add_sym(diff_collection & syms, diff_symbol const & sym, - profile_container::symbol_choice & choice) -{ - if (choice.match_image - && (image_names.name(sym.image_name) != choice.image_name)) - return; - - if (fabs(sym.diffs[0]) < choice.threshold) - return; - - choice.hints = sym.output_hint(choice.hints); - syms.push_back(sym); -} - - -/// add a symbol not present in the new profile -void -symbol_old(diff_collection & syms, symbol_entry const & sym, - profile_container::symbol_choice & choice) -{ - diff_symbol symbol(sym); - symbol.diffs.fill(sym.sample.counts.size(), -INFINITY); - add_sym(syms, symbol, choice); -} - - -/// add a symbol not present in the old profile -void -symbol_new(diff_collection & syms, symbol_entry const & sym, - profile_container::symbol_choice & choice) -{ - diff_symbol symbol(sym); - symbol.diffs.fill(sym.sample.counts.size(), INFINITY); - add_sym(syms, symbol, choice); -} - - -/// add a diffed symbol -void symbol_diff(diff_collection & syms, - symbol_entry const & sym1, count_array_t const & total1, - symbol_entry const & sym2, count_array_t const & total2, - profile_container::symbol_choice & choice) -{ - diff_symbol symbol(sym2); - - size_t size = sym2.sample.counts.size(); - for (size_t i = 0; i != size; ++i) { - double percent1; - double percent2; - percent1 = op_ratio(sym1.sample.counts[i], total1[i]); - percent2 = op_ratio(sym2.sample.counts[i], total2[i]); - symbol.diffs[i] = op_ratio(percent2 - percent1, percent1); - symbol.diffs[i] *= 100.0; - } - - add_sym(syms, symbol, choice); -} - - -}; // namespace anon - - -diff_container::diff_container(profile_container const & c1, - profile_container const & c2) - : pc1(c1), pc2(c2), - total1(pc1.samples_count()), total2(pc2.samples_count()) -{ -} - - -diff_collection const -diff_container::get_symbols(profile_container::symbol_choice & choice) const -{ - diff_collection syms; - - /* - * Do a pairwise comparison of the two symbol sets. We're - * relying here on the symbol container being sorted such - * that rough_less() is suitable for iterating through the - * two lists (see less_symbol). - */ - - symbol_container::symbols_t::iterator it1 = pc1.begin_symbol(); - symbol_container::symbols_t::iterator end1 = pc1.end_symbol(); - symbol_container::symbols_t::iterator it2 = pc2.begin_symbol(); - symbol_container::symbols_t::iterator end2 = pc2.end_symbol(); - - while (it1 != end1 && it2 != end2) { - if (rough_less(*it1, *it2)) { - symbol_old(syms, *it1, choice); - ++it1; - } else if (rough_less(*it2, *it1)) { - symbol_new(syms, *it2, choice); - ++it2; - } else { - symbol_diff(syms, *it1, total1, *it2, total2, choice); - ++it1; - ++it2; - } - } - - for (; it1 != end1; ++it1) - symbol_old(syms, *it1, choice); - - for (; it2 != end2; ++it2) - symbol_new(syms, *it2, choice); - - return syms; -} - - -count_array_t const diff_container::samples_count() const -{ - return total2; -} diff --git a/libpp/diff_container.h b/libpp/diff_container.h deleted file mode 100644 index 14b431d..0000000 --- a/libpp/diff_container.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file diff_container.h - * Container for diffed symbols - * - * @remark Copyright 2005 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#ifndef DIFF_CONTAINER_H -#define DIFF_CONTAINER_H - -#include "profile_container.h" - - -/** - * Store two profiles for diffing. - */ -class diff_container : noncopyable { -public: - /// populate the collection of diffed symbols - diff_container(profile_container const & pc1, - profile_container const & pc2); - - ~diff_container() {} - - /// return a collection of diffed symbols - diff_collection const - get_symbols(profile_container::symbol_choice & choice) const; - - /// total count for 'new' profile - count_array_t const samples_count() const; - -private: - /// first profile - profile_container const & pc1; - - /// second profile - profile_container const & pc2; - - /// samples count for pc1 - count_array_t total1; - - /// samples count for pc2 - count_array_t total2; -}; - -#endif /* !DIFF_CONTAINER_H */ diff --git a/libpp/filename_spec.cpp b/libpp/filename_spec.cpp deleted file mode 100644 index 9ce7cb4..0000000 --- a/libpp/filename_spec.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file filename_spec.cpp - * Container holding a sample filename split into its components - * - * @remark Copyright 2003 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - */ - -#include <string> - -#include "filename_spec.h" -#include "parse_filename.h" -#include "generic_spec.h" - - -using namespace std; - - -filename_spec::filename_spec(string const & filename) -{ - set_sample_filename(filename); -} - - -filename_spec::filename_spec() - : image("*"), lib_image("*") -{ -} - - -bool filename_spec::match(filename_spec const & rhs, - string const & binary) const -{ - if (!tid.match(rhs.tid) || !cpu.match(rhs.cpu) || - !tgid.match(rhs.tgid) || count != rhs.count || - unitmask != rhs.unitmask || event != rhs.event) { - return false; - } - - if (binary.empty()) { - return image == rhs.image && lib_image == rhs.lib_image; - } - - // PP:3.3 if binary is not empty we must match either the - // lib_name if present or the image name - if (!rhs.lib_image.empty()) { - // FIXME: use fnmatch ? - return rhs.lib_image == binary; - } - - // FIXME: use fnmatch ? - return rhs.image == binary; -} - - -void filename_spec::set_sample_filename(string const & filename) -{ - parsed_filename parsed = parse_filename(filename); - - image = parsed.image; - lib_image = parsed.lib_image; - cg_image = parsed.cg_image; - event = parsed.event; - count = op_lexical_cast<int>(parsed.count); - unitmask = op_lexical_cast<unsigned int>(parsed.unitmask); - tgid.set(parsed.tgid); - tid.set(parsed.tid); - cpu.set(parsed.cpu); -} - - -bool filename_spec::is_dependent() const -{ - if (cg_image.empty()) - return image != lib_image; - return cg_image != image || cg_image != lib_image; -} diff --git a/libpp/filename_spec.h b/libpp/filename_spec.h deleted file mode 100644 index abd7f8a..0000000 --- a/libpp/filename_spec.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file filename_spec.h - * Container holding a sample filename split into its components - * - * @remark Copyright 2003 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - */ - -#ifndef FILENAME_SPEC_H -#define FILENAME_SPEC_H - -#include <unistd.h> -#include <string> - -#include "generic_spec.h" - -class profile_spec; - -/** - * A class to split and store components of a sample filename. - * These derived values are then used to match against a - * profile_spec as given by the user. - */ -class filename_spec -{ - friend class profile_spec; - -public: - /** - * @param filename the samples filename - * - * build a filename_spec from a samples filename - */ - filename_spec(std::string const & filename); - - filename_spec(); - - /** - * @param filename a sample filename - * - * setup filename spec according to the samples filename. PP:3.19 to - * 3.25 - */ - void set_sample_filename(std::string const & filename); - - /** - * @param rhs right hand side of the match operator - * @param binary if binary is non-empty, and matches - * the binary or lib name, use it rather than the - * one in rhs. - * - * return true if *this match rhs, matching if: - * - image_name are identical - * - lib_name are identical - * - event_spec match - * - * This operation is not commutative. First part of PP:3.24 - */ - bool match(filename_spec const & rhs, - std::string const & binary) const; - - bool is_dependent() const; - -private: - std::string image; - std::string lib_image; - std::string cg_image; - std::string event; - int count; - unsigned int unitmask; - generic_spec<pid_t> tgid; - generic_spec<pid_t> tid; - generic_spec<int> cpu; -}; - - -#endif /* !FILENAME_SPEC_H */ diff --git a/libpp/format_flags.h b/libpp/format_flags.h deleted file mode 100644 index 6268ae1..0000000 --- a/libpp/format_flags.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @file format_flags.h - * output options - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author John Levon - * @author Philippe Elie - */ - -#ifndef FORMAT_FLAGS_H -#define FORMAT_FLAGS_H - -/** - * flags passed to the ctor of an output_symbol object. - * - * \sa format_output::formatter - */ -enum format_flags { - ff_none = 0, - /// a formatted memory address - ff_vma = 1 << 0, - /// output debug filename and line nr. - ff_linenr_info = 1 << 1, - /// output the image name for this line - ff_image_name = 1 << 3, - /// output owning application name - ff_app_name = 1 << 4, - /// output the (demangled) symbol name - ff_symb_name = 1 << 5, - - /** @name subset of flags used by opreport_formatter */ - //@{ - /// number of samples - ff_nr_samples = 1 << 6, - /// number of samples accumulated - ff_nr_samples_cumulated = 1 << 7, - /// relative percentage of samples - ff_percent = 1 << 8, - /// relative percentage of samples accumulated - ff_percent_cumulated = 1 << 9, - /** - * Output percentage for details, not relative - * to symbol but relative to the total nr of samples - */ - ff_percent_details = 1 << 10, - /** - * Output percentage for details, not relative - * to symbol but relative to the total nr of samples, - * accumulated - */ - ff_percent_cumulated_details = 1 << 11, - /// output diff value - ff_diff = 1 << 12, - //@} -}; - - -/** - * General hints about formatting of the columnar output. - */ -enum column_flags { - cf_none = 0, - cf_64bit_vma = 1 << 0, - cf_image_name = 1 << 1 -}; - -#endif // FORMAT_FLAGS_H diff --git a/libpp/format_output.cpp b/libpp/format_output.cpp deleted file mode 100644 index 700c0d6..0000000 --- a/libpp/format_output.cpp +++ /dev/null @@ -1,544 +0,0 @@ -/** - * @file format_output.cpp - * outputting format for symbol lists - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -/* older glibc has C99 INFINITY in _GNU_SOURCE */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include <sstream> -#include <iomanip> -#include <iostream> -#include <cmath> - -#include "string_manip.h" - -#include "format_output.h" -#include "profile_container.h" -#include "callgraph_container.h" -#include "diff_container.h" - -using namespace std; - - -namespace { - -string const & get_image_name(image_name_id id, bool lf) -{ - return lf ? image_names.name(id) : image_names.basename(id); -} - -string const get_linenr_info(file_location const floc, bool lf) -{ - ostringstream out; - - string const & filename = lf - ? debug_names.name(floc.filename) - : debug_names.basename(floc.filename); - - if (!filename.empty()) { - out << filename << ":" << floc.linenr; - } else { - out << "(no location information)"; - } - - return out.str(); -} - -string get_vma(bfd_vma vma, bool vma_64) -{ - ostringstream out; - int width = vma_64 ? 16 : 8; - - out << hex << setw(width) << setfill('0') << vma; - - return out.str(); -} - -string get_percent(size_t dividend, size_t divisor) -{ - double ratio = op_ratio(dividend, divisor); - - return ::format_percent(ratio * 100, percent_int_width, - percent_fract_width); -} - -} // anonymous namespace - - -namespace format_output { - - -formatter::formatter() - : - nr_classes(1), - flags(ff_none), - vma_64(false), - long_filenames(false), - need_header(true) -{ - format_map[ff_vma] = field_description(9, "vma", &formatter::format_vma); - format_map[ff_nr_samples] = field_description(9, "samples", &formatter::format_nr_samples); - format_map[ff_nr_samples_cumulated] = field_description(14, "cum. samples", &formatter::format_nr_cumulated_samples); - format_map[ff_percent] = field_description(9, "%", &formatter::format_percent); - format_map[ff_percent_cumulated] = field_description(11, "cum. %", &formatter::format_cumulated_percent); - format_map[ff_linenr_info] = field_description(28, "linenr info", &formatter::format_linenr_info); - format_map[ff_image_name] = field_description(25, "image name", &formatter::format_image_name); - format_map[ff_app_name] = field_description(25, "app name", &formatter::format_app_name); - format_map[ff_symb_name] = field_description(30, "symbol name", &formatter::format_symb_name); - format_map[ff_percent_details] = field_description(9, "%", &formatter::format_percent_details); - format_map[ff_percent_cumulated_details] = field_description(10, "cum. %", &formatter::format_cumulated_percent_details); - format_map[ff_diff] = field_description(10, "diff %", &formatter::format_diff); -} - - -formatter::~formatter() -{ -} - - -void formatter::set_nr_classes(size_t nr) -{ - nr_classes = nr; -} - - -void formatter::add_format(format_flags flag) -{ - flags = static_cast<format_flags>(flags | flag); -} - - -void formatter::show_header(bool on_off) -{ - need_header = on_off; -} - - -void formatter::vma_format_64bit(bool on_off) -{ - vma_64 = on_off; -} - - -void formatter::show_long_filenames(bool on_off) -{ - long_filenames = on_off; -} - - -void formatter::show_global_percent(bool on_off) -{ - global_percent = on_off; -} - - -void formatter::output_header(ostream & out) -{ - if (!need_header) - return; - - size_t padding = 0; - - // first output the vma field - if (flags & ff_vma) - padding = output_header_field(out, ff_vma, padding); - - // the field repeated for each profile class - for (size_t pclass = 0 ; pclass < nr_classes; ++pclass) { - if (flags & ff_nr_samples) - padding = output_header_field(out, - ff_nr_samples, padding); - - if (flags & ff_nr_samples_cumulated) - padding = output_header_field(out, - ff_nr_samples_cumulated, padding); - - if (flags & ff_percent) - padding = output_header_field(out, - ff_percent, padding); - - if (flags & ff_percent_cumulated) - padding = output_header_field(out, - ff_percent_cumulated, padding); - - if (flags & ff_diff) - padding = output_header_field(out, - ff_diff, padding); - - if (flags & ff_percent_details) - padding = output_header_field(out, - ff_percent_details, padding); - - if (flags & ff_percent_cumulated_details) - padding = output_header_field(out, - ff_percent_cumulated_details, padding); - } - - // now the remaining field - if (flags & ff_linenr_info) - padding = output_header_field(out, ff_linenr_info, padding); - - if (flags & ff_image_name) - padding = output_header_field(out, ff_image_name, padding); - - if (flags & ff_app_name) - padding = output_header_field(out, ff_app_name, padding); - - if (flags & ff_symb_name) - padding = output_header_field(out, ff_symb_name, padding); - - out << "\n"; -} - - -/// describe each possible field of colummned output. -// FIXME: use % of the screen width here. sum of % equal to 100, then calculate -// ratio between 100 and the selected % to grow non fixed field use also -// lib[n?]curses to get the console width (look info source) (so on add a fixed -// field flags) -size_t formatter:: -output_field(ostream & out, field_datum const & datum, - format_flags fl, size_t padding, bool hide_immutable) -{ - if (!hide_immutable) { - out << string(padding, ' '); - - field_description const & field(format_map[fl]); - string str = (this->*field.formatter)(datum); - out << str; - - // at least one separator char - padding = 1; - if (str.length() < field.width) - padding = field.width - str.length(); - } else { - field_description const & field(format_map[fl]); - padding += field.width; - } - - return padding; -} - - -size_t formatter:: -output_header_field(ostream & out, format_flags fl, size_t padding) -{ - out << string(padding, ' '); - - field_description const & field(format_map[fl]); - out << field.header_name; - - // at least one separator char - padding = 1; - if (field.header_name.length() < field.width) - padding = field.width - field.header_name.length(); - - return padding; -} - - -string formatter::format_vma(field_datum const & f) -{ - return get_vma(f.sample.vma, vma_64); -} - - -string formatter::format_symb_name(field_datum const & f) -{ - return symbol_names.demangle(f.symbol.name); -} - - -string formatter::format_image_name(field_datum const & f) -{ - return get_image_name(f.symbol.image_name, long_filenames); -} - - -string formatter::format_app_name(field_datum const & f) -{ - return get_image_name(f.symbol.app_name, long_filenames); -} - - -string formatter::format_linenr_info(field_datum const & f) -{ - return get_linenr_info(f.sample.file_loc, long_filenames); -} - - -string formatter::format_nr_samples(field_datum const & f) -{ - ostringstream out; - out << f.sample.counts[f.pclass]; - return out.str(); -} - - -string formatter::format_nr_cumulated_samples(field_datum const & f) -{ - if (f.diff == -INFINITY) - return "---"; - ostringstream out; - f.counts.cumulated_samples[f.pclass] += f.sample.counts[f.pclass]; - out << f.counts.cumulated_samples[f.pclass]; - return out.str(); -} - - -string formatter::format_percent(field_datum const & f) -{ - if (f.diff == -INFINITY) - return "---"; - return get_percent(f.sample.counts[f.pclass], f.counts.total[f.pclass]); -} - - -string formatter::format_cumulated_percent(field_datum const & f) -{ - if (f.diff == -INFINITY) - return "---"; - f.counts.cumulated_percent[f.pclass] += f.sample.counts[f.pclass]; - - return get_percent(f.counts.cumulated_percent[f.pclass], - f.counts.total[f.pclass]); -} - - -string formatter::format_percent_details(field_datum const & f) -{ - return get_percent(f.sample.counts[f.pclass], - f.counts.total[f.pclass]); -} - - -string formatter::format_cumulated_percent_details(field_datum const & f) -{ - f.counts.cumulated_percent_details[f.pclass] += f.sample.counts[f.pclass]; - - return get_percent(f.counts.cumulated_percent_details[f.pclass], - f.counts.total[f.pclass]); -} - - -string formatter::format_diff(field_datum const & f) -{ - if (f.diff == INFINITY) { - ostringstream out; - out << "+++"; - return out.str(); - } else if (f.diff == -INFINITY) { - ostringstream out; - out << "---"; - return out.str(); - } - - return ::format_percent(f.diff, percent_int_width, - percent_fract_width, true); -} - - -void formatter:: -do_output(ostream & out, symbol_entry const & symb, sample_entry const & sample, - counts_t & c, diff_array_t const & diffs, bool hide_immutable) -{ - size_t padding = 0; - - // first output the vma field - field_datum datum(symb, sample, 0, c); - if (flags & ff_vma) - padding = output_field(out, datum, ff_vma, padding, false); - - // repeated fields for each profile class - for (size_t pclass = 0 ; pclass < nr_classes; ++pclass) { - field_datum datum(symb, sample, pclass, c, diffs[pclass]); - - if (flags & ff_nr_samples) - padding = output_field(out, datum, - ff_nr_samples, padding, false); - - if (flags & ff_nr_samples_cumulated) - padding = output_field(out, datum, - ff_nr_samples_cumulated, padding, false); - - if (flags & ff_percent) - padding = output_field(out, datum, - ff_percent, padding, false); - - if (flags & ff_percent_cumulated) - padding = output_field(out, datum, - ff_percent_cumulated, padding, false); - - if (flags & ff_diff) - padding = output_field(out, datum, - ff_diff, padding, false); - - if (flags & ff_percent_details) - padding = output_field(out, datum, - ff_percent_details, padding, false); - - if (flags & ff_percent_cumulated_details) - padding = output_field(out, datum, - ff_percent_cumulated_details, padding, false); - } - - // now the remaining field - if (flags & ff_linenr_info) - padding = output_field(out, datum, ff_linenr_info, - padding, false); - - if (flags & ff_image_name) - padding = output_field(out, datum, ff_image_name, - padding, hide_immutable); - - if (flags & ff_app_name) - padding = output_field(out, datum, ff_app_name, - padding, hide_immutable); - - if (flags & ff_symb_name) - padding = output_field(out, datum, ff_symb_name, - padding, hide_immutable); - - out << "\n"; -} - - -opreport_formatter::opreport_formatter(profile_container const & p) - : - profile(p), - need_details(false) -{ - counts.total = profile.samples_count(); -} - - -void opreport_formatter::show_details(bool on_off) -{ - need_details = on_off; -} - - -void opreport_formatter::output(ostream & out, symbol_entry const * symb) -{ - do_output(out, *symb, symb->sample, counts); - - if (need_details) - output_details(out, symb); -} - - -void opreport_formatter:: -output(ostream & out, symbol_collection const & syms) -{ - output_header(out); - - symbol_collection::const_iterator it = syms.begin(); - symbol_collection::const_iterator end = syms.end(); - for (; it != end; ++it) - output(out, *it); -} - - -void opreport_formatter:: -output_details(ostream & out, symbol_entry const * symb) -{ - counts_t c = counts; - - if (!global_percent) - c.total = symb->sample.counts; - - // cumulated percent are relative to current symbol. - c.cumulated_samples = count_array_t(); - c.cumulated_percent = count_array_t(); - - sample_container::samples_iterator it = profile.begin(symb); - sample_container::samples_iterator end = profile.end(symb); - for (; it != end; ++it) { - out << " "; - do_output(out, *symb, it->second, c, diff_array_t(), true); - } -} - - -cg_formatter::cg_formatter(callgraph_container const & profile) -{ - counts.total = profile.samples_count(); -} - - -void cg_formatter::output(ostream & out, cg_collection const & syms) -{ - // amount of spacing prefixing child and parent lines - string const child_parent_prefix(" "); - - output_header(out); - - out << string(79, '-') << endl; - - cg_collection::const_iterator it; - cg_collection::const_iterator end = syms.end(); - - for (it = syms.begin(); it < end; ++it) { - cg_symbol const & sym = *it; - - cg_symbol::children::const_iterator cit; - cg_symbol::children::const_iterator cend = sym.callers.end(); - - counts_t c; - if (global_percent) - c.total = counts.total; - else - c.total = sym.total_caller_count; - - for (cit = sym.callers.begin(); cit != cend; ++cit) { - out << child_parent_prefix; - do_output(out, *cit, cit->sample, c); - } - - do_output(out, sym, sym.sample, counts); - - c = counts_t(); - if (global_percent) - c.total = counts.total; - else - c.total = sym.total_callee_count; - - cend = sym.callees.end(); - - for (cit = sym.callees.begin(); cit != cend; ++cit) { - out << child_parent_prefix; - do_output(out, *cit, cit->sample, c); - } - - out << string(79, '-') << endl; - } -} - - -diff_formatter::diff_formatter(diff_container const & profile) -{ - counts.total = profile.samples_count(); -} - - -void diff_formatter::output(ostream & out, diff_collection const & syms) -{ - output_header(out); - - diff_collection::const_iterator it = syms.begin(); - diff_collection::const_iterator end = syms.end(); - for (; it != end; ++it) - do_output(out, *it, it->sample, counts, it->diffs); -} - - -} // namespace format_output diff --git a/libpp/format_output.h b/libpp/format_output.h deleted file mode 100644 index 88404d7..0000000 --- a/libpp/format_output.h +++ /dev/null @@ -1,222 +0,0 @@ -/** - * @file format_output.h - * outputting format for symbol lists - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#ifndef FORMAT_OUTPUT_H -#define FORMAT_OUTPUT_H - -#include "config.h" - -#include <string> -#include <map> -#include <iosfwd> - -#include "format_flags.h" -#include "symbol.h" - -class symbol_entry; -class sample_entry; -class callgraph_container; -class profile_container; -class diff_container; - -namespace format_output { - -/// base class for formatter, handle common options to formatter -class formatter { -public: - formatter(); - virtual ~formatter(); - - /// add a given column - void add_format(format_flags flag); - - /// set the need_header boolean to false - void show_header(bool); - /// format for 64 bit wide VMAs - void vma_format_64bit(bool); - /// show long (full path) filenames - void show_long_filenames(bool); - /// use global count rather symbol count for details percent - void show_global_percent(bool); - - /** - * Set the number of collected profile classes. Each class - * will output sample count and percentage in extra columns. - * - * This class assumes that the profile information has been - * populated with the right number of classes. - */ - void set_nr_classes(size_t nr_classes); - - /// output table header, implemented by calling the virtual function - /// output_header_field() - void output_header(std::ostream & out); - -protected: - struct counts_t { - /// total sample count - count_array_t total; - /// samples so far - count_array_t cumulated_samples; - /// percentage so far - count_array_t cumulated_percent; - /// detailed percentage so far - count_array_t cumulated_percent_details; - }; - - /// data passed for output - struct field_datum { - field_datum(symbol_entry const & sym, - sample_entry const & s, - size_t pc, counts_t & c, double d = 0.0) - : symbol(sym), sample(s), pclass(pc), - counts(c), diff(d) {} - symbol_entry const & symbol; - sample_entry const & sample; - size_t pclass; - mutable counts_t & counts; - double diff; - }; - - /// format callback type - typedef std::string (formatter::*fct_format)(field_datum const &); - - /** @name format functions. - * The set of formatting functions, used internally by output(). - */ - //@{ - std::string format_vma(field_datum const &); - std::string format_symb_name(field_datum const &); - std::string format_image_name(field_datum const &); - std::string format_app_name(field_datum const &); - std::string format_linenr_info(field_datum const &); - std::string format_nr_samples(field_datum const &); - std::string format_nr_cumulated_samples(field_datum const &); - std::string format_percent(field_datum const &); - std::string format_cumulated_percent(field_datum const &); - std::string format_percent_details(field_datum const &); - std::string format_cumulated_percent_details(field_datum const &); - std::string format_diff(field_datum const &); - //@} - - /// decribe one field of the colummned output. - struct field_description { - field_description() {} - field_description(std::size_t w, std::string h, fct_format f) - : width(w), header_name(h), formatter(f) {} - - std::size_t width; - std::string header_name; - fct_format formatter; - }; - - typedef std::map<format_flags, field_description> format_map_t; - - /// actually do output - void do_output(std::ostream & out, symbol_entry const & symbol, - sample_entry const & sample, counts_t & c, - diff_array_t const & = diff_array_t(), - bool hide_immutable_field = false); - - /// returns the nr of char needed to pad this field - size_t output_header_field(std::ostream & out, format_flags fl, - size_t padding); - - /// returns the nr of char needed to pad this field - size_t output_field(std::ostream & out, field_datum const & datum, - format_flags fl, size_t padding, - bool hide_immutable); - - /// stores functors for doing actual formatting - format_map_t format_map; - - /// number of profile classes - size_t nr_classes; - - /// total counts - counts_t counts; - - /// formatting flags set - format_flags flags; - /// true if we need to format as 64 bits quantities - bool vma_64; - /// false if we use basename(filename) in output rather filename - bool long_filenames; - /// true if we need to show header before the first output - bool need_header; - /// bool if details percentage are relative to total count rather to - /// symbol count - bool global_percent; -}; - - -/// class to output in a columned format symbols and associated samples -class opreport_formatter : public formatter { -public: - /// build a ready to use formatter - opreport_formatter(profile_container const & profile); - - /** output a vector of symbols to out according to the output format - * specifier previously set by call(s) to add_format() */ - void output(std::ostream & out, symbol_collection const & syms); - - /// set the output_details boolean - void show_details(bool); - -private: - - /** output one symbol symb to out according to the output format - * specifier previously set by call(s) to add_format() */ - void output(std::ostream & out, symbol_entry const * symb); - - /// output details for the symbol - void output_details(std::ostream & out, symbol_entry const * symb); - - /// container we work from - profile_container const & profile; - - /// true if we need to show details for each symbols - bool need_details; -}; - - -/// class to output in a columned format caller/callee and associated samples -class cg_formatter : public formatter { -public: - /// build a ready to use formatter - cg_formatter(callgraph_container const & profile); - - /** output callgraph information according to the previously format - * specifier set by call(s) to add_format() */ - void output(std::ostream & out, cg_collection const & syms); -}; - -/// class to output a columned format symbols plus diff values -class diff_formatter : public formatter { -public: - /// build a ready to use formatter - diff_formatter(diff_container const & profile); - - /** - * Output a vector of symbols to out according to the output - * format specifier previously set by call(s) to add_format() - */ - void output(std::ostream & out, diff_collection const & syms); - -private: - /// output a single symbol - void output(std::ostream & out, diff_symbol const & sym); - -}; - -} // namespace format_output - -#endif /* !FORMAT_OUTPUT_H */ diff --git a/libpp/image_errors.cpp b/libpp/image_errors.cpp deleted file mode 100644 index 0960be6..0000000 --- a/libpp/image_errors.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @file image_errors.cpp - * Report errors in images - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author John Levon - */ - -#include "image_errors.h" - -#include "arrange_profiles.h" -#include "string_manip.h" - -#include <iostream> -#include <set> - -using namespace std; - -namespace { - -set<string> reported_images_error; - -} - -void report_image_error(string const & image, image_error error, bool fatal) -{ - if (error == image_ok) - return; - - if (reported_images_error.find(image) == reported_images_error.end()) { - reported_images_error.insert(image); - - // FIXME: hacky - if (error == image_not_found && is_prefix(image, "anon ")) - return; - - cerr << (fatal ? "error: " : "warning: "); - cerr << image << ' '; - - switch (error) { - case image_not_found: - cerr << "could not be found.\n"; - break; - - case image_unreadable: - cerr << "could not be read.\n"; - break; - - case image_multiple_match: - cerr << "matches more than one file: " - "detailed profile will not be provided.\n"; - break; - - case image_format_failure: - cerr << "is not in a usable binary format.\n"; - break; - - case image_ok: - break; - } - } -} - - -void report_image_error(inverted_profile const & profile, bool fatal) -{ - report_image_error(profile.image, profile.error, fatal); -} - - -void report_image_errors(list<inverted_profile> const & plist) -{ - list<inverted_profile>::const_iterator it = plist.begin(); - list<inverted_profile>::const_iterator const end = plist.end(); - - for (; it != end; ++it) { - report_image_error(*it, false); - } -} diff --git a/libpp/image_errors.h b/libpp/image_errors.h deleted file mode 100644 index ec26d90..0000000 --- a/libpp/image_errors.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file image_errors.h - * Report errors in images - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author John Levon - */ - -#ifndef IMAGE_ERRORS_H -#define IMAGE_ERRORS_H - -#include <list> -#include <string> - -class inverted_profile; - -/// possible reasons why we can't read a binary image -enum image_error { - image_ok = 0, - image_not_found, - image_unreadable, - image_format_failure, - image_multiple_match -}; - -/// output why the image passed can't be read to stderr, we warranty only one -/// error report by image name. -void -report_image_error(std::string const & image, image_error error, bool fatal); - -/// output why the image passed can't be read to stderr -void report_image_error(inverted_profile const & profile, bool fatal); - -/// output why any bad images can't be read to stderr -void report_image_errors(std::list<inverted_profile> const & plist); - -#endif /* IMAGE_ERRORS_H */ diff --git a/libpp/locate_images.cpp b/libpp/locate_images.cpp deleted file mode 100644 index 26b14b3..0000000 --- a/libpp/locate_images.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/** - * @file locate_images.cpp - * Command-line helper - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#include "file_manip.h" -#include "locate_images.h" - -#include <cerrno> -#include <iostream> -#include <sstream> -#include <cstdlib> - -using namespace std; - - -void extra_images::populate(vector<string> const & paths) -{ - vector<string>::const_iterator cit = paths.begin(); - vector<string>::const_iterator end = paths.end(); - for (; cit != end; ++cit) { - string const path = op_realpath(*cit); - list<string> file_list; - create_file_list(file_list, path, "*", true); - list<string>::const_iterator lit = file_list.begin(); - list<string>::const_iterator lend = file_list.end(); - for (; lit != lend; ++lit) { - value_type v(op_basename(*lit), op_dirname(*lit)); - images.insert(v); - } - } -} - - -vector<string> const extra_images::find(string const & name) const -{ - extra_images::matcher match(name); - return find(match); -} - - -vector<string> const -extra_images::find(extra_images::matcher const & match) const -{ - vector<string> matches; - - const_iterator cit = images.begin(); - const_iterator end = images.end(); - - for (; cit != end; ++cit) { - if (match(cit->first)) - matches.push_back(cit->second + '/' + cit->first); - } - - return matches; -} - - -namespace { - -/** - * Function object for matching a module filename, which - * has its own special mangling rules in 2.6 kernels. - */ -struct module_matcher : public extra_images::matcher { -public: - explicit module_matcher(string const & s) - : extra_images::matcher(s) {} - - virtual bool operator()(string const & candidate) const { - if (candidate.length() != value.length()) - return false; - - for (string::size_type i = 0 ; i < value.length() ; ++i) { - if (value[i] == candidate[i]) - continue; - if (value[i] == '_' && - (candidate[i] == ',' || candidate[i] == '-')) - continue; - return false; - } - - return true; - } -}; - -} // anon namespace - - -string const find_image_path(string const & archive_path, - string const & image_name, - extra_images const & extra_images, - image_error & error) -{ - error = image_ok; - - string const image = op_realpath(archive_path + image_name); - - // simplest case - if (op_file_readable(image)) { - error = image_ok; - return image_name; - } - - if (errno == EACCES) { - error = image_unreadable; - return image_name; - } - - string const base = op_basename(image); - - vector<string> result = extra_images.find(base); - - // not found, try a module search - if (result.empty()) - result = extra_images.find(module_matcher(base + ".ko")); - - if (result.empty()) { - error = image_not_found; - return image_name; - } - - if (result.size() > 1) { - error = image_multiple_match; - return image_name; - } - - return result[0]; -} diff --git a/libpp/locate_images.h b/libpp/locate_images.h deleted file mode 100644 index c003f9e..0000000 --- a/libpp/locate_images.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @file locate_images.h - * Location of binary images - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#ifndef LOCATE_IMAGES_H -#define LOCATE_IMAGES_H - -#include <string> -#include <map> -#include <vector> - -#include "image_errors.h" - -/** - * A class containing mappings from an image basename, - * such as 'floppy.ko', to locations in the paths passed - * in to populate(). - * - * The name may exist multiple times; all locations are recorded - * in this container. - */ -class extra_images { -public: - /// add all filenames found in the given paths, recursively - void populate(std::vector<std::string> const & paths); - - /// base class for matcher functors object - struct matcher { - std::string const & value; - public: - explicit matcher(std::string const & v) : value(v) {} - virtual ~matcher() {} - /// default functor allowing trivial match - virtual bool operator()(std::string const & str) const { - return str == value; - } - }; - - /** - * return a vector of all directories that match the functor - */ - std::vector<std::string> const find(matcher const & match) const; - - /// return a vector of all directories that match the given name - std::vector<std::string> const find(std::string const & name) const; - -private: - typedef std::multimap<std::string, std::string> images_t; - typedef images_t::value_type value_type; - typedef images_t::const_iterator const_iterator; - - /// map from image basename to owning directory - images_t images; -}; - -/** - * @param archive_path archive prefix path - * @param extra_images container where all extra candidate filenames are stored - * @param image_name binary image name - * @param error errors are flagged in this passed enum ref - * - * Locate a (number of) matching absolute paths to the given image name. - * If we fail to find the file we fill in error and return the original string. - */ -std::string const -find_image_path(std::string const & archive_path, - std::string const & image_name, - extra_images const & extra_images, - image_error & error); - -#endif /* LOCATE_IMAGES_H */ diff --git a/libpp/name_storage.cpp b/libpp/name_storage.cpp deleted file mode 100644 index 99e0e90..0000000 --- a/libpp/name_storage.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file name_storage.cpp - * Storage of global names (filenames and symbols) - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#include <stdexcept> - -#include "name_storage.h" -#include "demangle_symbol.h" -#include "file_manip.h" -#include "string_manip.h" - -using namespace std; - -image_name_storage image_names; -debug_name_storage debug_names; -symbol_name_storage symbol_names; - - -string const & image_name_storage::basename(image_name_id id) const -{ - stored_name const & n = get(id); - if (n.name_processed.empty()) { - n.name_processed = op_basename(n.name); - } - return n.name_processed; -} - - -string const & debug_name_storage::basename(debug_name_id id) const -{ - stored_name const & n = get(id); - if (n.name_processed.empty()) { - n.name_processed = op_basename(n.name); - } - return n.name_processed; -} - - -string const & symbol_name_storage::demangle(symbol_name_id id) const -{ - stored_name const & n = get(id); - if (!n.name_processed.empty() || n.name.empty()) - return n.name_processed; - - if (n.name[0] != '?') { - n.name_processed = demangle_symbol(n.name); - return n.name_processed; - } - - if (n.name.length() < 2 || n.name[1] != '?') { - n.name_processed = "(no symbols)"; - return n.name_processed; - } - - n.name_processed = "anonymous symbol from section "; - n.name_processed += ltrim(n.name, "?"); - return n.name_processed; -} diff --git a/libpp/name_storage.h b/libpp/name_storage.h deleted file mode 100644 index 0e278cb..0000000 --- a/libpp/name_storage.h +++ /dev/null @@ -1,102 +0,0 @@ -/** - * @file name_storage.h - * Type-safe unique storage of global names (filenames and symbols) - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#ifndef NAME_STORAGE_H -#define NAME_STORAGE_H - -#include <string> - -#include "unique_storage.h" - -/// store original name and processed name -struct stored_name { - stored_name(std::string const & n = std::string()) - : name(n) {} - - bool operator<(stored_name const & rhs) const { - return name < rhs.name; - } - - std::string name; - mutable std::string name_processed; -}; - - -/// partial specialization for unique storage of names -template <typename I> struct name_storage : unique_storage<I, stored_name> { - - typedef typename unique_storage<I, stored_name>::id_value id_value; - - std::string const & name(id_value const & id) const { - return unique_storage<I, stored_name>::get(id).name; - }; -}; - - -class debug_name_tag; -/// a debug filename -typedef name_storage<debug_name_tag>::id_value debug_name_id; - -/// class storing a set of shared debug name (source filename) -struct debug_name_storage : name_storage<debug_name_tag> { - /// return the basename for the given ID - std::string const & basename(debug_name_id id) const; -}; - - -class image_name_tag; -/// an image name -typedef name_storage<image_name_tag>::id_value image_name_id; - -/// class storing a set of shared image name -struct image_name_storage : name_storage<image_name_tag> { - /// return the basename name for the given ID - std::string const & basename(image_name_id) const; -}; - - -class symbol_name_tag; -/// a (demangled) symbol -typedef name_storage<symbol_name_tag>::id_value symbol_name_id; - -/// class storing a set of shared symbol name -struct symbol_name_storage : name_storage<symbol_name_tag> { - /// return the demangled name for the given ID - std::string const & demangle(symbol_name_id id) const; -}; - - -/// for images -extern image_name_storage image_names; - -/// for debug filenames i.e. source filename -extern debug_name_storage debug_names; - -/// for symbols -extern symbol_name_storage symbol_names; - - -/** - * debug name specialisation for comparison. - * - * We compare by name rather by id since what user will see are - * filename and when the criteria "samples count" give identical - * result it's better to obtain result sorted by the user visible - * property filename rather than by an obscure, invisible from user - * point of view, file identifier property - */ -template<> inline bool -debug_name_id::operator<(debug_name_id const & rhs) const -{ - return debug_names.name(*this) < debug_names.name(rhs); -} - -#endif /* !NAME_STORAGE_H */ diff --git a/libpp/op_header.cpp b/libpp/op_header.cpp deleted file mode 100644 index f0bacac..0000000 --- a/libpp/op_header.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/** - * @file op_header.cpp - * various free function acting on a sample file header - * - * @remark Copyright 2004 OProfile authors - * @remark Read the file COPYING - * - * @author John Levon - * @author Philippe Elie - */ - -#include <iostream> -#include <cstdlib> -#include <iomanip> -#include <set> -#include <sstream> - -#include "op_exception.h" -#include "odb.h" -#include "op_cpu_type.h" -#include "op_file.h" -#include "op_header.h" -#include "op_events.h" -#include "string_manip.h" - -using namespace std; - -void op_check_header(opd_header const & h1, opd_header const & h2, - string const & filename) -{ - if (h1.mtime != h2.mtime) { - ostringstream os; - os << "header timestamps are different (" - << h1.mtime << ", " << h2.mtime << ") for " - << filename << "\n"; - throw op_fatal_error(os.str()); - } - - if (h1.is_kernel != h2.is_kernel) { - ostringstream os; - os << "header is_kernel flags are different for " - << filename << "\n"; - throw op_fatal_error(os.str()); - } - - if (h1.anon_start != h2.anon_start) { - ostringstream os; - os << "header anon_start flags are different for " - << filename << "\n"; - throw op_fatal_error(os.str()); - } - - // Note that we don't check CPU speed since that can vary - // freely on the same machine -} - - -namespace { - -set<string> warned_files; - -} - - -void check_mtime(string const & file, opd_header const & header) -{ - time_t const newmtime = op_get_mtime(file.c_str()); - - if (newmtime == header.mtime) - return; - - if (warned_files.find(file) != warned_files.end()) - return; - - warned_files.insert(file); - - // Files we couldn't get mtime of have zero mtime - if (!header.mtime) { - cerr << "warning: could not check that the binary file " - << file << " has not been modified since " - "the profile was taken. Results may be inaccurate.\n"; - } else { - static bool warned_already = false; - - cerr << "warning: the last modified time of the binary file " - "does not match that of the sample file for " << file - << "\n"; - - if (!warned_already) { - cerr << "Either this is the wrong binary or the binary " - "has been modified since the sample file was created.\n"; - warned_already = true; - } - } -} - - -opd_header const read_header(string const & sample_filename) -{ - odb_t samples_db; - - int rc = odb_open(&samples_db, sample_filename.c_str(), ODB_RDONLY, - sizeof(struct opd_header)); - - if (rc) - throw op_fatal_error(sample_filename + ": " + strerror(rc)); - - opd_header head = *static_cast<opd_header *>(samples_db.data->base_memory); - - odb_close(&samples_db); - - return head; -} - - -namespace { - -string const op_print_event(op_cpu cpu_type, u8 type, u16 um, u32 count) -{ - string str; - - if (cpu_type == CPU_TIMER_INT) { - str += "Profiling through timer interrupt"; - return str; - } - - struct op_event * event = op_find_event(cpu_type, type); - - if (!event) { - cerr << "Could not locate event " << int(type) << endl; - return str; - } - - char const * um_desc = 0; - - for (size_t i = 0; i < event->unit->num; ++i) { - if (event->unit->um[i].value == um) - um_desc = event->unit->um[i].desc; - } - - str += string("Counted ") + event->name; - str += string(" events (") + event->desc + ")"; - - if (cpu_type != CPU_RTC) { - str += " with a unit mask of 0x"; - - ostringstream ss; - ss << hex << setw(2) << setfill('0') << unsigned(um); - str += ss.str(); - - str += " ("; - str += um_desc ? um_desc : "multiple flags"; - str += ")"; - } - - str += " count " + op_lexical_cast<string>(count); - return str; -} - -} - - -string const describe_header(opd_header const & header) -{ - op_cpu cpu = static_cast<op_cpu>(header.cpu_type); - - return op_print_event(cpu, header.ctr_event, - header.ctr_um, header.ctr_count); -} - - -string const describe_cpu(opd_header const & header) -{ - op_cpu cpu = static_cast<op_cpu>(header.cpu_type); - - string str; - str += string("CPU: ") + op_get_cpu_type_str(cpu); - str += ", speed "; - - ostringstream ss; - ss << header.cpu_speed; - str += ss.str() + " MHz (estimated)"; - return str; -} diff --git a/libpp/op_header.h b/libpp/op_header.h deleted file mode 100644 index 0e109bc..0000000 --- a/libpp/op_header.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file op_header.h - * various free function acting on a sample file header - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author John Levon - * @author Philippe Elie - */ - -#ifndef OP_HEADER_H -#define OP_HEADER_H - -#include <iosfwd> -#include <string> - -#include "op_sample_file.h" - -/** - * @param h1 sample file header - * @param h2 sample file header - * @param filename sample filename - * - * check that the h1 and h2 are coherent (same size, same mtime etc.) - * all error are fatal - */ -void op_check_header(opd_header const & h1, opd_header const & h2, - std::string const & filename); - -/** - * check mtime of samples file header against file - * all error are fatal - */ -void check_mtime(std::string const & file, opd_header const & header); - -/** - * @param sample_filename the sample to open - * - * Return the header of this sample file. Only the magic number is checked - * the version number is not checked. All error are fatal - */ -opd_header const read_header(std::string const & sample_filename); - -/** - * output a readable form of header, this don't include the cpu type - * and speed - */ -std::string const describe_header(opd_header const & header); - -/// output a readable form of cpu type and speed -std::string const describe_cpu(opd_header const & header); - -#endif // OP_HEADER_H diff --git a/libpp/parse_filename.cpp b/libpp/parse_filename.cpp deleted file mode 100644 index 1593b94..0000000 --- a/libpp/parse_filename.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/** - * @file parse_filename.cpp - * Split a sample filename into its constituent parts - * - * @remark Copyright 2003 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - */ - -#include <stdexcept> -#include <vector> -#include <string> -#include <iostream> - -#include "parse_filename.h" -#include "file_manip.h" -#include "string_manip.h" - -using namespace std; - -namespace { - -// PP:3.19 event_name.count.unitmask.tgid.tid.cpu -parsed_filename parse_event_spec(string const & event_spec) -{ - typedef vector<string> parts_type; - typedef parts_type::size_type size_type; - - size_type const nr_parts = 6; - - parts_type parts = separate_token(event_spec, '.'); - - if (parts.size() != nr_parts) { - throw invalid_argument("parse_event_spec(): bad event specification: " + event_spec); - } - - for (size_type i = 0; i < nr_parts ; ++i) { - if (parts[i].empty()) { - throw invalid_argument("parse_event_spec(): bad event specification: " + event_spec); - } - } - - parsed_filename result; - - size_type i = 0; - result.event = parts[i++]; - result.count = parts[i++]; - result.unitmask = parts[i++]; - result.tgid = parts[i++]; - result.tid = parts[i++]; - result.cpu = parts[i++]; - - return result; -} - - -/** - * @param component path component - * - * remove from path_component all directory left to {root}, {kern} or {anon} - */ -void remove_base_dir(vector<string> & path) -{ - vector<string>::iterator it; - for (it = path.begin(); it != path.end(); ++it) { - if (*it == "{root}" || *it == "{kern}" || *it == "{anon}") - break; - } - - path.erase(path.begin(), it); -} - - -/// Handle an anon region. Pretty print the details. -string const parse_anon(string const & str) -{ - vector<string> parts = separate_token(str, '.'); - if (parts.size() != 3) - throw invalid_argument("parse_anon() invalid name: " + str); - - string ret = "anon (tgid:"; - ret += parts[0] + " range:" + parts[1] + "-" + parts[2] + ")"; - return ret; -} - - -} // anonymous namespace - - -/* - * valid filename are variations on: - * - * {kern}/name/event_spec - * {root}/path/to/bin/{dep}/{root}/path/to/bin/event_spec - * {root}/path/to/bin/{dep}/{anon}/pid.start.end/event_spec - * {root}/path/to/bin/{dep}/{kern}/name/event_spec - * {root}/path/to/bin/{dep}/{root}/path/to/bin/{cg}/{root}/path/to/bin/event_spec - - * - * where /name/ denote a unique path component - */ -parsed_filename parse_filename(string const & filename) -{ - string::size_type pos = filename.find_last_of('/'); - if (pos == string::npos) { - throw invalid_argument("parse_filename() invalid filename: " + - filename); - } - string event_spec = filename.substr(pos + 1); - string filename_spec = filename.substr(0, pos); - - parsed_filename result = parse_event_spec(event_spec); - - result.filename = filename; - - vector<string> path = separate_token(filename_spec, '/'); - - remove_base_dir(path); - - // pp_interface PP:3.19 to PP:3.23 path must start either with {root} - // or {kern} and we must found at least 2 component, remove_base_dir() - // return an empty path if {root} or {kern} are not found - if (path.size() < 2) { - throw invalid_argument("parse_filename() invalid filename: " + - filename); - } - - size_t i; - for (i = 1 ; i < path.size() ; ++i) { - if (path[i] == "{dep}") - break; - - result.image += "/" + path[i]; - } - - if (i == path.size()) { - throw invalid_argument("parse_filename() invalid filename: " + - filename); - } - - // skip "{dep}" - ++i; - - // PP:3.19 {dep}/ must be followed by {kern}/, {root}/ or {anon}/ - if (path[i] != "{kern}" && path[i] != "{root}" && path[i] != "{anon}") { - throw invalid_argument("parse_filename() invalid filename: " + - filename); - } - - bool anon = path[i] == "{anon}"; - - // skip "{root}", "{kern}" or "{anon}" - ++i; - - for (; i < path.size(); ++i) { - if (path[i] == "{cg}") - break; - - if (anon) { - result.lib_image = parse_anon(path[i++]); - break; - } - result.lib_image += "/" + path[i]; - } - - if (i == path.size()) - return result; - - // skip "{cg}" - ++i; - if (i == path.size() || - (path[i] != "{kern}" && path[i] != "{root}" && path[i] != "{anon}")) { - throw invalid_argument("parse_filename() invalid filename: " - + filename); - } - - // skip "{root}", "{kern}" or "{anon}" - anon = path[i] == "{anon}"; - ++i; - - if (anon) { - result.cg_image = parse_anon(path[i++]); - } else { - for (; i < path.size(); ++i) - result.cg_image += "/" + path[i]; - } - - return result; -} - -bool parsed_filename::profile_spec_equal(parsed_filename const & parsed) -{ - return event == parsed.event && - count == parsed.count && - unitmask == parsed.unitmask && - tgid == parsed.tgid && - tid == parsed.tid && - cpu == parsed.tid; -} - -ostream & operator<<(ostream & out, parsed_filename const & data) -{ - out << data.filename << endl; - out << data.image << " " << data.lib_image << " " - << data.event << " " << data.count << " " - << data.unitmask << " " << data.tgid << " " - << data.tid << " " << data.cpu << endl; - - return out; -} diff --git a/libpp/parse_filename.h b/libpp/parse_filename.h deleted file mode 100644 index 79c06aa..0000000 --- a/libpp/parse_filename.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file parse_filename.h - * Split a sample filename into its constituent parts - * - * @remark Copyright 2003 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - */ - -#ifndef PARSE_FILENAME_H -#define PARSE_FILENAME_H - -#include <string> - -/** - * a convenience class to store result of parse_filename() - */ -struct parsed_filename -{ - std::string image; - std::string lib_image; - /// destination image for call graph file, empty if this sample - /// file is not a callgraph file. - std::string cg_image; - std::string event; - std::string count; - std::string unitmask; - std::string tgid; - std::string tid; - std::string cpu; - - /// return true if the profile specification are identical. - bool profile_spec_equal(parsed_filename const & parsed); - - /** - * the original sample filename from which the - * above components are built - */ - std::string filename; -}; - - -/// debugging helper -std::ostream & operator<<(std::ostream &, parsed_filename const &); - - -/** - * parse a sample filename - * @param filename in: a sample filename - * - * filename is split into constituent parts, the lib_image is optional - * and can be empty on successfull call. All other error are fatal. - * Filenames are encoded as according to PP:3.19 to PP:3.25 - * - * all errors throw an std::invalid_argument exception - */ -parsed_filename parse_filename(std::string const & filename); - -#endif /* !PARSE_FILENAME_H */ diff --git a/libpp/populate.cpp b/libpp/populate.cpp deleted file mode 100644 index 450673a..0000000 --- a/libpp/populate.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @file populate.cpp - * Fill up a profile_container from inverted profiles - * - * @remark Copyright 2003 OProfile authors - * @remark Read the file COPYING - * - * @author John Levon - * @author Philippe Elie - */ - -#include "profile.h" -#include "profile_container.h" -#include "arrange_profiles.h" -#include "op_bfd.h" -#include "op_header.h" -#include "populate.h" - -#include "image_errors.h" - -#include <iostream> - -using namespace std; - -namespace { - -/// load merged files for one set of sample files -bool -populate_from_files(profile_t & profile, op_bfd const & abfd, - list<profile_sample_files> const & files) -{ - list<profile_sample_files>::const_iterator it = files.begin(); - list<profile_sample_files>::const_iterator const end = files.end(); - - bool found = false; - // we can't handle cg files here obviously - for (; it != end; ++it) { - // A bit ugly but we must accept silently empty sample filename - // since we can create a profile_sample_files for cg file only - // (i.e no sample to the binary) - if (!it->sample_filename.empty()) { - profile.add_sample_file(it->sample_filename); - profile.set_offset(abfd); - found = true; - } - } - - return found; -} - -} // anon namespace - - -void -populate_for_image(string const & archive_path, profile_container & samples, - inverted_profile const & ip, string_filter const & symbol_filter, - bool * has_debug_info) -{ - bool ok = ip.error == image_ok; - - op_bfd abfd(archive_path, ip.image, symbol_filter, ok); - if (!ok && ip.error == image_ok) - ip.error = image_format_failure; - - if (ip.error == image_format_failure) - report_image_error(ip, false); - - opd_header header; - - bool found = false; - for (size_t i = 0; i < ip.groups.size(); ++i) { - list<image_set>::const_iterator it - = ip.groups[i].begin(); - list<image_set>::const_iterator const end - = ip.groups[i].end(); - - // we can only share a profile_t amongst each - // image_set's files - this is because it->app_image - // changes, and the .add() would mis-attribute - // to the wrong app_image otherwise - for (; it != end; ++it) { - profile_t profile; - if (populate_from_files(profile, abfd, it->files)) { - header = profile.get_header(); - samples.add(profile, abfd, it->app_image, i); - found = true; - } - } - } - - // we shouldn't check/warn if an archive is used - if (archive_path.empty() && found == true && ip.error == image_ok) - check_mtime(abfd.get_filename(), header); - - if (has_debug_info) - *has_debug_info = abfd.has_debug_info(); -} diff --git a/libpp/populate.h b/libpp/populate.h deleted file mode 100644 index 082136f..0000000 --- a/libpp/populate.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @file populate.h - * Fill up a profile_container from inverted profiles - * - * @remark Copyright 2003 OProfile authors - * @remark Read the file COPYING - * - * @author John Levon - * @author Philippe Elie - */ - -#ifndef POPULATE_H -#define POPULATE_H - -class profile_container; -class inverted_profile; -class string_filter; - - -/// Load all sample file information for exactly one binary image. -void -populate_for_image(std::string const & archive_path, - profile_container & samples, inverted_profile const & ip, - string_filter const & symbol_filter, bool * has_debug_info); - -#endif /* POPULATE_H */ diff --git a/libpp/profile.cpp b/libpp/profile.cpp deleted file mode 100644 index a0007dd..0000000 --- a/libpp/profile.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/** - * @file profile.cpp - * Encapsulation for samples files over all profile classes - * belonging to the same binary image - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#include <unistd.h> - -#include <iostream> -#include <string> -#include <sstream> - -#include <cerrno> - -#include "op_exception.h" -#include "op_header.h" -#include "op_config.h" -#include "op_sample_file.h" -#include "profile.h" -#include "op_bfd.h" -#include "cverb.h" - -using namespace std; - -profile_t::profile_t() - : start_offset(0) -{ -} - - -// static member -unsigned int profile_t::sample_count(string const & filename) -{ - odb_t samples_db; - - open_sample_file(filename, samples_db); - - unsigned int count = 0; - - odb_node_nr_t node_nr, pos; - odb_node_t * node = odb_get_iterator(&samples_db, &node_nr); - for (pos = 0; pos < node_nr; ++pos) { - if (node[pos].key) - count += node[pos].value; - } - - odb_close(&samples_db); - - return count; -} - -//static member -void profile_t::open_sample_file(string const & filename, odb_t & db) -{ - int rc = odb_open(&db, filename.c_str(), ODB_RDONLY, - sizeof(struct opd_header)); - - if (rc) - throw op_fatal_error(filename + ": " + strerror(rc)); - - opd_header const & head = - *static_cast<opd_header *>(odb_get_data(&db)); - - if (head.version != OPD_VERSION) { - ostringstream os; - os << "oprofpp: samples files version mismatch, are you " - << "running a daemon and post-profile tools with version " - << "mismatch ?\n"; - throw op_fatal_error(os.str()); - } -} - -void profile_t::add_sample_file(string const & filename) -{ - odb_t samples_db; - - open_sample_file(filename, samples_db); - - opd_header const & head = - *static_cast<opd_header *>(odb_get_data(&samples_db)); - - // if we already read a sample file header pointer is non null - if (file_header.get()) - op_check_header(head, *file_header, filename); - - file_header.reset(new opd_header(head)); - - odb_node_nr_t node_nr, pos; - odb_node_t * node = odb_get_iterator(&samples_db, &node_nr); - - for (pos = 0; pos < node_nr; ++pos) { - if (node[pos].key) { - ordered_samples_t::iterator it = - ordered_samples.find(node[pos].key); - if (it != ordered_samples.end()) { - it->second += node[pos].value; - } else { - ordered_samples_t::value_type - val(node[pos].key, node[pos].value); - ordered_samples.insert(val); - } - } - } - - odb_close(&samples_db); -} - - -void profile_t::set_offset(op_bfd const & abfd) -{ - opd_header const & header = get_header(); - if (header.anon_start || header.is_kernel) - start_offset = abfd.get_start_offset(header.anon_start); - cverb << (vdebug) << "start_offset is now " << start_offset << endl; -} - - -profile_t::iterator_pair -profile_t::samples_range(odb_key_t start, odb_key_t end) const -{ - // Check the start position isn't before start_offset: - // this avoids wrapping/underflowing start/end. - // This can happen on e.g. ARM kernels, where .init is - // mapped before .text - we just have to skip any such - // .init symbols. - if (start < start_offset) { - return make_pair(const_iterator(ordered_samples.end(), 0), - const_iterator(ordered_samples.end(), 0)); - } - - start -= start_offset; - end -= start_offset; - - // sanity check if start > end caller will enter into an infinite loop - if (start > end) { - throw op_fatal_error("profile_t::samples_range(): start > end" - " something wrong with kernel or module layout ?\n" - "please report problem to " - "oprofile-list@lists.sourceforge.net"); - } - - ordered_samples_t::const_iterator first = - ordered_samples.lower_bound(start); - ordered_samples_t::const_iterator last = - ordered_samples.lower_bound(end); - - return make_pair(const_iterator(first, start_offset), - const_iterator(last, start_offset)); -} - - -profile_t::iterator_pair profile_t::samples_range() const -{ - ordered_samples_t::const_iterator first = ordered_samples.begin(); - ordered_samples_t::const_iterator last = ordered_samples.end(); - - return make_pair(const_iterator(first, start_offset), - const_iterator(last, start_offset)); -} diff --git a/libpp/profile.h b/libpp/profile.h deleted file mode 100644 index 237e354..0000000 --- a/libpp/profile.h +++ /dev/null @@ -1,176 +0,0 @@ -/** - * @file profile.h - * Encapsulation for samples files over all profile classes - * belonging to the same binary image - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#ifndef PROFILE_H -#define PROFILE_H - -#include <string> -#include <map> -#include <iterator> - -#include "odb.h" -#include "op_types.h" -#include "utility.h" - -class opd_header; -class op_bfd; - -/** - * Class containing a single sample file contents. - * i.e. set of count values for VMA offsets for - * a particular binary. - */ -class profile_t : noncopyable { -public: - /** - * profile_t - construct an empty profile_t object - */ - profile_t(); - - /// return true if no sample file has been loaded - bool empty() const { return !file_header.get(); } - - /// return the header of the last opened samples file - opd_header const & get_header() const { - return *file_header; - } - - /** - * count samples count w/o recording them - * @param filename sample filename - * - * convenience interface for raw access to sample count w/o recording - * them. It's placed here so all access to samples files go through - * profile_t static or non static member. - */ - static unsigned int sample_count(std::string const & filename); - - /** - * cumulate sample file to our container of samples - * @param filename sample file name - * - * store samples for one sample file, sample file header is sanitized. - * - * all error are fatal - */ - void add_sample_file(std::string const & filename); - - /// Set an appropriate start offset, see comments below. - void set_offset(op_bfd const & abfd); - - class const_iterator; - typedef std::pair<const_iterator, const_iterator> iterator_pair; - - /** - * @param start start offset - * @param end end offset - * - * return an iterator pair to [start, end) range - */ - iterator_pair - samples_range(odb_key_t start, odb_key_t end) const; - - /// return a pair of iterator for all samples - iterator_pair samples_range() const; - -private: - /// helper for sample_count() and add_sample_file(). All error launch - /// an exception. - static void - open_sample_file(std::string const & filename, odb_t &); - - /// copy of the samples file header - scoped_ptr<opd_header> file_header; - - /// storage type for samples sorted by eip - typedef std::map<odb_key_t, odb_value_t> ordered_samples_t; - - /** - * Samples are stored in hash table, iterating over hash table don't - * provide any ordering, the above count() interface rely on samples - * ordered by eip. This map is only a temporary storage where samples - * are ordered by eip. - */ - ordered_samples_t ordered_samples; - - /** - * For certain profiles, such as kernel/modules, and anon - * regions with a matching binary, this value is non-zero, - * and represents the file offset of the relevant section. - * - * For kernel profiles, this is done because we use the information - * provided in /proc/ksyms, which only gives the mapped position of - * .text, and the symbol _text from vmlinux. This value is used to fix - * up the sample offsets for kernel code as a result of this difference - * - * In user-space samples, the sample offset is from the start of the - * mapped file, as seen in /proc/pid/maps. This is fine for - * mappings of permanent files, but with anon mappings, we need - * to adjust the key values to be a file offset against the - * *binary* (if there is one). This can obviously be different. - * So we pass our anon mapping start VMA to op_bfd, which looks - * for a section with that VMA, then returns the section's - * filepos. So all is good. - * - * Finally, note that for cg we can't use this inside the - * profile_t, as we're storing two offsets in the key value. So - * we do it later in that case. - * - * Phew. - */ - u32 start_offset; -}; - - -// It will be easier to derive profile_t::const_iterator from -// std::iterator<std::input_iterator_tag, unsigned int> but this doesn't -// work for gcc <= 2.95 so we provide the neccessary typedef in the hard way. -// See ISO C++ 17.4.3.1 § 1 and 14.7.3 § 9. -namespace std { - template <> - struct iterator_traits<profile_t::const_iterator> { - typedef ptrdiff_t difference_type; - typedef unsigned int value_type; - typedef unsigned int * pointer; - typedef unsigned int & reference; - typedef input_iterator_tag iterator_category; - }; -} - - -class profile_t::const_iterator -{ - typedef ordered_samples_t::const_iterator iterator_t; -public: - const_iterator() : start_offset(0) {} - const_iterator(iterator_t it_, u32 start_offset_) - : it(it_), start_offset(start_offset_) {} - - unsigned int operator*() const { return it->second; } - const_iterator & operator++() { ++it; return *this; } - - odb_key_t vma() const { return it->first + start_offset; } - unsigned int count() const { return **this; } - - bool operator!=(const_iterator const & rhs) const { - return it != rhs.it; - } - bool operator==(const_iterator const & rhs) const { - return it == rhs.it; - } - -private: - iterator_t it; - u32 start_offset; -}; - -#endif /* !PROFILE_H */ diff --git a/libpp/profile_container.cpp b/libpp/profile_container.cpp deleted file mode 100644 index b0422d1..0000000 --- a/libpp/profile_container.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/** - * @file profile_container.cpp - * profile file container - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#include <set> -#include <vector> -#include <string> -#include <iostream> -#include <algorithm> -#include <numeric> - -#include "symbol.h" -#include "op_header.h" -#include "profile.h" -#include "symbol_functors.h" -#include "profile_container.h" -#include "sample_container.h" -#include "symbol_container.h" - -using namespace std; - -namespace { - -struct filename_by_samples { - filename_by_samples(debug_name_id id, double percent_) - : filename(id), percent(percent_) - {} - - bool operator<(filename_by_samples const & lhs) const { - if (percent != lhs.percent) - return percent < lhs.percent; - return filename < lhs.filename; - } - - debug_name_id filename; - // ratio of samples which belongs to this filename. - double percent; -}; - -} // anon namespace - - -profile_container::profile_container(bool debug_info_, bool need_details_) - : - symbols(new symbol_container), - samples(new sample_container), - debug_info(debug_info_), - need_details(need_details_) -{ -} - - -profile_container::~profile_container() -{ -} - - -// Post condition: -// the symbols/samples are sorted by increasing vma. -// the range of sample_entry inside each symbol entry are valid -// the samples_by_file_loc member var is correctly setup. -void profile_container::add(profile_t const & profile, - op_bfd const & abfd, string const & app_name, - size_t pclass) -{ - string const image_name = abfd.get_filename(); - - for (symbol_index_t i = 0; i < abfd.syms.size(); ++i) { - - unsigned long start, end; - symbol_entry symb_entry; - - abfd.get_symbol_range(i, start, end); - - profile_t::iterator_pair p_it = - profile.samples_range(start, end); - - u32 count = accumulate(p_it.first, p_it.second, 0); - - // skip entries with no samples - if (count == 0) - continue; - - symb_entry.sample.counts[pclass] = count; - total_count[pclass] += count; - - symb_entry.size = end - start; - - symb_entry.name = symbol_names.create(abfd.syms[i].name()); - - symb_entry.sample.file_loc.linenr = 0; - if (debug_info) { - string filename; - if (abfd.get_linenr(i, start, filename, - symb_entry.sample.file_loc.linenr)) { - symb_entry.sample.file_loc.filename = - debug_names.create(filename); - } - } - - symb_entry.image_name = image_names.create(image_name); - symb_entry.app_name = image_names.create(app_name); - - bfd_vma base_vma = abfd.syms[i].vma(); - - symb_entry.sample.vma = abfd.sym_offset(i, start) + base_vma; - - symbol_entry const * symbol = symbols->insert(symb_entry); - - if (need_details) { - add_samples(abfd, i, p_it, symbol, pclass); - } - } -} - - -void -profile_container::add_samples(op_bfd const & abfd, symbol_index_t sym_index, - profile_t::iterator_pair const & p_it, - symbol_entry const * symbol, size_t pclass) -{ - bfd_vma base_vma = abfd.syms[sym_index].vma(); - - profile_t::const_iterator it; - for (it = p_it.first; it != p_it.second ; ++it) { - sample_entry sample; - - sample.counts[pclass] = it.count(); - - sample.file_loc.linenr = 0; - if (debug_info) { - string filename; - if (abfd.get_linenr(sym_index, it.vma(), filename, - sample.file_loc.linenr)) { - sample.file_loc.filename = - debug_names.create(filename); - } - } - - sample.vma = abfd.sym_offset(sym_index, it.vma()) + base_vma; - - samples->insert(symbol, sample); - } -} - - -symbol_collection const -profile_container::select_symbols(symbol_choice & choice) const -{ - symbol_collection result; - - double const threshold = choice.threshold / 100.0; - - symbol_container::symbols_t::iterator it = symbols->begin(); - symbol_container::symbols_t::iterator const end = symbols->end(); - - for (; it != end; ++it) { - if (choice.match_image - && (image_names.name(it->image_name) != choice.image_name)) - continue; - - double const percent = - op_ratio(it->sample.counts[0], total_count[0]); - - if (percent >= threshold) { - result.push_back(&*it); - - choice.hints = it->output_hint(choice.hints); - } - } - - return result; -} - - -vector<debug_name_id> const -profile_container::select_filename(double threshold) const -{ - set<debug_name_id> filename_set; - - threshold /= 100.0; - - // Trying to iterate on symbols to create the set of filenames which - // contain sample does not work: a symbol can contain samples and this - // symbol is in a source file that contain zero sample because only - // inline function in this source file contains samples. - sample_container::samples_iterator sit = samples->begin(); - sample_container::samples_iterator const send = samples->end(); - - for (; sit != send; ++sit) { - debug_name_id name_id = sit->second.file_loc.filename; - if (name_id.set()) { - filename_set.insert(name_id); - } - } - - // Give a sort order on filename for the selected pclass. - vector<filename_by_samples> file_by_samples; - - set<debug_name_id>::const_iterator it = filename_set.begin(); - set<debug_name_id>::const_iterator const end = filename_set.end(); - for (; it != end; ++it) { - // FIXME: is samples_count() the right interface now ? - count_array_t counts = samples_count(*it); - - double const ratio = op_ratio(counts[0], total_count[0]); - filename_by_samples const f(*it, ratio); - - file_by_samples.push_back(f); - } - - // now sort the file_by_samples entry. - sort(file_by_samples.begin(), file_by_samples.end()); - - // 2.91.66 doesn't like const_reverse_iterator in this context - vector<filename_by_samples>::reverse_iterator cit - = file_by_samples.rbegin(); - vector<filename_by_samples>::reverse_iterator const cend - = file_by_samples.rend(); - - vector<debug_name_id> result; - for (; cit != cend; ++cit) { - if (cit->percent >= threshold) - result.push_back(cit->filename); - } - - return result; -} - - -count_array_t profile_container::samples_count() const -{ - return total_count; -} - - -// Rest here are delegated to our private implementation. - -symbol_entry const * -profile_container::find_symbol(string const & image_name, bfd_vma vma) const -{ - return symbols->find_by_vma(image_name, vma); -} - - -symbol_entry const * -profile_container::find_symbol(debug_name_id filename, size_t linenr) const -{ - return symbols->find(filename, linenr); -} - - -sample_entry const * -profile_container::find_sample(symbol_entry const * symbol, bfd_vma vma) const -{ - return samples->find_by_vma(symbol, vma); -} - - -count_array_t profile_container::samples_count(debug_name_id filename_id) const -{ - return samples->accumulate_samples(filename_id); -} - - -count_array_t profile_container::samples_count(debug_name_id filename, - size_t linenr) const -{ - return samples->accumulate_samples(filename, linenr); -} - - -sample_container::samples_iterator -profile_container::begin(symbol_entry const * symbol) const -{ - return samples->begin(symbol); -} - - -sample_container::samples_iterator -profile_container::end(symbol_entry const * symbol) const -{ - return samples->end(symbol); -} - - -sample_container::samples_iterator profile_container::begin() const -{ - return samples->begin(); -} - - -sample_container::samples_iterator profile_container::end() const -{ - return samples->end(); -} - -symbol_entry const * profile_container::find(symbol_entry const & symbol) const -{ - return symbols->find(symbol); -} - -symbol_container::symbols_t::iterator profile_container::begin_symbol() const -{ - return symbols->begin(); -} - -symbol_container::symbols_t::iterator profile_container::end_symbol() const -{ - return symbols->end(); -} diff --git a/libpp/profile_container.h b/libpp/profile_container.h deleted file mode 100644 index 153ecfc..0000000 --- a/libpp/profile_container.h +++ /dev/null @@ -1,175 +0,0 @@ -/** - * @file profile_container.h - * Container associating symbols and samples - * - * @remark Copyright 2002, 2003 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#ifndef PROFILE_CONTAINER_H -#define PROFILE_CONTAINER_H - -#include <string> -#include <vector> - -#include "profile.h" -#include "utility.h" -#include "op_bfd.h" -#include "sample_container.h" -#include "symbol_container.h" -#include "format_flags.h" - -class string_filter; -class symbol_entry; -class sample_entry; - -/** - * Store multiple samples files belonging to the same profiling session. - * This is the main container capable of holding the profiles for arbitrary - * binary images and arbitrary profile classes. - */ -class profile_container : noncopyable { -public: - /** - * Build an object to store information on samples. All parameters - * acts as hint for what you will request after recording samples and - * so allow optimizations during recording the information. - * - * @param debug_info If true line numbers and source files are recorded. - * - * @param need_details If true if we need to record all samples or to - * to record them at symbol level. - */ - profile_container(bool debug_info, bool need_details); - - ~profile_container(); - - /** - * add() - record symbols/samples in the underlying container - * - * @param profile the samples files container - * @param abfd the associated bfd object - * @param app_name the owning application name of sample - * @param pclass the profile class to add results for - * - * add() is an helper for delayed ctor. Take care you can't safely - * make any call to add after any other member function call. - * Obviously you can add only samples files which are coherent (same - * sampling rate, same events etc.) - */ - void add(profile_t const & profile, op_bfd const & abfd, - std::string const & app_name, size_t pclass); - - /// Find a symbol from its image_name, vma, return zero if no symbol - /// for this image at this vma - symbol_entry const * find_symbol(std::string const & image_name, - bfd_vma vma) const; - - /// Find a symbol from its filename, linenr, return zero if no symbol - /// at this location - symbol_entry const * find_symbol(debug_name_id filename, - size_t linenr) const; - - /// Find a sample by its symbol, vma, return zero if there is no sample - /// at this vma - sample_entry const * find_sample(symbol_entry const * symbol, - bfd_vma vma) const; - - /// Find a symbol. Return NULL if not found. - symbol_entry const * find(symbol_entry const & symbol) const; - - /// used for select_symbols() - struct symbol_choice { - symbol_choice() - : hints(cf_none), threshold(0.0), match_image(false) {} - - /// hints filled in - column_flags hints; - /// percentage threshold - double threshold; - /// match the image name only - bool match_image; - /// owning image name - std::string image_name; - }; - - /** - * select_symbols - create a set of symbols sorted by sample count - * @param choice parameters to use/fill in when selecting - */ - symbol_collection const select_symbols(symbol_choice & choice) const; - - /// Like select_symbols for filename without allowing sort by vma. - std::vector<debug_name_id> const select_filename(double threshold) const; - - /// return the total number of samples - count_array_t samples_count() const; - - /// Get the samples count which belongs to filename. Return 0 if - /// no samples found. - count_array_t samples_count(debug_name_id filename_id) const; - /// Get the samples count which belongs to filename, linenr. Return - /// 0 if no samples found. - count_array_t samples_count(debug_name_id filename, - size_t linenr) const; - - /// return an iterator to the first symbol - symbol_container::symbols_t::iterator begin_symbol() const; - /// return an iterator to the last symbol - symbol_container::symbols_t::iterator end_symbol() const; - - /// return iterator to the first samples - sample_container::samples_iterator begin() const; - /// return iterator to the last samples - sample_container::samples_iterator end() const; - - /// return iterator to the first samples for this symbol - sample_container::samples_iterator begin(symbol_entry const *) const; - /// return iterator to the last samples for this symbol - sample_container::samples_iterator end(symbol_entry const *) const; - -private: - /// helper for add() - void add_samples(op_bfd const & abfd, symbol_index_t sym_index, - profile_t::iterator_pair const &, - symbol_entry const * symbol, size_t pclass); - - /** - * create an unique artificial symbol for an offset range. The range - * is only a hint of the maximum size of the created symbol. We - * give to the symbol an unique name as ?image_file_name#order and - * a range up to the nearest of syms or for the whole range if no - * syms exist after the start offset. the end parameter is updated - * to reflect the symbol range. - * - * The rationale here is to try to create symbols for alignment between - * function as little as possible and to create meaningfull symbols - * for special case such image w/o symbol. - */ - std::string create_artificial_symbol(op_bfd const & abfd, u32 start, - u32 & end, size_t & order); - - /// The symbols collected by pp tools sorted by increased vma, provide - /// also a sort order on samples count for each profile class - scoped_ptr<symbol_container> symbols; - /// The samples count collected by pp tools sorted by increased vma, - /// provide also a sort order on (filename, linenr) - scoped_ptr<sample_container> samples; - /// build() must count samples count for each profile class so cache it - /// here since user of profile_container often need it later. - count_array_t total_count; - - /** - * Optimization hints for what information we are going to need, - * see the explanation in profile_container() - */ - //@{ - bool debug_info; - bool need_details; - //@} -}; - -#endif /* !PROFILE_CONTAINER_H */ diff --git a/libpp/profile_spec.cpp b/libpp/profile_spec.cpp deleted file mode 100644 index f244e7c..0000000 --- a/libpp/profile_spec.cpp +++ /dev/null @@ -1,447 +0,0 @@ -/** - * @file profile_spec.cpp - * Contains a PP profile specification - * - * @remark Copyright 2003 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - */ - -#include <algorithm> -#include <set> -#include <sstream> -#include <iterator> -#include <iostream> - -#include "file_manip.h" -#include "op_config.h" -#include "profile_spec.h" -#include "string_manip.h" -#include "glob_filter.h" -#include "locate_images.h" -#include "op_exception.h" - -using namespace std; - -namespace { - -// PP:3.7, full path, or relative path. If we can't find it, -// we should maintain the original to maintain the wordexp etc. -string const fixup_image_spec(string const & str, extra_images const & extra) -{ - string dummy_archive_path; - // FIXME: what todo if an error in find_image_path() ? - image_error error; - return find_image_path(dummy_archive_path, str, extra, error); -} - - -void fixup_image_spec(vector<string> & images, extra_images const & extra) -{ - vector<string>::iterator it = images.begin(); - vector<string>::iterator const end = images.end(); - - for (; it != end; ++it) { - *it = fixup_image_spec(*it, extra); - } -} - -} // anon namespace - - -profile_spec::profile_spec(extra_images const & extra) - : extra(extra) -{ - parse_table["archive"] = &profile_spec::parse_archive_path; - parse_table["session"] = &profile_spec::parse_session; - parse_table["session-exclude"] = - &profile_spec::parse_session_exclude; - parse_table["image"] = &profile_spec::parse_image; - parse_table["image-exclude"] = &profile_spec::parse_image_exclude; - parse_table["lib-image"] = &profile_spec::parse_lib_image; - parse_table["event"] = &profile_spec::parse_event; - parse_table["count"] = &profile_spec::parse_count; - parse_table["unit-mask"] = &profile_spec::parse_unitmask; - parse_table["tid"] = &profile_spec::parse_tid; - parse_table["tgid"] = &profile_spec::parse_tgid; - parse_table["cpu"] = &profile_spec::parse_cpu; -} - - -void profile_spec::parse(string const & tag_value) -{ - string value; - action_t action = get_handler(tag_value, value); - if (!action) { - throw invalid_argument("profile_spec::parse(): not " - "a valid tag \"" + tag_value + "\""); - } - - (this->*action)(value); -} - - -bool profile_spec::is_valid_tag(string const & tag_value) -{ - string value; - return get_handler(tag_value, value); -} - - -void profile_spec::set_image_or_lib_name(string const & str) -{ - /* FIXME: what does spec say about this being allowed to be - * a comma list or not ? */ - image_or_lib_image.push_back(fixup_image_spec(str, extra)); -} - - -void profile_spec::parse_archive_path(string const & str) -{ - archive_path = op_realpath(str); -} - - -string profile_spec::get_archive_path() const -{ - return archive_path; -} - - -void profile_spec::parse_session(string const & str) -{ - session = separate_token(str, ','); -} - - -void profile_spec::parse_session_exclude(string const & str) -{ - session_exclude = separate_token(str, ','); -} - - -void profile_spec::parse_image(string const & str) -{ - image = separate_token(str, ','); - fixup_image_spec(image, extra); -} - - -void profile_spec::parse_image_exclude(string const & str) -{ - image_exclude = separate_token(str, ','); -} - - -void profile_spec::parse_lib_image(string const & str) -{ - lib_image = separate_token(str, ','); - fixup_image_spec(image, extra); -} - - -void profile_spec::parse_event(string const & str) -{ - event.set(str); -} - - -void profile_spec::parse_count(string const & str) -{ - count.set(str); -} - - -void profile_spec::parse_unitmask(string const & str) -{ - unitmask.set(str); -} - - -void profile_spec::parse_tid(string const & str) -{ - tid.set(str); -} - - -void profile_spec::parse_tgid(string const & str) -{ - tgid.set(str); -} - - -void profile_spec::parse_cpu(string const & str) -{ - cpu.set(str); -} - - -profile_spec::action_t -profile_spec::get_handler(string const & tag_value, string & value) -{ - string::size_type pos = tag_value.find_first_of(':'); - if (pos == string::npos) { - return 0; - } - - string tag(tag_value.substr(0, pos)); - value = tag_value.substr(pos + 1); - - parse_table_t::const_iterator it = parse_table.find(tag); - if (it == parse_table.end()) { - return 0; - } - - return it->second; -} - - -namespace { - -/// return true if the value from the profile spec may match the comma -/// list -template<typename T> -bool comma_match(comma_list<T> const & cl, generic_spec<T> const & value) -{ - // if the profile spec is "all" we match the sample file - if (!cl.is_set()) - return true; - - // an "all" sample file should never match specified profile - // spec values - if (!value.is_set()) - return false; - - // now match each profile spec value against the sample file - return cl.match(value.value()); -} - -} - - -bool profile_spec::match(filename_spec const & spec) const -{ - bool matched_by_image_or_lib_image = false; - - // PP:3.19 - if (!image_or_lib_image.empty()) { - // Need the path search for the benefit of modules - // which have "/oprofile" or similar - string simage = fixup_image_spec(spec.image, extra); - string slib_image = fixup_image_spec(spec.lib_image, extra); - glob_filter filter(image_or_lib_image, image_exclude); - if (filter.match(simage) || filter.match(slib_image)) { - matched_by_image_or_lib_image = true; - } - } - - if (!matched_by_image_or_lib_image) { - // PP:3.7 3.8 - if (!image.empty()) { - glob_filter filter(image, image_exclude); - if (!filter.match(spec.image)) { - return false; - } - } else if (!image_or_lib_image.empty()) { - // image.empty() means match all except if user - // specified image_or_lib_image - return false; - } - - // PP:3.9 3.10 - if (!lib_image.empty()) { - glob_filter filter(lib_image, image_exclude); - if (!filter.match(spec.lib_image)) { - return false; - } - } else if (image.empty() && !image_or_lib_image.empty()) { - // lib_image empty means match all except if user - // specified image_or_lib_image *or* we already - // matched this spec through image - return false; - } - } - - if (!matched_by_image_or_lib_image) { - // if we don't match by image_or_lib_image we must try to - // exclude from spec, exclusion from image_or_lib_image has - // been handled above - vector<string> empty; - glob_filter filter(empty, image_exclude); - if (!filter.match(spec.image)) { - return false; - } - if (!spec.lib_image.empty() && !filter.match(spec.lib_image)) { - return false; - } - } - - if (!event.match(spec.event)) - return false; - - if (!count.match(spec.count)) - return false; - - if (!unitmask.match(spec.unitmask)) - return false; - - if (!comma_match(cpu, spec.cpu)) - return false; - - if (!comma_match(tid, spec.tid)) - return false; - - if (!comma_match(tgid, spec.tgid)) - return false; - - return true; -} - - -profile_spec profile_spec::create(list<string> const & args, - extra_images const & extra) -{ - profile_spec spec(extra); - set<string> tag_seen; - - list<string>::const_iterator it = args.begin(); - list<string>::const_iterator end = args.end(); - - for (; it != end; ++it) { - if (spec.is_valid_tag(*it)) { - if (tag_seen.find(*it) != tag_seen.end()) { - throw op_runtime_error("tag specified " - "more than once: " + *it); - } - tag_seen.insert(*it); - spec.parse(*it); - } else { - string const file = op_realpath(*it); - spec.set_image_or_lib_name(file); - } - } - - // PP:3.5 no session given means use the current session. - if (spec.session.empty()) { - spec.session.push_back("current"); - } - - return spec; -} - -namespace { - -vector<string> filter_session(vector<string> const & session, - vector<string> const & session_exclude) -{ - vector<string> result(session); - - if (result.empty()) { - result.push_back("current"); - } - - for (size_t i = 0 ; i < session_exclude.size() ; ++i) { - // FIXME: would we use fnmatch on each item, are we allowed - // to --session=current* ? - vector<string>::iterator it = - find(result.begin(), result.end(), session_exclude[i]); - - if (it != result.end()) { - result.erase(it); - } - } - - return result; -} - - -bool valid_candidate(string const & base_dir, string const & filename, - profile_spec const & spec, bool exclude_dependent, - bool exclude_cg) -{ - if (exclude_cg && filename.find("{cg}") != string::npos) - return false; - - // strip out non sample files - string const & sub = filename.substr(base_dir.size(), string::npos); - if (!is_prefix(sub, "/{root}/") && !is_prefix(sub, "/{kern}/")) - return false; - - filename_spec file_spec(filename); - if (spec.match(file_spec)) { - if (exclude_dependent && file_spec.is_dependent()) - return false; - return true; - } - - return false; -} - -} // anonymous namespace - - -list<string> profile_spec::generate_file_list(bool exclude_dependent, - bool exclude_cg) const -{ - // FIXME: isn't remove_duplicates faster than doing this, then copy() ? - set<string> unique_files; - - vector<string> sessions = filter_session(session, session_exclude); - - if (sessions.empty()) { - ostringstream os; - os << "No session given\n" - << "included session was:\n"; - copy(session.begin(), session.end(), - ostream_iterator<string>(os, "\n")); - os << "excluded session was:\n"; - copy(session_exclude.begin(), session_exclude.end(), - ostream_iterator<string>(os, "\n")); - throw invalid_argument(os.str()); - } - - bool found_file = false; - - vector<string>::const_iterator cit = sessions.begin(); - vector<string>::const_iterator end = sessions.end(); - - for (; cit != end; ++cit) { - if (cit->empty()) - continue; - - string base_dir; - if ((*cit)[0] != '.' && (*cit)[0] != '/') - base_dir = archive_path + OP_SAMPLES_DIR; - base_dir += *cit; - - base_dir = op_realpath(base_dir); - - list<string> files; - create_file_list(files, base_dir, "*", true); - - if (!files.empty()) - found_file = true; - - list<string>::const_iterator it = files.begin(); - list<string>::const_iterator fend = files.end(); - for (; it != fend; ++it) { - if (valid_candidate(base_dir, *it, *this, - exclude_dependent, exclude_cg)) { - unique_files.insert(*it); - } - } - } - - if (!found_file) { - ostringstream os; - os << "No sample file found: try running opcontrol --dump\n" - << "or specify a session containing sample files\n"; - throw op_fatal_error(os.str()); - } - - list<string> result; - copy(unique_files.begin(), unique_files.end(), back_inserter(result)); - - return result; -} diff --git a/libpp/profile_spec.h b/libpp/profile_spec.h deleted file mode 100644 index 1e02abb..0000000 --- a/libpp/profile_spec.h +++ /dev/null @@ -1,142 +0,0 @@ -/** - * @file profile_spec.h - * Contains a PP profile specification - * - * @remark Copyright 2003 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - */ - -#ifndef PROFILE_SPEC_H -#define PROFILE_SPEC_H - -#include <map> -#include <vector> -#include <list> - -#include "filename_spec.h" -#include "comma_list.h" - -class extra_images; - -/** - * Holds a parsed profile spec composed of tag:value pairs, as given in - * pp_interface documentation. - * - * @internal implemented through a map of string, pointer to function member - * indexed by tag_name. - */ -class profile_spec -{ -public: - /** - * @param args a vector of non options strings - * @param extra extra image paths to search - * - * Factory returning a profile_spec instance storing all valid - * tag:value contained in args vector doing also alias - * substitution, non-valid tag:value options are considered - * as image:value - */ - static profile_spec create(std::list<std::string> const & args, - extra_images const & extra); - - /** - * @param exclude_dependent whether to exclude dependent sub-images - * @param exclude_cg whether to exclude call graph file - * - * Use the spec to generate the list of candidate sample files. - */ - std::list<std::string> - generate_file_list(bool exclude_dependent, bool exclude_cg) const; - - /** - * @param file_spec the filename specification to check - * - * return true if filename match the spec. PP:3.24 internal loop - */ - bool match(filename_spec const & file_spec) const; - - /** - * return archive name - * returns an empty string if not using an archive. - */ - std::string get_archive_path() const; - -private: - profile_spec(extra_images const & extra); - - /** - * @param tag_value a "tag:value" to interpret, all error throw an - * invalid_argument exception. - */ - void parse(std::string const & tag_value); - - /** - * @param image an image or a libray name given on command line - * - * Used for e.g. "opreport /bin/mybinary". We don't know yet - * if this is an application or a dependent image. - */ - void set_image_or_lib_name(std::string const & image); - - /** - * @param str a "tag:value" - * - * return true if tag is a valid tag - */ - bool is_valid_tag(std::string const & str); - - /** - * implement tag parsing: PP:3.3 to 3.16 - */ - void parse_archive_path(std::string const &); - void parse_session(std::string const &); - void parse_session_exclude(std::string const &); - void parse_image(std::string const &); - void parse_image_exclude(std::string const &); - void parse_lib_image(std::string const &); - void parse_event(std::string const &); - void parse_count(std::string const &); - void parse_unitmask(std::string const &); - void parse_tid(std::string const &); - void parse_tgid(std::string const &); - void parse_cpu(std::string const &); - - typedef void (profile_spec::*action_t)(std::string const &); - typedef std::map<std::string, action_t> parse_table_t; - parse_table_t parse_table; - - /** - * @param tag_value input "tag:value" string - * @param value if success return the value part of tag_value - * helper for set/is_valid_tag public interface - * - * return null if tag is not valid, else return the pointer to member - * function to apply and the value in value parameter - */ - action_t get_handler(std::string const & tag_value, - std::string & value); - - std::string archive_path; - std::string binary; - std::vector<std::string> session; - std::vector<std::string> session_exclude; - std::vector<std::string> image; - std::vector<std::string> image_exclude; - std::vector<std::string> lib_image; - comma_list<std::string> event; - comma_list<int> count; - comma_list<unsigned int> unitmask; - comma_list<pid_t> tid; - comma_list<pid_t> tgid; - comma_list<int> cpu; - // specified by user on command like opreport image1 image2 ... - std::vector<std::string> image_or_lib_image; - - /// extra search path for images - extra_images const & extra; -}; - -#endif /* !PROFILE_SPEC_H */ diff --git a/libpp/sample_container.cpp b/libpp/sample_container.cpp deleted file mode 100644 index 7a9f4af..0000000 --- a/libpp/sample_container.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/** - * @file sample_container.cpp - * Internal container for samples - * - * @remark Copyright 2002, 2003 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#include <set> -#include <numeric> -#include <algorithm> -#include <vector> - -#include "sample_container.h" - -using namespace std; - -namespace { - -// FIXME: efficiency ? -count_array_t add_counts(count_array_t const & counts, - sample_entry const * s) -{ - count_array_t temp(counts); - temp += s->counts; - return temp; -} - -} // namespace anon - - -sample_container::samples_iterator sample_container::begin() const -{ - return samples.begin(); -} - - -sample_container::samples_iterator sample_container::end() const -{ - return samples.end(); -} - - -sample_container::samples_iterator -sample_container::begin(symbol_entry const * symbol) const -{ - samples_storage::key_type key(symbol, 0); - - return samples.lower_bound(key); -} - - -sample_container::samples_iterator -sample_container::end(symbol_entry const * symbol) const -{ - samples_storage::key_type key(symbol, ~bfd_vma(0)); - - return samples.upper_bound(key); -} - - -void sample_container::insert(symbol_entry const * symbol, - sample_entry const & sample) -{ - samples_storage::key_type key(symbol, sample.vma); - - samples_storage::iterator it = samples.find(key); - if (it != samples.end()) { - it->second.counts += sample.counts; - } else { - samples[key] = sample; - } -} - - -count_array_t -sample_container::accumulate_samples(debug_name_id filename_id) const -{ - build_by_loc(); - - sample_entry lower, upper; - - lower.file_loc.filename = upper.file_loc.filename = filename_id; - lower.file_loc.linenr = 0; - upper.file_loc.linenr = INT_MAX; - - typedef samples_by_loc_t::const_iterator iterator; - - iterator it1 = samples_by_loc.lower_bound(&lower); - iterator it2 = samples_by_loc.upper_bound(&upper); - - return accumulate(it1, it2, count_array_t(), add_counts); -} - - -sample_entry const * -sample_container::find_by_vma(symbol_entry const * symbol, bfd_vma vma) const -{ - sample_index_t key(symbol, vma); - samples_iterator it = samples.find(key); - if (it != samples.end()) - return &it->second; - - return 0; -} - - -count_array_t -sample_container::accumulate_samples(debug_name_id filename, - size_t linenr) const -{ - build_by_loc(); - - sample_entry sample; - - sample.file_loc.filename = filename; - sample.file_loc.linenr = linenr; - - typedef pair<samples_by_loc_t::const_iterator, - samples_by_loc_t::const_iterator> it_pair; - - it_pair itp = samples_by_loc.equal_range(&sample); - - return accumulate(itp.first, itp.second, count_array_t(), add_counts); -} - - -void sample_container::build_by_loc() const -{ - if (!samples_by_loc.empty()) - return; - - samples_iterator cit = samples.begin(); - samples_iterator end = samples.end(); - for (; cit != end; ++cit) - samples_by_loc.insert(&cit->second); -} diff --git a/libpp/sample_container.h b/libpp/sample_container.h deleted file mode 100644 index 74c9ab0..0000000 --- a/libpp/sample_container.h +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @file sample_container.h - * Internal implementation of sample container - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#ifndef SAMPLE_CONTAINER_H -#define SAMPLE_CONTAINER_H - -#include <map> -#include <set> -#include <string> - -#include "symbol.h" -#include "symbol_functors.h" - -/** - * Arbitrary container of sample entries. Can return - * number of samples for a file or line number and - * return the particular sample information for a VMA. - */ -class sample_container { - typedef std::pair<symbol_entry const *, bfd_vma> sample_index_t; -public: - typedef std::map<sample_index_t, sample_entry> samples_storage; - typedef samples_storage::const_iterator samples_iterator; - - /// return iterator to the first samples for this symbol - samples_iterator begin(symbol_entry const *) const; - /// return iterator to the last samples for this symbol - samples_iterator end(symbol_entry const *) const; - - /// return iterator to the first samples - samples_iterator begin() const; - /// return iterator to the last samples - samples_iterator end() const; - - /// insert a sample entry by creating a new entry or by cumulating - /// samples into an existing one. Can only be done before any lookups - void insert(symbol_entry const * symbol, sample_entry const &); - - /// return nr of samples in the given filename - count_array_t accumulate_samples(debug_name_id filename_id) const; - - /// return nr of samples at the given line nr in the given file - count_array_t accumulate_samples(debug_name_id, size_t linenr) const; - - /// return the sample entry for the given image_name and vma if any - sample_entry const * find_by_vma(symbol_entry const * symbol, - bfd_vma vma) const; - -private: - /// build the symbol by file-location cache - void build_by_loc() const; - - /// main sample entry container - samples_storage samples; - - typedef std::multiset<sample_entry const *, less_by_file_loc> - samples_by_loc_t; - - // must be declared after the samples_storage to ensure a - // correct life-time. - - /** - * Sample entries by file location. Lazily built when necessary, - * so mutable. - */ - mutable samples_by_loc_t samples_by_loc; -}; - -#endif /* SAMPLE_CONTAINER_H */ diff --git a/libpp/symbol.cpp b/libpp/symbol.cpp deleted file mode 100644 index dd94412..0000000 --- a/libpp/symbol.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @file symbol.cpp - * Symbol containers - * - * @remark Copyright 2002, 2004 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - - -#include "symbol.h" -#include <iostream> - -using std::cerr; -using std::endl; - -column_flags symbol_entry::output_hint(column_flags fl) const -{ - if (app_name != image_name) - fl = column_flags(fl | cf_image_name); - - // FIXME: see comment in symbol.h: why we don't use sample.vma + size ? - if (sample.vma & ~0xffffffffLLU) - fl = column_flags(fl | cf_64bit_vma); - - return fl; -} diff --git a/libpp/symbol.h b/libpp/symbol.h deleted file mode 100644 index 7072d9c..0000000 --- a/libpp/symbol.h +++ /dev/null @@ -1,133 +0,0 @@ -/** - * @file symbol.h - * Symbol containers - * - * @remark Copyright 2002, 2004 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#ifndef SYMBOL_H -#define SYMBOL_H - -#include "name_storage.h" -#include "growable_vector.h" -#include "format_flags.h" -#include "op_types.h" - -#include <bfd.h> - -#include <list> - - -/// for storing sample counts -typedef growable_vector<u32> count_array_t; - - -/// A simple container for a fileno:linenr location. -struct file_location { - file_location() : linenr(0) {} - /// empty if not valid. - debug_name_id filename; - /// 0 means invalid or code is generated internally by the compiler - unsigned int linenr; - - bool operator<(file_location const & rhs) const { - // Note we sort on filename id not on string - return filename < rhs.filename || - (filename == rhs.filename && linenr < rhs.linenr); - } -}; - - -/// associate vma address with a file location and a samples count -struct sample_entry { - sample_entry() : vma(0) {} - /// From where file location comes the samples - file_location file_loc; - /// From where virtual memory address comes the samples - bfd_vma vma; - /// the samples count - count_array_t counts; -}; - - -/// associate a symbol with a file location, samples count and vma address -struct symbol_entry { - symbol_entry() : size(0) {} - /// which image this symbol belongs to - image_name_id image_name; - /// owning application name: identical to image name if profiling - /// session did not separate samples for shared libs or if image_name - /// is not a shared lib - image_name_id app_name; - /// file location, vma and cumulated samples count for this symbol - sample_entry sample; - /// name of symbol - symbol_name_id name; - /// symbol size as calculated by op_bfd, start of symbol is sample.vma - size_t size; - - /** - * @param fl input hint - * - * combine fl with the calculated hint. It's theoretically possible - * that we get a symbol where its samples pass the border line, but - * the start is below it, but the the hint is only used for formatting - */ - column_flags output_hint(column_flags fl) const; -}; - - -/// a collection of sorted symbols -typedef std::vector<symbol_entry const *> symbol_collection; - - -/** - * The public data for call-graph symbols. Each caller/callee has - * the sample counts replaced with the relevant arc counts, whilst - * the cg_symbol retains its self count. - */ -struct cg_symbol : public symbol_entry { - cg_symbol(symbol_entry const & sym) : symbol_entry(sym) {} - - typedef std::vector<symbol_entry> children; - - /// all callers of this symbol - children callers; - /// total count of callers - count_array_t total_caller_count; - - /// all symbols called by this symbol - children callees; - /// total count of callees - count_array_t total_callee_count; -}; - - -/// a collection of sorted callgraph symbols -typedef std::vector<cg_symbol> cg_collection; - - -/// for storing diff %ages -typedef growable_vector<double> diff_array_t; - - -/** - * Data for a diffed symbol. - */ -struct diff_symbol : public symbol_entry { - diff_symbol(symbol_entry const & sym) : symbol_entry(sym) {} - - /// diff %age values for each profile class - diff_array_t diffs; -}; - - -/// a collection of diffed symbols -typedef std::vector<diff_symbol> diff_collection; - - -#endif /* !SYMBOL_H */ diff --git a/libpp/symbol_container.cpp b/libpp/symbol_container.cpp deleted file mode 100644 index b7a6d3e..0000000 --- a/libpp/symbol_container.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @file symbol_container.cpp - * Internal container for symbols - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#include <string> -#include <algorithm> -#include <set> -#include <vector> - -#include "symbol_container.h" - -using namespace std; - -symbol_container::size_type symbol_container::size() const -{ - return symbols.size(); -} - - -symbol_entry const * symbol_container::insert(symbol_entry const & symb) -{ - pair<symbols_t::iterator, bool> p = symbols.insert(symb); - if (!p.second) { - // safe: count is not used by sorting criteria - symbol_entry * symbol = const_cast<symbol_entry*>(&*p.first); - symbol->sample.counts += symb.sample.counts; - } - - return &*p.first; -} - - -symbol_entry const * -symbol_container::find(debug_name_id filename, size_t linenr) const -{ - build_by_loc(); - - symbol_entry symbol; - symbol.sample.file_loc.filename = filename; - symbol.sample.file_loc.linenr = linenr; - - symbols_by_loc_t::const_iterator it = symbols_by_loc.find(&symbol); - - if (it != symbols_by_loc.end()) - return *it; - - return 0; -} - - -void symbol_container::build_by_loc() const -{ - if (!symbols_by_loc.empty()) - return; - - symbols_t::const_iterator cit = symbols.begin(); - symbols_t::const_iterator end = symbols.end(); - for (; cit != end; ++cit) - symbols_by_loc.insert(&*cit); -} - - -symbol_entry const * symbol_container::find_by_vma(string const & image_name, - bfd_vma vma) const -{ - // FIXME: this is too inefficient probably - symbols_t::const_iterator it; - for (it = symbols.begin(); it != symbols.end(); ++it) { - if (it->sample.vma == vma && - image_names.name(it->image_name) == image_name) - return &*it; - } - - return 0; -} - - -symbol_container::symbols_t::iterator symbol_container::begin() -{ - return symbols.begin(); -} - - -symbol_container::symbols_t::iterator symbol_container::end() -{ - return symbols.end(); -} - -symbol_entry const * symbol_container::find(symbol_entry const & symbol) const -{ - symbols_t::const_iterator it = symbols.find(symbol); - return it == symbols.end() ? 0 : &*it; -} diff --git a/libpp/symbol_container.h b/libpp/symbol_container.h deleted file mode 100644 index 73ca581..0000000 --- a/libpp/symbol_container.h +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @file symbol_container.h - * Internal container for symbols - * - * @remark Copyright 2002, 2003 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#ifndef SYMBOL_CONTAINER_H -#define SYMBOL_CONTAINER_H - -#include <string> -#include <set> - -#include "symbol.h" -#include "symbol_functors.h" - -/** - * An arbitrary container of symbols. Supports lookup - * by name, by VMA, and by file location. - * - * Lookup by name or by VMA is O(n). Lookup by file location - * is O(log(n)). - */ -class symbol_container { -public: - /// container type - typedef std::set<symbol_entry, less_symbol> symbols_t; - - typedef symbols_t::size_type size_type; - - /// return the number of symbols stored - size_type size() const; - - /** - * Insert a new symbol. If the symbol already exists in the container, - * then the sample counts are accumulated. - * Returns the newly created symbol or the existing one. This pointer - * remains valid during the whole life time of a symbol_container - * object and is warranted unique according to less_symbol comparator. - * Can only be done before any file-location based lookups, since the - * two lookup methods are not synchronised. - */ - symbol_entry const * insert(symbol_entry const &); - - /// find the symbol at the given filename and line number, if any - symbol_entry const * find(debug_name_id filename, - size_t linenr) const; - - /// find the symbol with the given image_name vma if any - symbol_entry const * find_by_vma(std::string const & image_name, - bfd_vma vma) const; - - /// Search a symbol. Return NULL if not found. - symbol_entry const * find(symbol_entry const & symbol) const; - - /// return start of symbols - symbols_t::iterator begin(); - - /// return end of symbols - symbols_t::iterator end(); - -private: - /// build the symbol by file-location cache - void build_by_loc() const; - - /** - * The main container of symbols. Multiple symbols with the same - * name are allowed. - */ - symbols_t symbols; - - /** - * Differently-named symbol at same file location are allowed e.g. - * template instantiation. - */ - typedef std::multiset<symbol_entry const *, less_by_file_loc> - symbols_by_loc_t; - - // must be declared after the set to ensure a correct life-time. - - /** - * Symbols sorted by location order. Lazily built on request, - * so mutable. - */ - mutable symbols_by_loc_t symbols_by_loc; -}; - -#endif /* SYMBOL_CONTAINER_H */ diff --git a/libpp/symbol_functors.cpp b/libpp/symbol_functors.cpp deleted file mode 100644 index a4107c3..0000000 --- a/libpp/symbol_functors.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @file symbol_functors.cpp - * Functors for symbol/sample comparison - * - * @remark Copyright 2002 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#include "symbol_functors.h" - -bool less_symbol::operator()(symbol_entry const & lhs, - symbol_entry const & rhs) const -{ - if (lhs.image_name != rhs.image_name) - return lhs.image_name < rhs.image_name; - - if (lhs.app_name != rhs.app_name) - return lhs.app_name < rhs.app_name; - - if (lhs.name != rhs.name) - return lhs.name < rhs.name; - - if (lhs.sample.vma != rhs.sample.vma) - return lhs.sample.vma < rhs.sample.vma; - - return lhs.size < rhs.size; -} diff --git a/libpp/symbol_functors.h b/libpp/symbol_functors.h deleted file mode 100644 index 53a7253..0000000 --- a/libpp/symbol_functors.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file symbol_functors.h - * Functors for symbol/sample comparison - * - * @remark Copyright 2002, 2003 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#ifndef SYMBOL_FUNCTORS_H -#define SYMBOL_FUNCTORS_H - -#include "symbol.h" - -/// compare based on file location -struct less_by_file_loc { - bool operator()(sample_entry const * lhs, - sample_entry const * rhs) const { - return lhs->file_loc < rhs->file_loc; - } - - bool operator()(symbol_entry const * lhs, - symbol_entry const * rhs) const { - return lhs->sample.file_loc < rhs->sample.file_loc; - } -}; - - -/// compare based on symbol contents -struct less_symbol { - // implementation compare by id rather than by string - bool operator()(symbol_entry const & lhs, - symbol_entry const & rhs) const; -}; - -#endif /* SYMBOL_FUNCTORS_H */ diff --git a/libpp/symbol_sort.cpp b/libpp/symbol_sort.cpp deleted file mode 100644 index 4b18e59..0000000 --- a/libpp/symbol_sort.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/** - * @file symbol_sort.cpp - * Sorting symbols - * - * @remark Copyright 2002, 2003 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#include "symbol_sort.h" -#include "symbol_functors.h" - -#include "name_storage.h" -#include "op_exception.h" - -#include <algorithm> -#include <sstream> - -using namespace std; - -namespace { - -bool long_filenames; - -int image_compare(image_name_id l, image_name_id r) -{ - if (long_filenames) - return image_names.name(l).compare(image_names.name(r)); - return image_names.basename(l).compare(image_names.basename(r)); -} - - -int debug_compare(debug_name_id l, debug_name_id r) -{ - if (long_filenames) - return debug_names.name(l).compare(debug_names.name(r)); - return debug_names.basename(l).compare(debug_names.basename(r)); -} - - -int compare_by(sort_options::sort_order order, - symbol_entry const & lhs, symbol_entry const & rhs) -{ - switch (order) { - case sort_options::sample: - if (lhs.sample.counts[0] < rhs.sample.counts[0]) - return 1; - if (lhs.sample.counts[0] > rhs.sample.counts[0]) - return -1; - return 0; - - case sort_options::symbol: - return symbol_names.demangle(lhs.name).compare( - symbol_names.demangle(rhs.name)); - - case sort_options::image: - return image_compare(lhs.image_name, rhs.image_name); - - case sort_options::app_name: - return image_compare(lhs.app_name, rhs.app_name); - - case sort_options::vma: - if (lhs.sample.vma < rhs.sample.vma) - return -1; - if (lhs.sample.vma > rhs.sample.vma) - return 1; - return 0; - - case sort_options::debug: { - file_location const & f1 = lhs.sample.file_loc; - file_location const & f2 = rhs.sample.file_loc; - int ret = debug_compare(f1.filename, f2.filename); - if (ret == 0) - ret = f1.linenr - f2.linenr; - return ret; - } - - default: { - // static_cast<> to shut up g++ 2.91.66 which warn - // about ambiguity between <<(int) and <<(long int) - ostringstream os; - os << "compare_by(): unknown sort option: " - << static_cast<int>(order) << endl; - throw op_fatal_error(os.str()); - } - } - - return 0; -} - - -struct symbol_compare { - symbol_compare(vector<sort_options::sort_order> const & order, - bool reverse) - : compare_order(order), reverse_sort(reverse) {} - - bool operator()(symbol_entry const * lhs, - symbol_entry const * rhs) const { - return operator()(*lhs, *rhs); - } - - bool operator()(symbol_entry const & lhs, - symbol_entry const & rhs) const; - -protected: - vector<sort_options::sort_order> const & compare_order; - bool reverse_sort; -}; - - -bool symbol_compare::operator()(symbol_entry const & lhs, - symbol_entry const & rhs) const -{ - for (size_t i = 0; i < compare_order.size(); ++i) { - int ret = compare_by(compare_order[i], lhs, rhs); - - if (reverse_sort) - ret = -ret; - if (ret != 0) - return ret < 0; - } - return false; -} - - -} // anonymous namespace - - -void sort_options:: -sort(symbol_collection & syms, bool reverse_sort, bool lf) const -{ - long_filenames = lf; - - vector<sort_order> sort_option(options); - for (sort_order cur = first; cur != last; cur = sort_order(cur + 1)) { - if (find(sort_option.begin(), sort_option.end(), cur) == - sort_option.end()) - sort_option.push_back(cur); - } - - stable_sort(syms.begin(), syms.end(), - symbol_compare(sort_option, reverse_sort)); -} - - -void sort_options:: -sort(cg_collection & syms, bool reverse_sort, bool lf) const -{ - long_filenames = lf; - - vector<sort_order> sort_option(options); - for (sort_order cur = first; cur != last; cur = sort_order(cur + 1)) { - if (find(sort_option.begin(), sort_option.end(), cur) == - sort_option.end()) - sort_option.push_back(cur); - } - - stable_sort(syms.begin(), syms.end(), - symbol_compare(sort_option, reverse_sort)); -} - - -void sort_options:: -sort(diff_collection & syms, bool reverse_sort, bool lf) const -{ - long_filenames = lf; - - vector<sort_order> sort_option(options); - for (sort_order cur = first; cur != last; cur = sort_order(cur + 1)) { - if (find(sort_option.begin(), sort_option.end(), cur) == - sort_option.end()) - sort_option.push_back(cur); - } - - stable_sort(syms.begin(), syms.end(), - symbol_compare(sort_option, reverse_sort)); -} - - -void sort_options::add_sort_option(string const & name) -{ - if (name == "vma") { - options.push_back(vma); - } else if (name == "sample") { - options.push_back(sample); - } else if (name == "symbol") { - options.push_back(symbol); - } else if (name == "debug") { - options.push_back(debug); - } else if (name == "image") { - options.push_back(image); - } else if (name == "app-name") { - options.push_back(app_name); - } else { - ostringstream os; - os << "unknown sort option: " << name << endl; - throw op_fatal_error(os.str()); - } -} - - -void sort_options::add_sort_option(sort_options::sort_order order) -{ - options.push_back(order); -} diff --git a/libpp/symbol_sort.h b/libpp/symbol_sort.h deleted file mode 100644 index da93d04..0000000 --- a/libpp/symbol_sort.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @file symbol_sort.h - * Sorting symbols - * - * @remark Copyright 2002, 2003 OProfile authors - * @remark Read the file COPYING - * - * @author Philippe Elie - * @author John Levon - */ - -#ifndef SYMBOL_SORT_H -#define SYMBOL_SORT_H - -#include "symbol.h" - -#include <vector> -#include <string> - -struct sort_options { - enum sort_order { - // order give sort order if caller doesn't specify one - first, - sample = first, - image, - app_name, - symbol, - debug, - vma, - last - }; - - sort_options() {} - - void add_sort_option(std::string const & name); - void add_sort_option(sort_order order); - - /** - * Sort the given container by the given criteria. - */ - void sort(symbol_collection & syms, bool reverse_sort, - bool long_filenames) const; - - /** - * Sort the given container by the given criteria. - */ - void sort(cg_collection & syms, bool reverse_sort, - bool long_filenames) const; - - /** - * Sort the given container by the given criteria. - */ - void sort(diff_collection & syms, bool reverse_sort, - bool long_filenames) const; - - std::vector<sort_order> options; -}; - -#endif // SYMBOL_SORT_H |