gprofng: a new GNU profiler

top-level
	* Makefile.def: Add gprofng module.
	* configure.ac: Add --enable-gprofng option.
	* src-release.sh: Add gprofng.
	* Makefile.in: Regenerate.
	* configure: Regenerate.
	* gprofng: New directory.

binutils
	* MAINTAINERS: Add gprofng maintainer.
	* README-how-to-make-a-release: Add gprofng.

include.
	* collectorAPI.h: New file.
	* libcollector.h: New file.
	* libfcollector.h: New file.
This commit is contained in:
Vladimir Mezentsev 2022-03-11 08:58:31 +00:00 committed by Nick Clifton
parent a655f19af9
commit bb368aad29
319 changed files with 222979 additions and 8 deletions

View file

@ -1,3 +1,12 @@
2022-03-11 Vladimir Mezentsev <vladimir.mezentsev@oracle.com>
* Makefile.def: Add gprofng module.
* configure.ac: Add --enable-gprofng option.
* src-release.sh: Add gprofng.
* Makefile.in: Regenerate.
* configure: Regenerate.
* gprofng: New directory.
2022-01-22 Nick Clifton <nickc@redhat.com>
* 2.38 release branch created.

View file

@ -75,6 +75,7 @@ host_modules= { module= libelf; lib_path=.libs; bootstrap=true;
no_install= true; };
host_modules= { module= gold; bootstrap=true; };
host_modules= { module= gprof; };
host_modules= { module= gprofng; };
host_modules= { module= intl; bootstrap=true; };
host_modules= { module= tcl;
missing=mostlyclean; };
@ -508,6 +509,16 @@ dependencies = { module=all-gprof; on=all-bfd; };
dependencies = { module=all-gprof; on=all-opcodes; };
dependencies = { module=all-gprof; on=all-intl; };
dependencies = { module=all-gprof; on=all-gas; };
dependencies = { module=configure-gprofng; on=configure-intl; };
dependencies = { module=all-gprofng; on=all-libiberty; };
dependencies = { module=all-gprofng; on=all-bfd; };
dependencies = { module=all-gprofng; on=all-opcodes; };
dependencies = { module=all-gprofng; on=all-intl; };
dependencies = { module=all-gprofng; on=all-gas; };
dependencies = { module=install-gprofng; on=install-opcodes; };
dependencies = { module=install-gprofng; on=install-bfd; };
dependencies = { module=configure-ld; on=configure-intl; };
dependencies = { module=all-ld; on=all-libiberty; };
dependencies = { module=all-ld; on=all-bfd; };

View file

@ -1073,6 +1073,7 @@ configure-host: \
maybe-configure-libelf \
maybe-configure-gold \
maybe-configure-gprof \
maybe-configure-gprofng \
maybe-configure-intl \
maybe-configure-tcl \
maybe-configure-itcl \
@ -1228,6 +1229,7 @@ all-host: maybe-all-libelf
all-host: maybe-all-gold
@endif gold-no-bootstrap
all-host: maybe-all-gprof
all-host: maybe-all-gprofng
@if intl-no-bootstrap
all-host: maybe-all-intl
@endif intl-no-bootstrap
@ -1357,6 +1359,7 @@ info-host: maybe-info-isl
info-host: maybe-info-libelf
info-host: maybe-info-gold
info-host: maybe-info-gprof
info-host: maybe-info-gprofng
info-host: maybe-info-intl
info-host: maybe-info-tcl
info-host: maybe-info-itcl
@ -1447,6 +1450,7 @@ dvi-host: maybe-dvi-isl
dvi-host: maybe-dvi-libelf
dvi-host: maybe-dvi-gold
dvi-host: maybe-dvi-gprof
dvi-host: maybe-dvi-gprofng
dvi-host: maybe-dvi-intl
dvi-host: maybe-dvi-tcl
dvi-host: maybe-dvi-itcl
@ -1537,6 +1541,7 @@ pdf-host: maybe-pdf-isl
pdf-host: maybe-pdf-libelf
pdf-host: maybe-pdf-gold
pdf-host: maybe-pdf-gprof
pdf-host: maybe-pdf-gprofng
pdf-host: maybe-pdf-intl
pdf-host: maybe-pdf-tcl
pdf-host: maybe-pdf-itcl
@ -1627,6 +1632,7 @@ html-host: maybe-html-isl
html-host: maybe-html-libelf
html-host: maybe-html-gold
html-host: maybe-html-gprof
html-host: maybe-html-gprofng
html-host: maybe-html-intl
html-host: maybe-html-tcl
html-host: maybe-html-itcl
@ -1717,6 +1723,7 @@ TAGS-host: maybe-TAGS-isl
TAGS-host: maybe-TAGS-libelf
TAGS-host: maybe-TAGS-gold
TAGS-host: maybe-TAGS-gprof
TAGS-host: maybe-TAGS-gprofng
TAGS-host: maybe-TAGS-intl
TAGS-host: maybe-TAGS-tcl
TAGS-host: maybe-TAGS-itcl
@ -1807,6 +1814,7 @@ install-info-host: maybe-install-info-isl
install-info-host: maybe-install-info-libelf
install-info-host: maybe-install-info-gold
install-info-host: maybe-install-info-gprof
install-info-host: maybe-install-info-gprofng
install-info-host: maybe-install-info-intl
install-info-host: maybe-install-info-tcl
install-info-host: maybe-install-info-itcl
@ -1897,6 +1905,7 @@ install-dvi-host: maybe-install-dvi-isl
install-dvi-host: maybe-install-dvi-libelf
install-dvi-host: maybe-install-dvi-gold
install-dvi-host: maybe-install-dvi-gprof
install-dvi-host: maybe-install-dvi-gprofng
install-dvi-host: maybe-install-dvi-intl
install-dvi-host: maybe-install-dvi-tcl
install-dvi-host: maybe-install-dvi-itcl
@ -1987,6 +1996,7 @@ install-pdf-host: maybe-install-pdf-isl
install-pdf-host: maybe-install-pdf-libelf
install-pdf-host: maybe-install-pdf-gold
install-pdf-host: maybe-install-pdf-gprof
install-pdf-host: maybe-install-pdf-gprofng
install-pdf-host: maybe-install-pdf-intl
install-pdf-host: maybe-install-pdf-tcl
install-pdf-host: maybe-install-pdf-itcl
@ -2077,6 +2087,7 @@ install-html-host: maybe-install-html-isl
install-html-host: maybe-install-html-libelf
install-html-host: maybe-install-html-gold
install-html-host: maybe-install-html-gprof
install-html-host: maybe-install-html-gprofng
install-html-host: maybe-install-html-intl
install-html-host: maybe-install-html-tcl
install-html-host: maybe-install-html-itcl
@ -2167,6 +2178,7 @@ installcheck-host: maybe-installcheck-isl
installcheck-host: maybe-installcheck-libelf
installcheck-host: maybe-installcheck-gold
installcheck-host: maybe-installcheck-gprof
installcheck-host: maybe-installcheck-gprofng
installcheck-host: maybe-installcheck-intl
installcheck-host: maybe-installcheck-tcl
installcheck-host: maybe-installcheck-itcl
@ -2257,6 +2269,7 @@ mostlyclean-host: maybe-mostlyclean-isl
mostlyclean-host: maybe-mostlyclean-libelf
mostlyclean-host: maybe-mostlyclean-gold
mostlyclean-host: maybe-mostlyclean-gprof
mostlyclean-host: maybe-mostlyclean-gprofng
mostlyclean-host: maybe-mostlyclean-intl
mostlyclean-host: maybe-mostlyclean-tcl
mostlyclean-host: maybe-mostlyclean-itcl
@ -2347,6 +2360,7 @@ clean-host: maybe-clean-isl
clean-host: maybe-clean-libelf
clean-host: maybe-clean-gold
clean-host: maybe-clean-gprof
clean-host: maybe-clean-gprofng
clean-host: maybe-clean-intl
clean-host: maybe-clean-tcl
clean-host: maybe-clean-itcl
@ -2437,6 +2451,7 @@ distclean-host: maybe-distclean-isl
distclean-host: maybe-distclean-libelf
distclean-host: maybe-distclean-gold
distclean-host: maybe-distclean-gprof
distclean-host: maybe-distclean-gprofng
distclean-host: maybe-distclean-intl
distclean-host: maybe-distclean-tcl
distclean-host: maybe-distclean-itcl
@ -2527,6 +2542,7 @@ maintainer-clean-host: maybe-maintainer-clean-isl
maintainer-clean-host: maybe-maintainer-clean-libelf
maintainer-clean-host: maybe-maintainer-clean-gold
maintainer-clean-host: maybe-maintainer-clean-gprof
maintainer-clean-host: maybe-maintainer-clean-gprofng
maintainer-clean-host: maybe-maintainer-clean-intl
maintainer-clean-host: maybe-maintainer-clean-tcl
maintainer-clean-host: maybe-maintainer-clean-itcl
@ -2675,6 +2691,7 @@ check-host: \
maybe-check-libelf \
maybe-check-gold \
maybe-check-gprof \
maybe-check-gprofng \
maybe-check-intl \
maybe-check-tcl \
maybe-check-itcl \
@ -2812,6 +2829,7 @@ install-host-nogcc: \
maybe-install-libelf \
maybe-install-gold \
maybe-install-gprof \
maybe-install-gprofng \
maybe-install-intl \
maybe-install-tcl \
maybe-install-itcl \
@ -2867,6 +2885,7 @@ install-host: \
maybe-install-libelf \
maybe-install-gold \
maybe-install-gprof \
maybe-install-gprofng \
maybe-install-intl \
maybe-install-tcl \
maybe-install-itcl \
@ -2977,6 +2996,7 @@ install-strip-host: \
maybe-install-strip-libelf \
maybe-install-strip-gold \
maybe-install-strip-gprof \
maybe-install-strip-gprofng \
maybe-install-strip-intl \
maybe-install-strip-tcl \
maybe-install-strip-itcl \
@ -20404,6 +20424,474 @@ maintainer-clean-gprof:
.PHONY: configure-gprofng maybe-configure-gprofng
maybe-configure-gprofng:
@if gcc-bootstrap
configure-gprofng: stage_current
@endif gcc-bootstrap
@if gprofng
maybe-configure-gprofng: configure-gprofng
configure-gprofng:
@: $(MAKE); $(unstage)
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
test ! -f $(HOST_SUBDIR)/gprofng/Makefile || exit 0; \
$(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/gprofng; \
$(HOST_EXPORTS) \
echo Configuring in $(HOST_SUBDIR)/gprofng; \
cd "$(HOST_SUBDIR)/gprofng" || exit 1; \
case $(srcdir) in \
/* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
*) topdir=`echo $(HOST_SUBDIR)/gprofng/ | \
sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
esac; \
module_srcdir=gprofng; \
$(SHELL) \
$$s/$$module_srcdir/configure \
--srcdir=$${topdir}/$$module_srcdir \
$(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
--target=${target_alias} \
|| exit 1
@endif gprofng
.PHONY: all-gprofng maybe-all-gprofng
maybe-all-gprofng:
@if gcc-bootstrap
all-gprofng: stage_current
@endif gcc-bootstrap
@if gprofng
TARGET-gprofng=all
maybe-all-gprofng: all-gprofng
all-gprofng: configure-gprofng
@: $(MAKE); $(unstage)
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) $(EXTRA_HOST_FLAGS) $(STAGE1_FLAGS_TO_PASS) \
$(TARGET-gprofng))
@endif gprofng
.PHONY: check-gprofng maybe-check-gprofng
maybe-check-gprofng:
@if gprofng
maybe-check-gprofng: check-gprofng
check-gprofng:
@: $(MAKE); $(unstage)
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(FLAGS_TO_PASS) check)
@endif gprofng
.PHONY: install-gprofng maybe-install-gprofng
maybe-install-gprofng:
@if gprofng
maybe-install-gprofng: install-gprofng
install-gprofng: installdirs
@: $(MAKE); $(unstage)
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(FLAGS_TO_PASS) install)
@endif gprofng
.PHONY: install-strip-gprofng maybe-install-strip-gprofng
maybe-install-strip-gprofng:
@if gprofng
maybe-install-strip-gprofng: install-strip-gprofng
install-strip-gprofng: installdirs
@: $(MAKE); $(unstage)
@r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(FLAGS_TO_PASS) install-strip)
@endif gprofng
# Other targets (info, dvi, pdf, etc.)
.PHONY: maybe-info-gprofng info-gprofng
maybe-info-gprofng:
@if gprofng
maybe-info-gprofng: info-gprofng
info-gprofng: \
configure-gprofng
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing info in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
info) \
|| exit 1
@endif gprofng
.PHONY: maybe-dvi-gprofng dvi-gprofng
maybe-dvi-gprofng:
@if gprofng
maybe-dvi-gprofng: dvi-gprofng
dvi-gprofng: \
configure-gprofng
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing dvi in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
dvi) \
|| exit 1
@endif gprofng
.PHONY: maybe-pdf-gprofng pdf-gprofng
maybe-pdf-gprofng:
@if gprofng
maybe-pdf-gprofng: pdf-gprofng
pdf-gprofng: \
configure-gprofng
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing pdf in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
pdf) \
|| exit 1
@endif gprofng
.PHONY: maybe-html-gprofng html-gprofng
maybe-html-gprofng:
@if gprofng
maybe-html-gprofng: html-gprofng
html-gprofng: \
configure-gprofng
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing html in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
html) \
|| exit 1
@endif gprofng
.PHONY: maybe-TAGS-gprofng TAGS-gprofng
maybe-TAGS-gprofng:
@if gprofng
maybe-TAGS-gprofng: TAGS-gprofng
TAGS-gprofng: \
configure-gprofng
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing TAGS in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
TAGS) \
|| exit 1
@endif gprofng
.PHONY: maybe-install-info-gprofng install-info-gprofng
maybe-install-info-gprofng:
@if gprofng
maybe-install-info-gprofng: install-info-gprofng
install-info-gprofng: \
configure-gprofng \
info-gprofng
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing install-info in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
install-info) \
|| exit 1
@endif gprofng
.PHONY: maybe-install-dvi-gprofng install-dvi-gprofng
maybe-install-dvi-gprofng:
@if gprofng
maybe-install-dvi-gprofng: install-dvi-gprofng
install-dvi-gprofng: \
configure-gprofng \
dvi-gprofng
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing install-dvi in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
install-dvi) \
|| exit 1
@endif gprofng
.PHONY: maybe-install-pdf-gprofng install-pdf-gprofng
maybe-install-pdf-gprofng:
@if gprofng
maybe-install-pdf-gprofng: install-pdf-gprofng
install-pdf-gprofng: \
configure-gprofng \
pdf-gprofng
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing install-pdf in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
install-pdf) \
|| exit 1
@endif gprofng
.PHONY: maybe-install-html-gprofng install-html-gprofng
maybe-install-html-gprofng:
@if gprofng
maybe-install-html-gprofng: install-html-gprofng
install-html-gprofng: \
configure-gprofng \
html-gprofng
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing install-html in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
install-html) \
|| exit 1
@endif gprofng
.PHONY: maybe-installcheck-gprofng installcheck-gprofng
maybe-installcheck-gprofng:
@if gprofng
maybe-installcheck-gprofng: installcheck-gprofng
installcheck-gprofng: \
configure-gprofng
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing installcheck in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
installcheck) \
|| exit 1
@endif gprofng
.PHONY: maybe-mostlyclean-gprofng mostlyclean-gprofng
maybe-mostlyclean-gprofng:
@if gprofng
maybe-mostlyclean-gprofng: mostlyclean-gprofng
mostlyclean-gprofng:
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing mostlyclean in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
mostlyclean) \
|| exit 1
@endif gprofng
.PHONY: maybe-clean-gprofng clean-gprofng
maybe-clean-gprofng:
@if gprofng
maybe-clean-gprofng: clean-gprofng
clean-gprofng:
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing clean in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
clean) \
|| exit 1
@endif gprofng
.PHONY: maybe-distclean-gprofng distclean-gprofng
maybe-distclean-gprofng:
@if gprofng
maybe-distclean-gprofng: distclean-gprofng
distclean-gprofng:
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing distclean in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
distclean) \
|| exit 1
@endif gprofng
.PHONY: maybe-maintainer-clean-gprofng maintainer-clean-gprofng
maybe-maintainer-clean-gprofng:
@if gprofng
maybe-maintainer-clean-gprofng: maintainer-clean-gprofng
maintainer-clean-gprofng:
@: $(MAKE); $(unstage)
@[ -f ./gprofng/Makefile ] || exit 0; \
r=`${PWD_COMMAND}`; export r; \
s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
$(HOST_EXPORTS) \
for flag in $(EXTRA_HOST_FLAGS) ; do \
eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
done; \
echo "Doing maintainer-clean in gprofng"; \
(cd $(HOST_SUBDIR)/gprofng && \
$(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
"CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
"RANLIB=$${RANLIB}" \
"DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
maintainer-clean) \
|| exit 1
@endif gprofng
.PHONY: configure-intl maybe-configure-intl
maybe-configure-intl:
@if gcc-bootstrap
@ -62838,6 +63326,8 @@ all-stagetrain-gas: maybe-all-stagetrain-intl
all-stagefeedback-gas: maybe-all-stagefeedback-intl
all-stageautoprofile-gas: maybe-all-stageautoprofile-intl
all-stageautofeedback-gas: maybe-all-stageautofeedback-intl
install-gprofng: maybe-install-opcodes
install-gprofng: maybe-install-bfd
configure-ld: maybe-configure-intl
configure-stage1-ld: maybe-configure-stage1-intl
configure-stage2-ld: maybe-configure-stage2-intl
@ -63240,6 +63730,7 @@ configure-gdb: stage_last
configure-gdbserver: stage_last
configure-gdbsupport: stage_last
configure-gprof: stage_last
configure-gprofng: stage_last
configure-sid: stage_last
configure-sim: stage_last
configure-fastjar: stage_last
@ -63272,6 +63763,12 @@ all-gprof: maybe-all-bfd
all-gprof: maybe-all-opcodes
all-gprof: maybe-all-intl
all-gprof: maybe-all-gas
configure-gprofng: maybe-configure-intl
all-gprofng: maybe-all-libiberty
all-gprofng: maybe-all-bfd
all-gprofng: maybe-all-opcodes
all-gprofng: maybe-all-intl
all-gprofng: maybe-all-gas
all-sid: maybe-all-libiberty
all-sid: maybe-all-bfd
all-sid: maybe-all-opcodes

View file

@ -1,3 +1,8 @@
2022-03-11 Vladimir Mezentsev <vladimir.mezentsev@oracle.com>
* MAINTAINERS: Add gprofng maintainer.
* README-how-to-make-a-release: Add gprofng.
2022-03-10 Nick Clifton <nickc@redhat.com>
* dwarf.c (use_debuginfod): New variable. Set to 1.

View file

@ -84,6 +84,7 @@ responsibility among the other maintainers.
FRV Alexandre Oliva <aoliva@sourceware.org>
GOLD Ian Lance Taylor <iant@google.com>
GOLD Cary Coutant <ccoutant@gmail.com>
gprofng Vladimir Mezentsev <vladimir.mezentsev@oracle.com>
H8300 Prafulla Thakare <prafulla.thakare@kpitcummins.com>
HPPA Dave Anglin <dave.anglin@bell.net>
HPPA elf32 Alan Modra <amodra@gmail.com>

View file

@ -35,7 +35,7 @@ Approx time to complete from here: 2 hours ....
in the gold directory - it has its own release numbering.
Likewise for the ChangeLog files in: bfd, binutils, config, cpu,
elfcpp, gas, gold, gprof, include, ld, libctf, libiberty, opcodes
elfcpp, gas, gold, gprof, gprofng, include, ld, libctf, libiberty, opcodes
and toplevel.
Add a note of the name of the new branch to binutils/BRANCHES.
@ -97,8 +97,8 @@ Approx time to complete from here: 2 hours ....
m4_define([BFD_VERSION], [2.39.50])
Regenerate various files on both branch and HEAD by configuring
with "--enable-maintainer-mode --enable-gold" and then building
with "make all-binutils all-gas all-gold all-gprof all-ld"
with "--enable-maintainer-mode --enable-gold --enable-shared" and then building
with "make all-binutils all-gas all-gold all-gprof all-gprofng all-ld"
Add ChangeLog entries for the updated files. Commit the changes.
Make sure that this includes the .pot files as well as the
@ -114,7 +114,7 @@ Approx time to complete from here: 2 hours ....
b. Create a source tarball of the BRANCH sources:
./src-release -x binutils
./src-release.sh -x binutils
c. Build a test target using this tarball.
@ -262,8 +262,8 @@ When the time comes to actually make the release....
chmod -R -w binutils-2.*
mkdir build
cd build
../binutils-2.*/configure --quiet --enable-gold --prefix=`pwd`/install --enable-plugins
make all-gas all-gold all-ld all-binutils all-gprof
../binutils-2.*/configure --quiet --enable-gold --prefix=`pwd`/install --enable-plugins --enable-shared
make all-gas all-gold all-ld all-binutils all-gprof all-gprofng
make check-gas check-binutils check-ld check-gold
make install-gas install-gold install-ld install-binutils

18
configure vendored
View file

@ -787,6 +787,7 @@ enable_as_accelerator_for
enable_offload_targets
enable_gold
enable_ld
enable_gprofng
enable_compressed_debug_sections
enable_libquadmath
enable_libquadmath_support
@ -1514,6 +1515,7 @@ Optional Features:
offload target compiler during the build
--enable-gold[=ARG] build gold [ARG={default,yes,no}]
--enable-ld[=ARG] build ld [ARG={default,yes,no}]
--enable-gprofng[=ARG] build gprofng [ARG={yes,no}]
--enable-compressed-debug-sections={all,gas,gold,ld,none}
Enable compressed debug sections for gas, gold or ld
by default
@ -3072,6 +3074,22 @@ $as_echo "$as_me: WARNING: neither ld nor gold are enabled" >&2;}
;;
esac
# Check whether --enable-gprofng was given.
if test "${enable_gprofng+set}" = set; then :
enableval=$enable_gprofng; enable_gprofng=$enableval
else
enable_gprofng=yes
fi
if test "$enable_gprofng" = "yes"; then
case "${target}" in
x86_64-*-linux* | i?86-*-linux* | aarch64-*-linux*)
configdirs="$configdirs gprofng"
;;
esac
fi
# PR gas/19109
# Decide the default method for compressing debug sections.
# Provide a configure time option to override our default.

View file

@ -392,6 +392,20 @@ case "${ENABLE_LD}" in
;;
esac
AC_ARG_ENABLE(gprofng,
[AS_HELP_STRING([[--enable-gprofng[=ARG]]],
[build gprofng @<:@ARG={yes,no}@:>@])],
enable_gprofng=$enableval,
enable_gprofng=yes)
if test "$enable_gprofng" = "yes"; then
case "${target}" in
x86_64-*-linux* | i?86-*-linux* | aarch64-*-linux*)
configdirs="$configdirs gprofng"
;;
esac
fi
# PR gas/19109
# Decide the default method for compressing debug sections.
# Provide a configure time option to override our default.

79
gprofng/Makefile.am Normal file
View file

@ -0,0 +1,79 @@
## Process this file with automake to generate Makefile.in
#
# Copyright (C) 2021 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
ACLOCAL_AMFLAGS = -I . -I ..
AUTOMAKE_OPTIONS = dejagnu foreign
if BUILD_COLLECTOR
COLLECTOR_SUBDIRS = libcollector
endif
if BUILD_SRC
SRC_SUBDIRS = src gp-display-html doc
endif
SUBDIRS = $(COLLECTOR_SUBDIRS) $(SRC_SUBDIRS)
DIST_SUBDIRS = libcollector src gp-display-html doc
# Setup the testing framework, if you have one
EXPECT = expect
RUNTEST = runtest
RUNTESTFLAGS =
BASEDIR = $(srcdir)/..
BFDDIR = $(BASEDIR)/bfd
jdk_inc = @jdk_inc@
LD_NO_AS_NEEDED = @LD_NO_AS_NEEDED@
GPROFNG_CFLAGS = @GPROFNG_CFLAGS@
GPROFNG_CPPFLAGS = @GPROFNG_CPPFLAGS@
GPROFNG_LIBDIR = @GPROFNG_LIBDIR@
AM_MAKEFLAGS = \
jdk_inc="$(jdk_inc)" \
LD_NO_AS_NEEDED="$(LD_NO_AS_NEEDED)" \
GPROFNG_CFLAGS="$(GPROFNG_CFLAGS)" \
GPROFNG_CPPFLAGS="$(GPROFNG_CPPFLAGS)" \
GPROFNG_LIBDIR="$(GPROFNG_LIBDIR)"
if TCL_TRY
check-DEJAGNU: site.exp development.exp
srcroot=`cd $(srcdir) && pwd`; export srcroot; \
r=`pwd`; export r; \
LC_ALL=C; export LC_ALL; \
EXPECT=$(EXPECT); export EXPECT; \
jdk_inc="$(jdk_inc)"; export jdk_inc; \
runtest=$(RUNTEST); \
if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
$$runtest --tool $(DEJATOOL) --srcdir $${srcroot}/testsuite \
MAKE="$(MAKE)" CC="$(CC)" CFLAGS="$(CFLAGS) $(PTHREAD_CFLAGS)" \
LDFLAGS="$(LDFLAGS)" LIBS="$(PTHREAD_LIBS) $(LIBS)" \
BUILDDIR="$(abs_top_builddir)" $(RUNTESTFLAGS); \
else echo "WARNING: could not find \`runtest'" 1>&2; :;\
fi
development.exp: $(BFDDIR)/development.sh
$(EGREP) "(development|experimental)=" $(BFDDIR)/development.sh \
| $(AWK) -F= '{ print "set " $$1 " " $$2 }' > $@
# development.sh is used to determine -Werror default.
CONFIG_STATUS_DEPENDENCIES = $(BFDDIR)/development.sh
EXTRA_DEJAGNU_SITE_CONFIG = development.exp
DISTCLEANFILES = site.exp development.exp
endif

940
gprofng/Makefile.in Normal file
View file

@ -0,0 +1,940 @@
# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2017 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@
#
# Copyright (C) 2021 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
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 = :
build_triplet = @build@
host_triplet = @host@
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../libtool.m4 \
$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
$(top_srcdir)/acinclude.m4 $(top_srcdir)/../config/warnings.m4 \
$(top_srcdir)/../config/enable.m4 \
$(top_srcdir)/../config/ax_pthread.m4 \
$(top_srcdir)/config/bison.m4 $(top_srcdir)/../bfd/version.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
$(am__configure_deps) $(am__DIST_COMMON)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
SOURCES =
DIST_SOURCES =
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
ctags-recursive dvi-recursive html-recursive info-recursive \
install-data-recursive install-dvi-recursive \
install-exec-recursive install-html-recursive \
install-info-recursive install-pdf-recursive \
install-ps-recursive install-recursive installcheck-recursive \
installdirs-recursive pdf-recursive ps-recursive \
tags-recursive uninstall-recursive
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
am__recursive_targets = \
$(RECURSIVE_TARGETS) \
$(RECURSIVE_CLEAN_TARGETS) \
$(am__extra_recursive_targets)
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
cscope distdir dist dist-all distcheck
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
CSCOPE = cscope
DEJATOOL = $(PACKAGE)
RUNTESTDEFAULTFLAGS = --tool $$tool --srcdir $$srcdir
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../ar-lib \
$(top_srcdir)/../compile $(top_srcdir)/../config.guess \
$(top_srcdir)/../config.sub $(top_srcdir)/../install-sh \
$(top_srcdir)/../ltmain.sh $(top_srcdir)/../missing \
$(top_srcdir)/../mkinstalldirs \
$(top_srcdir)/common/config.h.in README
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
am__remove_distdir = \
if test -d "$(distdir)"; then \
find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
&& rm -rf "$(distdir)" \
|| { sleep 5 && rm -rf "$(distdir)"; }; \
else :; fi
am__post_remove_distdir = $(am__remove_distdir)
am__relativize = \
dir0=`pwd`; \
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
sed_rest='s,^[^/]*/*,,'; \
sed_last='s,^.*/\([^/]*\)$$,\1,'; \
sed_butlast='s,/*[^/]*$$,,'; \
while test -n "$$dir1"; do \
first=`echo "$$dir1" | sed -e "$$sed_first"`; \
if test "$$first" != "."; then \
if test "$$first" = ".."; then \
dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
else \
first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
if test "$$first2" = "$$first"; then \
dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
else \
dir2="../$$dir2"; \
fi; \
dir0="$$dir0"/"$$first"; \
fi; \
fi; \
dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
done; \
reldir="$$dir2"
DIST_ARCHIVES = $(distdir).tar.gz
GZIP_ENV = --best
DIST_TARGETS = dist-gzip
distuninstallcheck_listfiles = find . -type f -print
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BUILD_SUBDIRS = @BUILD_SUBDIRS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
# Setup the testing framework, if you have one
EXPECT = expect
FGREP = @FGREP@
GPROFNG_CFLAGS = @GPROFNG_CFLAGS@
GPROFNG_CPPFLAGS = @GPROFNG_CPPFLAGS@
GPROFNG_LIBADD = @GPROFNG_LIBADD@
GPROFNG_LIBDIR = @GPROFNG_LIBDIR@
GREP = @GREP@
HELP2MAN = @HELP2MAN@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
JAVA = @JAVA@
JAVAC = @JAVAC@
LD = @LD@
LDFLAGS = @LDFLAGS@
LD_NO_AS_NEEDED = @LD_NO_AS_NEEDED@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PTHREAD_CC = @PTHREAD_CC@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
PTHREAD_LIBS = @PTHREAD_LIBS@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
WERROR = @WERROR@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
ax_pthread_config = @ax_pthread_config@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
gprofng_cflags = @gprofng_cflags@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
jdk_inc = @jdk_inc@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
subdirs = @subdirs@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
ACLOCAL_AMFLAGS = -I . -I ..
AUTOMAKE_OPTIONS = dejagnu foreign
@BUILD_COLLECTOR_TRUE@COLLECTOR_SUBDIRS = libcollector
@BUILD_SRC_TRUE@SRC_SUBDIRS = src gp-display-html doc
SUBDIRS = $(COLLECTOR_SUBDIRS) $(SRC_SUBDIRS)
DIST_SUBDIRS = libcollector src gp-display-html doc
RUNTEST = runtest
RUNTESTFLAGS =
BASEDIR = $(srcdir)/..
BFDDIR = $(BASEDIR)/bfd
AM_MAKEFLAGS = \
jdk_inc="$(jdk_inc)" \
LD_NO_AS_NEEDED="$(LD_NO_AS_NEEDED)" \
GPROFNG_CFLAGS="$(GPROFNG_CFLAGS)" \
GPROFNG_CPPFLAGS="$(GPROFNG_CPPFLAGS)" \
GPROFNG_LIBDIR="$(GPROFNG_LIBDIR)"
# development.sh is used to determine -Werror default.
@TCL_TRY_TRUE@CONFIG_STATUS_DEPENDENCIES = $(BFDDIR)/development.sh
@TCL_TRY_TRUE@EXTRA_DEJAGNU_SITE_CONFIG = development.exp
@TCL_TRY_TRUE@DISTCLEANFILES = site.exp development.exp
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive
.SUFFIXES:
am--refresh: Makefile
@:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
$(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
echo ' $(SHELL) ./config.status'; \
$(SHELL) ./config.status;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
$(am__cd) $(srcdir) && $(AUTOCONF)
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
$(am__aclocal_m4_deps):
config.h: stamp-h1
@test -f $@ || rm -f stamp-h1
@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
stamp-h1: $(top_srcdir)/common/config.h.in $(top_builddir)/config.status
@rm -f stamp-h1
cd $(top_builddir) && $(SHELL) ./config.status config.h
$(top_srcdir)/common/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
($(am__cd) $(top_srcdir) && $(AUTOHEADER))
rm -f stamp-h1
touch $@
distclean-hdr:
-rm -f config.h stamp-h1
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
distclean-libtool:
-rm -f libtool config.lt
# This directory's subdirectories are mostly independent; you can cd
# into them and run 'make' without going through this Makefile.
# To change the values of 'make' variables: instead of editing Makefiles,
# (1) if the variable is set in 'config.status', edit 'config.status'
# (which will cause the Makefiles to be regenerated when you run 'make');
# (2) otherwise, pass the desired values on the 'make' command line.
$(am__recursive_targets):
@fail=; \
if $(am__make_keepgoing); then \
failcom='fail=yes'; \
else \
failcom='exit 1'; \
fi; \
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
case "$@" in \
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
*) list='$(SUBDIRS)' ;; \
esac; \
for subdir in $$list; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| eval $$failcom; \
done; \
if test "$$dot_seen" = "no"; then \
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
fi; test -z "$$fail"
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-recursive
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
include_option=--etags-include; \
empty_fix=.; \
else \
include_option=--include; \
empty_fix=; \
fi; \
list='$(SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test ! -f $$subdir/TAGS || \
set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
fi; \
done; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-recursive
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscope: cscope.files
test ! -s cscope.files \
|| $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
clean-cscope:
-rm -f cscope.files
cscope.files: clean-cscope cscopelist
cscopelist: cscopelist-recursive
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
@TCL_TRY_FALSE@check-DEJAGNU: site.exp
@TCL_TRY_FALSE@ srcdir='$(srcdir)'; export srcdir; \
@TCL_TRY_FALSE@ EXPECT=$(EXPECT); export EXPECT; \
@TCL_TRY_FALSE@ if $(SHELL) -c "$(RUNTEST) --version" > /dev/null 2>&1; then \
@TCL_TRY_FALSE@ exit_status=0; l='$(DEJATOOL)'; for tool in $$l; do \
@TCL_TRY_FALSE@ if $(RUNTEST) $(AM_RUNTESTFLAGS) $(RUNTESTDEFAULTFLAGS) $(RUNTESTFLAGS); \
@TCL_TRY_FALSE@ then :; else exit_status=1; fi; \
@TCL_TRY_FALSE@ done; \
@TCL_TRY_FALSE@ else echo "WARNING: could not find '$(RUNTEST)'" 1>&2; :;\
@TCL_TRY_FALSE@ fi; \
@TCL_TRY_FALSE@ exit $$exit_status
site.exp: Makefile $(EXTRA_DEJAGNU_SITE_CONFIG)
@echo 'Making a new site.exp file ...'
@echo '## these variables are automatically generated by make ##' >site.tmp
@echo '# Do not edit here. If you wish to override these values' >>site.tmp
@echo '# edit the last section' >>site.tmp
@echo 'set srcdir "$(srcdir)"' >>site.tmp
@echo "set objdir `pwd`" >>site.tmp
@echo 'set build_alias "$(build_alias)"' >>site.tmp
@echo 'set build_triplet $(build_triplet)' >>site.tmp
@echo 'set host_alias "$(host_alias)"' >>site.tmp
@echo 'set host_triplet $(host_triplet)' >>site.tmp
@list='$(EXTRA_DEJAGNU_SITE_CONFIG)'; for f in $$list; do \
echo "## Begin content included from file $$f. Do not modify. ##" \
&& cat `test -f "$$f" || echo '$(srcdir)/'`$$f \
&& echo "## End content included from file $$f. ##" \
|| exit 1; \
done >> site.tmp
@echo "## End of auto-generated content; you can edit from here. ##" >> site.tmp
@if test -f site.exp; then \
sed -e '1,/^## End of auto-generated content.*##/d' site.exp >> site.tmp; \
fi
@-rm -f site.bak
@test ! -f site.exp || mv site.exp site.bak
@mv site.tmp site.exp
distclean-DEJAGNU:
-rm -f site.exp site.bak
-l='$(DEJATOOL)'; for tool in $$l; do \
rm -f $$tool.sum $$tool.log; \
done
distdir: $(DISTFILES)
$(am__remove_distdir)
test -d "$(distdir)" || mkdir "$(distdir)"
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
$(am__make_dryrun) \
|| test -d "$(distdir)/$$subdir" \
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|| exit 1; \
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
$(am__relativize); \
new_distdir=$$reldir; \
dir1=$$subdir; dir2="$(top_distdir)"; \
$(am__relativize); \
new_top_distdir=$$reldir; \
echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
($(am__cd) $$subdir && \
$(MAKE) $(AM_MAKEFLAGS) \
top_distdir="$$new_top_distdir" \
distdir="$$new_distdir" \
am__remove_distdir=: \
am__skip_length_check=: \
am__skip_mode_fix=: \
distdir) \
|| exit 1; \
fi; \
done
-test -n "$(am__skip_mode_fix)" \
|| find "$(distdir)" -type d ! -perm -755 \
-exec chmod u+rwx,go+rx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|| chmod -R a+r "$(distdir)"
dist-gzip: distdir
tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
$(am__post_remove_distdir)
dist-bzip2: distdir
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
$(am__post_remove_distdir)
dist-lzip: distdir
tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
$(am__post_remove_distdir)
dist-xz: distdir
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
$(am__post_remove_distdir)
dist-tarZ: distdir
@echo WARNING: "Support for distribution archives compressed with" \
"legacy program 'compress' is deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
$(am__post_remove_distdir)
dist-shar: distdir
@echo WARNING: "Support for shar distribution archives is" \
"deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
$(am__post_remove_distdir)
dist-zip: distdir
-rm -f $(distdir).zip
zip -rq $(distdir).zip $(distdir)
$(am__post_remove_distdir)
dist dist-all:
$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
$(am__post_remove_distdir)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
# tarfile.
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.lz*) \
lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
*.tar.xz*) \
xz -dc $(distdir).tar.xz | $(am__untar) ;;\
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac
chmod -R a-w $(distdir)
chmod u+w $(distdir)
mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
chmod a-w $(distdir)
test -d $(distdir)/_build || exit 0; \
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
&& am__cwd=`pwd` \
&& $(am__cd) $(distdir)/_build/sub \
&& ../../configure \
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
$(DISTCHECK_CONFIGURE_FLAGS) \
--srcdir=../.. --prefix="$$dc_install_base" \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
distuninstallcheck \
&& chmod -R a-w "$$dc_install_base" \
&& ({ \
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
} || { rm -rf "$$dc_destdir"; exit 1; }) \
&& rm -rf "$$dc_destdir" \
&& $(MAKE) $(AM_MAKEFLAGS) dist \
&& rm -rf $(DIST_ARCHIVES) \
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
&& cd "$$am__cwd" \
|| exit 1
$(am__post_remove_distdir)
@(echo "$(distdir) archives ready for distribution: "; \
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
distuninstallcheck:
@test -n '$(distuninstallcheck_dir)' || { \
echo 'ERROR: trying to run $@ with an empty' \
'$$(distuninstallcheck_dir)' >&2; \
exit 1; \
}; \
$(am__cd) '$(distuninstallcheck_dir)' || { \
echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
exit 1; \
}; \
test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
|| { echo "ERROR: files left after uninstall:" ; \
if test -n "$(DESTDIR)"; then \
echo " (check DESTDIR support)"; \
fi ; \
$(distuninstallcheck_listfiles) ; \
exit 1; } >&2
distcleancheck: distclean
@if test '$(srcdir)' = . ; then \
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
exit 1 ; \
fi
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|| { echo "ERROR: files left in build directory after distclean:" ; \
$(distcleancheck_listfiles) ; \
exit 1; } >&2
check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU
check: check-recursive
all-am: Makefile config.h
installdirs: installdirs-recursive
installdirs-am:
install: install-recursive
install-exec: install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-recursive
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
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-recursive
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -f Makefile
distclean-am: clean-am distclean-DEJAGNU distclean-generic \
distclean-hdr distclean-libtool distclean-tags
dvi: dvi-recursive
dvi-am:
html: html-recursive
html-am:
info: info-recursive
info-am:
install-data-am:
install-dvi: install-dvi-recursive
install-dvi-am:
install-exec-am:
install-html: install-html-recursive
install-html-am:
install-info: install-info-recursive
install-info-am:
install-man:
install-pdf: install-pdf-recursive
install-pdf-am:
install-ps: install-ps-recursive
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf $(top_srcdir)/autom4te.cache
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-recursive
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
pdf: pdf-recursive
pdf-am:
ps: ps-recursive
ps-am:
uninstall-am:
.MAKE: $(am__recursive_targets) all check-am install-am install-strip
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
am--refresh check check-DEJAGNU check-am clean clean-cscope \
clean-generic clean-libtool cscope cscopelist-am ctags \
ctags-am dist dist-all dist-bzip2 dist-gzip dist-lzip \
dist-shar dist-tarZ dist-xz dist-zip distcheck distclean \
distclean-DEJAGNU distclean-generic distclean-hdr \
distclean-libtool distclean-tags distcleancheck distdir \
distuninstallcheck dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
install-html-am install-info install-info-am install-man \
install-pdf install-pdf-am install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
installdirs-am maintainer-clean maintainer-clean-generic \
mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
ps ps-am tags tags-am uninstall uninstall-am
.PRECIOUS: Makefile
@TCL_TRY_TRUE@check-DEJAGNU: site.exp development.exp
@TCL_TRY_TRUE@ srcroot=`cd $(srcdir) && pwd`; export srcroot; \
@TCL_TRY_TRUE@ r=`pwd`; export r; \
@TCL_TRY_TRUE@ LC_ALL=C; export LC_ALL; \
@TCL_TRY_TRUE@ EXPECT=$(EXPECT); export EXPECT; \
@TCL_TRY_TRUE@ jdk_inc="$(jdk_inc)"; export jdk_inc; \
@TCL_TRY_TRUE@ runtest=$(RUNTEST); \
@TCL_TRY_TRUE@ if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
@TCL_TRY_TRUE@ $$runtest --tool $(DEJATOOL) --srcdir $${srcroot}/testsuite \
@TCL_TRY_TRUE@ MAKE="$(MAKE)" CC="$(CC)" CFLAGS="$(CFLAGS) $(PTHREAD_CFLAGS)" \
@TCL_TRY_TRUE@ LDFLAGS="$(LDFLAGS)" LIBS="$(PTHREAD_LIBS) $(LIBS)" \
@TCL_TRY_TRUE@ BUILDDIR="$(abs_top_builddir)" $(RUNTESTFLAGS); \
@TCL_TRY_TRUE@ else echo "WARNING: could not find \`runtest'" 1>&2; :;\
@TCL_TRY_TRUE@ fi
@TCL_TRY_TRUE@development.exp: $(BFDDIR)/development.sh
@TCL_TRY_TRUE@ $(EGREP) "(development|experimental)=" $(BFDDIR)/development.sh \
@TCL_TRY_TRUE@ | $(AWK) -F= '{ print "set " $$1 " " $$2 }' > $@
# 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:

100
gprofng/README Normal file
View file

@ -0,0 +1,100 @@
What is gprofng?
Gprofng is the GNU Next Generation profiler for analyzing the performance
of Linux applications. Gprofng allows you to:
- Profile C / C++ / Java / Scala applications without needing to recompile
- Profile multi-threaded applications
- Analyze and compare multiple experiments
- Use time-based sampling and / or hardware event counters
Building gprofng
Gprofng is distributed with binutils. To build gprofng, you build binutils.
Overview:
1. Set paths
2. Verify prerequisites
3. Git clone
4. Configure, make, and make install
Details follow for each of these.
1. Set paths
If you are configuring binutils for the default location, it will use:
/usr/local
In your shell initialization procedure, set your paths using commands
similar to these:
export PATH=/usr/local/bin:$PATH
export MANPATH=/usr/local/share/man:$MANPATH
export INFOPATH=/usr/local/share/info/:$INFOPATH
2. Verify prerequisites
To build a recent version of binutils, it is useful to have a developer
system with the most recent compilers, libraries, and operating system.
Development systems will typically already include most of these:
bison bison-devel bzip2 elfutils-debuginfod-client-devel
expat-devel flex gcc gcc-c++ git-core git-core-doc gmp-devel
help2man libbabeltrace-devel libipt-devel m4 make mpfr-devel
ncurses-devel perl-Data-Dumper tar texinfo xz zlib-devel
java-17-openjdk-devel
CAUTION: The list of prerequisites changes depending on your operating system
and changes as binutils evolves. The list above is a snapshot of the useful
packages in early 2022 for Red Hat Enterprise Linux and Oracle Linux.
Your system may use other packages; for example, you may be able to use a
different version of Java than shown above. If there are failures, you may
need to search for other packages as described in the "Hints" section below.
3. Git clone
Select a binutils repository and a branch that you would like
to start from. For example, to clone from the master at
sourceware.org, you could say:
git clone http://sourceware.org/git/binutils-gdb.git CloneDir
4. Configure, make, and install
There are many options for configure (see: configure --help). For example,
--prefix sets the destination, as described in the "Hints" section below.
If the default destination /usr/local is acceptable for your needs, then
after the clone operation finishes, you can simply say:
mkdir build
cd build
../CloneDir/configure
make
sudo make install
Getting started
To start using gprofng, see the tutorial available by saying:
info gprofng
Hints and tips for building binutils
- Use the script(1) command to write a log of your build.
- If you run multiple commands at once (for example: make --jobs=10) then you
should also use make option:
--output-sync
Without --output-sync, the log would be difficult to interpret.
- Search the log for errors and warnings, for example:
configure: WARNING: <package> is missing or unusable; some features
may be unavailable.
The above message suggests that <package> may be needed on your system.
- Sometimes the above message is not sufficiently specific to guide you to
the right package. In the directory where the failure happens, config.log
may identify a specific missing file, and your package manager may allow
you to search for it. For example, if build/gprofng/config.log shows that
javac is missing, and if your package manager is dnf, you could try:
dnf --repo='*' whatprovides '*/javac'
- You can set a custom destination directory using configure --prefix.
This is useful if you prefer not to change /usr/local, or if you are not
allowed to do so. If you set a custom prefix, be sure to change all three
paths mentioned in the PATH section above.

4
gprofng/acinclude.m4 Normal file
View file

@ -0,0 +1,4 @@
m4_include([../config/warnings.m4])
m4_include([../config/enable.m4])
m4_include([../config/ax_pthread.m4])
m4_include([config/bison.m4])

1254
gprofng/aclocal.m4 vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,44 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/*
* This file describes the enum's, etc. shared by the collector control
* class and libcollector and its modules. It is #included in collctrl.h
* so any changes to it should follow the procedure described there.
*/
#ifndef _CC_LIBCOLLECTOR_H
#define _CC_LIBCOLLECTOR_H
/* definitions for synchronization tracing scope -- a bit mask */
#define SYNCSCOPE_NATIVE 0x1
#define SYNCSCOPE_JAVA 0x2
typedef enum
{
FOLLOW_NONE = 0x0,
FOLLOW_EXEC = 0x1,
FOLLOW_FORK = 0x2,
FOLLOW_ON = 0x3,
FOLLOW_COMBO = 0x4,
FOLLOW_ALL = 0x7
} Follow_type;
#endif /* !__CC_LIBCOLLECTOR_H */

117
gprofng/common/config.h.in Normal file
View file

@ -0,0 +1,117 @@
/* common/config.h.in. Generated from configure.ac by autoheader. */
/* Enable debugging output. */
#undef DEBUG
/* Enable java profiling */
#undef GPROFNG_JAVA_PROFILING
/* Define to 1 if you have the declaration of `basename', and to 0 if you
don't. */
#undef HAVE_DECL_BASENAME
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
/* Have PTHREAD_PRIO_INHERIT. */
#undef HAVE_PTHREAD_PRIO_INHERIT
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strsignal' function. */
#undef HAVE_STRSIGNAL
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* Version number of package */
#undef VERSION
/* Define to 1 if on MINIX. */
#undef _MINIX
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
#undef _POSIX_1_SOURCE
/* Define to 1 if you need to in order for `stat' and other things to work. */
#undef _POSIX_SOURCE

3023
gprofng/common/core_pcbe.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,303 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _CPU_FREQUENCY_H
#define _CPU_FREQUENCY_H
#ifdef __cplusplus
extern "C"
{
#endif
#include <alloca.h>
#include <unistd.h> /* processor_info_t */
#include <fcntl.h>
typedef unsigned char uint8_t;
#define MAXSTRLEN 1024
/*
* This file provide the api to detect Intel CPU frequency variation features
*/
#define COL_CPUFREQ_NONE 0x0000
#define COL_CPUFREQ_SCALING 0x0001
#define COL_CPUFREQ_TURBO 0x0002
#if defined(__i386__) || defined(__x86_64)
// XXXX This is a rough table to estimate frequency increment due to intel turbo boost.
// CPU with different stepping and different core number have different turbo increment.
// It is used internally here, and is not implemented on SPARC
// YLM: one can use cputrack to estimate max turbo frequency
// example: for a cpu-bound app that runs for > 10 seconds, count cycles for 10 seconds:
// cputrack -T 10 -v -c cpu_clk_unhalted.thread_p a.out
static int
get_max_turbo_freq (int model)
{
switch (model)
{
// Nehalem
case 30:// Core i7-870: 2/2/4/5
return 2 * 133333;
case 26:// Xeon L5520: 1/1/1/2
return 2 * 133333;
case 46:// Xeon E7540: 2
return 2 * 133333;
// Westmere
case 37:// Core i5-520M: 2/4
return 2 * 133333;
case 44:// Xeon E5620: 1/1/2/2
return 2 * 133333;
case 47:// Xeon E7-2820: 1/1/1/2
return 1 * 133333;
// Sandy Bridge
case 42:// Core i5-2500: 1/2/3/4
return 3 * 100000;
// http://ark.intel.com/products/64584/Intel-Xeon-Processor-E5-2660-20M-Cache-2_20-GHz-8_00-GTs-Intel-QPI
case 45:// Xeon E5-2660 GenuineIntel 206D7 family 6 model 45 step 7 clock 2200 MHz
return 8 * 100000;
// Ivy Bridge
case 58:// Core i7-3770: 3/4/5/5
return 4 * 100000;
case 62:// Xeon E5-2697: 3/3/3/3/3/3/3/4/5/6/7/8
return 7 * 100000;
// Haswell
case 60:
return 789000; // empirically we see 3189 MHz - 2400 MHz
case 63:
return 1280000; // empirically we see 3580 MHz - 2300 MHz for single-threaded
// return 500000; // empirically we see 2800 MHz - 2300 MHz for large throughput
// Broadwell
// where are these values listed?
// maybe try https://en.wikipedia.org/wiki/Broadwell_%28microarchitecture%29#Server_processors
case 61:
return 400000;
case 71:
return 400000;
case 79:
return 950000; // empirically we see (3550-2600) MHz for single-threaded on x6-2a
case 85:
return 1600000; // X7: empirically see ~3.7GHz with single thread, baseline is 2.1Ghz Return 3,700,000-2,100,000
case 31: // Nehalem?
case 28: // Atom
case 69: // Haswell
case 70: // Haswell
case 78: // Skylake
case 94: // Skylake
default:
return 0;
}
}
#endif
/*
* parameter: mode, pointer to a 8bit mode indicator
* return: max cpu frequency in MHz
*/
//YXXX Updating this function? Check similar cut/paste code in:
// collctrl.cc::Coll_Ctrl()
// collector.c::log_header_write()
// cpu_frequency.h::get_cpu_frequency()
static int
get_cpu_frequency (uint8_t *mode)
{
int ret_freq = 0;
if (mode != NULL)
*mode = COL_CPUFREQ_NONE;
FILE *procf = fopen ("/proc/cpuinfo", "r");
if (procf != NULL)
{
char temp[1024];
int cpu = -1;
#if defined(__i386__) || defined(__x86_64)
int model = -1;
int family = -1;
#endif
while (fgets (temp, 1024, procf) != NULL)
{
if (strncmp (temp, "processor", strlen ("processor")) == 0)
{
char *val = strchr (temp, ':');
cpu = val ? atoi (val + 1) : -1;
}
#if defined(__i386__) || defined(__x86_64)
else if (strncmp (temp, "model", strlen ("model")) == 0
&& strstr (temp, "name") == 0)
{
char *val = strchr (temp, ':');
model = val ? atoi (val + 1) : -1;
}
else if (strncmp (temp, "cpu family", strlen ("cpu family")) == 0)
{
char *val = strchr (temp, ':');
family = val ? atoi (val + 1) : -1;
}
#endif
else if (strncmp (temp, "cpu MHz", strlen ("cpu MHz")) == 0)
{
char *val = strchr (temp, ':');
int mhz = val ? atoi (val + 1) : 0; /* reading it as int is fine */
char scaling_freq_file[MAXSTRLEN + 1];
snprintf (scaling_freq_file, sizeof (scaling_freq_file),
"/sys/devices/system/cpu/cpu%d/cpufreq/scaling_driver", cpu);
int intel_pstate = 0;
int no_turbo = 0;
if (access (scaling_freq_file, R_OK) == 0)
{
FILE *cpufreqd = fopen (scaling_freq_file, "r");
if (cpufreqd != NULL)
{
if (fgets (temp, 1024, cpufreqd) != NULL
&& strncmp (temp, "intel_pstate", sizeof ("intel_pstate") - 1) == 0)
intel_pstate = 1;
fclose (cpufreqd);
}
}
snprintf (scaling_freq_file, sizeof (scaling_freq_file),
"/sys/devices/system/cpu/intel_pstate/no_turbo");
if (access (scaling_freq_file, R_OK) == 0)
{
FILE *pstatent = fopen (scaling_freq_file, "r");
if (pstatent != NULL)
{
if (fgets (temp, 1024, pstatent) != NULL)
if (strncmp (temp, "1", sizeof ("1") - 1) == 0)
no_turbo = 1;
fclose (pstatent);
}
}
snprintf (scaling_freq_file, sizeof (scaling_freq_file),
"/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpu);
int frequency_scaling = 0;
int turbo_mode = 0;
if (access (scaling_freq_file, R_OK) == 0)
{
FILE *cpufreqf = fopen (scaling_freq_file, "r");
if (cpufreqf != NULL)
{
if (fgets (temp, 1024, cpufreqf) != NULL)
{
int ondemand = 0;
if (strncmp (temp, "ondemand", sizeof ("ondemand") - 1) == 0)
ondemand = 1;
int performance = 0;
if (strncmp (temp, "performance", sizeof ("performance") - 1) == 0)
performance = 1;
int powersave = 0;
if (strncmp (temp, "powersave", sizeof ("powersave") - 1) == 0)
powersave = 1;
if (intel_pstate || ondemand || performance)
{
snprintf (scaling_freq_file, sizeof (scaling_freq_file),
"/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
if (access (scaling_freq_file, R_OK) == 0)
{
FILE * cpufreqf_max;
if ((cpufreqf_max = fopen (scaling_freq_file, "r")) != NULL)
{
if (fgets (temp, 1024, cpufreqf_max) != NULL)
{
int tmpmhz = atoi (temp);
snprintf (scaling_freq_file, sizeof (scaling_freq_file),
"/sys/devices/system/cpu/cpu%d/cpufreq/scaling_available_frequencies", cpu);
if (intel_pstate)
{
frequency_scaling = 1;
turbo_mode = !no_turbo;
if (powersave)
// the system might have been relatively cold
// so we might do better with scaling_max_freq
mhz = (int) (((double) tmpmhz / 1000.0) + 0.5);
}
else if (access (scaling_freq_file, R_OK) == 0)
{
FILE * cpufreqf_ava;
if ((cpufreqf_ava = fopen (scaling_freq_file, "r")) != NULL)
{
if (fgets (temp, 1024, cpufreqf_ava) != NULL)
{
if (strchr (temp, ' ') != strrchr (temp, ' ') && ondemand)
frequency_scaling = 1;
if (tmpmhz > 1000)
{
#if defined(__i386__) || defined(__x86_64)
if (family == 6)
{
// test turbo mode
char non_turbo_max_freq[1024];
snprintf (non_turbo_max_freq, sizeof (non_turbo_max_freq),
"%d", tmpmhz - 1000);
if (strstr (temp, non_turbo_max_freq))
{
turbo_mode = 1;
tmpmhz = (tmpmhz - 1000) + get_max_turbo_freq (model);
}
}
#endif
}
}
fclose (cpufreqf_ava);
}
mhz = (int) (((double) tmpmhz / 1000.0) + 0.5);
}
}
fclose (cpufreqf_max);
}
}
}
}
fclose (cpufreqf);
}
}
if (mhz > ret_freq)
ret_freq = mhz;
if (frequency_scaling && mode != NULL)
*mode |= COL_CPUFREQ_SCALING;
if (turbo_mode && mode != NULL)
*mode |= COL_CPUFREQ_TURBO;
}
else if (strncmp (temp, "Cpu", 3) == 0 && temp[3] != '\0' &&
strncmp (strchr (temp + 1, 'C') ? strchr (temp + 1, 'C') : (temp + 4), "ClkTck", 6) == 0)
{ // sparc-Linux
char *val = strchr (temp, ':');
if (val)
{
unsigned long long freq;
sscanf (val + 2, "%llx", &freq);
int mhz = (unsigned int) (((double) freq) / 1000000.0 + 0.5);
if (mhz > ret_freq)
ret_freq = mhz;
}
}
}
fclose (procf);
}
return ret_freq;
}
#ifdef __cplusplus
}
#endif
#endif /*_CPU_FREQUENCY_H*/

203
gprofng/common/cpuid.c Normal file
View file

@ -0,0 +1,203 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#if defined(__i386__) || defined(__x86_64)
#include <cpuid.h> /* GCC-provided */
#elif defined(__aarch64__)
#define ATTRIBUTE_UNUSED __attribute__((unused))
static inline uint_t __attribute_const__
__get_cpuid (unsigned int op ATTRIBUTE_UNUSED, unsigned int *eax,
unsigned int *ebx ATTRIBUTE_UNUSED,
unsigned int *ecx ATTRIBUTE_UNUSED, unsigned int *edx ATTRIBUTE_UNUSED)
{
// CPUID bit assignments:
// [31:24] IMPLEMENTER (0x50 - ARM_CPU_IMP_APM)
// [23:20] VARIANT indicates processor revision (0x2 = Revision 2)
// [19:16] Constant (Reads as 0xF)
// [15:04] PARTNO indicates part number (0xC23 = Cortex-M3)
// [03:00] REVISION indicates patch release (0x0 = Patch 0)
// unsigned long v = 0;
// __asm volatile ("MRS %[result], MPIDR_EL1" : [result] "=r" (v));
// Tprintf(DBG_LT0, "cpuid.c:%d read_cpuid_id() MPIDR_EL1=0x%016lx\n", __LINE__, v);
uint_t res = 0;
__asm volatile ("MRS %[result], MIDR_EL1" : [result] "=r" (*eax));
Tprintf (DBG_LT0, "cpuid.c:%d read_cpuid_id() MIDR_EL1=0x%016x\n", __LINE__, *eax);
return res;
}
#endif
/*
* Various routines to handle identification
* and classification of x86 processors.
*/
#define IS_GLOBAL /* externally visible */
#define X86_VENDOR_Intel 0
#define X86_VENDORSTR_Intel "GenuineIntel"
#define X86_VENDOR_IntelClone 1
#define X86_VENDOR_AMD 2
#define X86_VENDORSTR_AMD "AuthenticAMD"
#define BITX(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
#define CPI_FAMILY_XTD(reg) BITX(reg, 27, 20)
#define CPI_MODEL_XTD(reg) BITX(reg, 19, 16)
#define CPI_TYPE(reg) BITX(reg, 13, 12)
#define CPI_FAMILY(reg) BITX(reg, 11, 8)
#define CPI_STEP(reg) BITX(reg, 3, 0)
#define CPI_MODEL(reg) BITX(reg, 7, 4)
#define IS_EXTENDED_MODEL_INTEL(model) ((model) == 0x6 || (model) >= 0xf)
typedef struct
{
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
} cpuid_regs_t;
typedef struct
{
unsigned int cpi_model;
unsigned int cpi_family;
unsigned int cpi_vendor; /* enum of cpi_vendorstr */
unsigned int cpi_maxeax; /* fn 0: %eax */
char cpi_vendorstr[13]; /* fn 0: %ebx:%ecx:%edx */
} cpuid_info_t;
#if defined(__i386__) || defined(__x86_64)
static uint_t
cpuid_vendorstr_to_vendorcode (char *vendorstr)
{
if (strcmp (vendorstr, X86_VENDORSTR_Intel) == 0)
return X86_VENDOR_Intel;
else if (strcmp (vendorstr, X86_VENDORSTR_AMD) == 0)
return X86_VENDOR_AMD;
else
return X86_VENDOR_IntelClone;
}
static int
my_cpuid (unsigned int op, cpuid_regs_t *regs)
{
regs->eax = regs->ebx = regs->ecx = regs->edx = 0;
int ret = __get_cpuid (op, &regs->eax, &regs->ebx, &regs->ecx, &regs->edx);
TprintfT (DBG_LT1, "my_cpuid: __get_cpuid(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) returns %d\n",
op, regs->eax, regs->ebx, regs->ecx, regs->edx, ret);
return ret;
}
#endif
static cpuid_info_t *
get_cpuid_info ()
{
static int cpuid_inited = 0;
static cpuid_info_t cpuid_info;
cpuid_info_t *cpi = &cpuid_info;
if (cpuid_inited)
return cpi;
cpuid_inited = 1;
#if defined(__aarch64__)
// CPUID bit assignments:
// [31:24] IMPLEMENTER (0x50 - ARM_CPU_IMP_APM)
// [23:20] VARIANT indicates processor revision (0x2 = Revision 2)
// [19:16] Constant (Reads as 0xF)
// [15:04] PARTNO indicates part number (0xC23 = Cortex-M3)
// [03:00] REVISION indicates patch release (0x0 = Patch 0)
uint_t reg = 0;
__asm volatile ("MRS %[result], MIDR_EL1" : [result] "=r" (reg));
cpi->cpi_vendor = reg >> 24;
cpi->cpi_model = (reg >> 4) & 0xfff;
switch (cpi->cpi_vendor)
{
case ARM_CPU_IMP_APM:
case ARM_CPU_IMP_ARM:
case ARM_CPU_IMP_CAVIUM:
case ARM_CPU_IMP_BRCM:
case ARM_CPU_IMP_QCOM:
strncpy (cpi->cpi_vendorstr, AARCH64_VENDORSTR_ARM, sizeof (cpi->cpi_vendorstr));
break;
default:
strncpy (cpi->cpi_vendorstr, "UNKNOWN ARM", sizeof (cpi->cpi_vendorstr));
break;
}
Tprintf (DBG_LT0, "cpuid.c:%d read_cpuid_id() MIDR_EL1==0x%016x cpi_vendor=%d cpi_model=%d\n",
__LINE__, (unsigned int) reg, cpi->cpi_vendor, cpi->cpi_model);
#elif defined(__i386__) || defined(__x86_64)
cpuid_regs_t regs;
my_cpuid (0, &regs);
cpi->cpi_maxeax = regs.eax;
((uint32_t *) cpi->cpi_vendorstr)[0] = regs.ebx;
((uint32_t *) cpi->cpi_vendorstr)[1] = regs.edx;
((uint32_t *) cpi->cpi_vendorstr)[2] = regs.ecx;
cpi->cpi_vendorstr[12] = 0;
cpi->cpi_vendor = cpuid_vendorstr_to_vendorcode (cpi->cpi_vendorstr);
my_cpuid (1, &regs);
cpi->cpi_model = CPI_MODEL (regs.eax);
cpi->cpi_family = CPI_FAMILY (regs.eax);
if (cpi->cpi_family == 0xf)
cpi->cpi_family += CPI_FAMILY_XTD (regs.eax);
/*
* Beware: AMD uses "extended model" iff base *FAMILY* == 0xf.
* Intel, and presumably everyone else, uses model == 0xf, as
* one would expect (max value means possible overflow). Sigh.
*/
switch (cpi->cpi_vendor)
{
case X86_VENDOR_Intel:
if (IS_EXTENDED_MODEL_INTEL (cpi->cpi_family))
cpi->cpi_model += CPI_MODEL_XTD (regs.eax) << 4;
break;
case X86_VENDOR_AMD:
if (CPI_FAMILY (cpi->cpi_family) == 0xf)
cpi->cpi_model += CPI_MODEL_XTD (regs.eax) << 4;
break;
default:
if (cpi->cpi_model == 0xf)
cpi->cpi_model += CPI_MODEL_XTD (regs.eax) << 4;
break;
}
#endif
return cpi;
}
static inline uint_t
cpuid_getvendor ()
{
return get_cpuid_info ()->cpi_vendor;
}
static inline uint_t
cpuid_getfamily ()
{
return get_cpuid_info ()->cpi_family;
}
static inline uint_t
cpuid_getmodel ()
{
return get_cpuid_info ()->cpi_model;
}

58
gprofng/common/gp-defs.h Normal file
View file

@ -0,0 +1,58 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _GP_DEFS_H_
#define _GP_DEFS_H_
/* Define the ARCH and WSIZE predicates */
/*
* The way we define and use predicates is similar to the
* standard #assert with one important exception:
* if an argument of a predicate is not known the result
* is 'false' and we want a compile time error to avoid
* silent results from typos like ARCH(INTEL), COMPILER(gnu),
* etc.
*/
#define ARCH(x) TOK_A_##x(ARCH)
#define TOK_A_Aarch64(x) x##_Aarch64
#define TOK_A_SPARC(x) x##_SPARC
#define TOK_A_Intel(x) x##_Intel
#define WSIZE(x) TOK_W_##x(WSIZE)
#define TOK_W_32(x) x##_32
#define TOK_W_64(x) x##_64
#if defined(sparc) || defined(__sparcv9)
#define ARCH_SPARC 1
#elif defined(__i386__) || defined(__x86_64)
#define ARCH_Intel 1
#elif defined(__aarch64__)
#define ARCH_Aarch64 1
#else
#error "Undefined platform"
#endif
#if defined(__sparcv9) || defined(__x86_64) || defined(__aarch64__)
#define WSIZE_64 1
#else
#define WSIZE_32 1
#endif
#endif

View file

@ -0,0 +1,186 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _EXPERIMENT_H
#define _EXPERIMENT_H
/* version numbers define experiment format */
#define SUNPERF_VERNUM 12
#define SUNPERF_VERNUM_MINOR 4
/* backward compatibility down to: */
#define SUNPERF_VERNUM_LEAST 12
#include "Emsgnum.h" /* for COL_ERROR_*, etc. symbols */
#define SP_REMOTE_PROTOCOL_VERSION "12.4.1"
#define SP_GROUP_HEADER "#analyzer experiment group"
/* Experiment name macro definitions */
/* for descendant experiments */
#define DESCENDANT_EXPT_KEY ".er/_"
#define IS_DESC_EXPT(exptname) (strstr(exptname,DESCENDANT_EXPT_KEY) != NULL)
#define IS_FNDR_EXPT(exptname) (strstr(exptname,DESCENDANT_EXPT_KEY) == NULL)
/* File name definitions */
#define SP_ARCHIVES_DIR "archives"
#define SP_ARCHIVE_LOG_FILE "archive.log"
#define SP_LOG_FILE "log.xml"
#define SP_NOTES_FILE "notes"
#define SP_IFREQ_FILE "ifreq"
#define SP_MAP_FILE "map.xml"
#define SP_LABELS_FILE "labels.xml"
#define SP_DYNTEXT_FILE "dyntext"
#define SP_OVERVIEW_FILE "overview"
#define SP_PROFILE_FILE "profile"
#define SP_SYNCTRACE_FILE "synctrace"
#define SP_IOTRACE_FILE "iotrace"
#define SP_OMPTRACE_FILE "omptrace"
#define SP_MPVIEW_FILE "mpview.dat3"
#define SP_HWCNTR_FILE "hwcounters"
#define SP_HEAPTRACE_FILE "heaptrace"
#define SP_JCLASSES_FILE "jclasses"
#define SP_DYNAMIC_CLASSES "jdynclasses"
#define SP_RACETRACE_FILE "dataraces"
#define SP_DEADLOCK_FILE "deadlocks"
#define SP_FRINFO_FILE "frameinfo"
#define SP_WARN_FILE "warnings.xml"
#define SP_LIBCOLLECTOR_NAME "libgp-collector.so"
#define SP_LIBAUDIT_NAME "libcollect-ng.so"
/* XML tags */
#define SP_TAG_COLLECTOR "collector"
#define SP_TAG_CPU "cpu"
#define SP_TAG_DATAPTR "dataptr"
#define SP_TAG_EVENT "event"
#define SP_TAG_EXPERIMENT "experiment"
#define SP_TAG_FIELD "field"
#define SP_TAG_PROCESS "process"
#define SP_TAG_PROFILE "profile"
#define SP_TAG_PROFDATA "profdata"
#define SP_TAG_PROFPCKT "profpckt"
#define SP_TAG_SETTING "setting"
#define SP_TAG_STATE "state"
#define SP_TAG_SYSTEM "system"
#define SP_TAG_POWERM "powerm"
#define SP_TAG_FREQUENCY "frequency"
#define SP_TAG_DTRACEFATAL "dtracefatal"
/* records for log and loadobjects files */
/* note that these are in alphabetical order */
#define SP_JCMD_ARCH "architecture"
#define SP_JCMD_ARCHIVE "archive_run"
#define SP_JCMD_ARGLIST "arglist"
#define SP_JCMD_BLKSZ "blksz"
#define SP_JCMD_CERROR "cerror"
#define SP_JCMD_CLASS_LOAD "class_load"
#define SP_JCMD_CLASS_UNLOAD "class_unload"
#define SP_JCMD_COLLENV "collenv"
#define SP_JCMD_COMMENT "comment"
#define SP_JCMD_CPUID "cpuid"
#define SP_JCMD_CWARN "cwarn"
#define SP_JCMD_CWD "cwd"
#define SP_JCMD_CVERSION "cversion"
#define SP_JCMD_DATARACE "datarace"
#define SP_JCMD_DEADLOCK "deadlock"
#define SP_JCMD_DELAYSTART "delay_start"
#define SP_JCMD_DESC_START "desc_start"
#define SP_JCMD_DESC_STARTED "desc_started"
#define SP_JCMD_DVERSION "dversion"
#define SP_JCMD_EXEC_START "exec_start"
#define SP_JCMD_EXEC_ERROR "exec_error"
#define SP_JCMD_EXIT "exit"
#define SP_JCMD_EXPT_DURATION "exp_duration"
#define SP_JCMD_FAKETIME "faketime"
#define SP_JCMD_FN_LOAD "fn_load"
#define SP_JCMD_FN_UNLOAD "fn_unload"
#define SP_JCMD_FUN_MAP "fun_map"
#define SP_JCMD_FUN_UNMAP "fun_unmap"
#define SP_JCMD_HEAPTRACE "heaptrace"
#define SP_JCMD_HOSTNAME "hostname"
#define SP_JCMD_HWC_DEFAULT "hwc_default"
#define SP_JCMD_HW_COUNTER "hwcounter"
#define SP_JCMD_HW_SIM_CTR "hwsimctr"
#define SP_JCMD_IOTRACE "iotrace"
#define SP_JCMD_JCM_LOAD "jcm_load"
#define SP_JCMD_JCM_UNLOAD "jcm_unload"
#define SP_JCMD_JCM_MAP "jcm_map"
#define SP_JCMD_JCM_UNMAP "jcm_unmap"
#define SP_JCMD_JTHREND "jthread_end"
#define SP_JCMD_JTHRSTART "jthread_start"
#define SP_JCMD_GCEND "gc_end"
#define SP_JCMD_GCSTART "gc_start"
#define SP_JCMD_JVERSION "jversion"
//#define SP_JCMD_KPROFILE "kprofile" /* TBR */
#define SP_JCMD_LIMIT "limit"
#define SP_JCMD_LINETRACE "linetrace"
#define SP_JCMD_LO_OPEN "lo_open"
#define SP_JCMD_LO_CLOSE "lo_close"
#define SP_JCMD_MOD_OPEN "mod_open"
#define SP_JCMD_MPIEXP "MPIexperiment"
#define SP_JCMD_MPI_NO_TRACE "MPI_no_trace"
#define SP_JCMD_MPIOMPVER "mpi_openmpi_version"
#define SP_JCMD_MPITRACEVER "mpi_trace_version"
#define SP_JCMD_MPIPP "mpipp"
#define SP_JCMD_MPIPPERR "mpipp_err"
#define SP_JCMD_MPIPPWARN "mpipp_warn"
#define SP_JCMD_MPISTATE "mpistate"
#define SP_JCMD_MPITRACE "mpitrace" /* backwards compat only */
#define SP_JCMD_MPVIEW "mpview"
#define SP_JCMD_MSGTRACE "msgtrace"
#define SP_JCMD_NOIDLE "noidle"
#define SP_JCMD_OMPTRACE "omptrace"
#define SP_JCMD_OS "os"
#define SP_JCMD_PAGESIZE "pagesize"
#define SP_JCMD_PAUSE "pause"
#define SP_JCMD_PAUSE_SIG "pause_signal"
#define SP_JCMD_PROFILE "profile"
#define SP_JCMD_RESUME "resume"
#define SP_JCMD_RUN "run"
#define SP_JCMD_SAMPLE "sample"
#define SP_JCMD_SAMPLE_PERIOD "sample_period"
#define SP_JCMD_SAMPLE_SIG "sample_signal"
#define SP_JCMD_SEGMENT_MAP "seg_map"
#define SP_JCMD_SEGMENT_UNMAP "seg_unmap"
#define SP_JCMD_SRCHPATH "search_path"
#define SP_JCMD_STACKBASE "stackbase"
#define SP_JCMD_SUNPERF "sunperf"
#define SP_JCMD_SYNCTRACE "synctrace"
#define SP_JCMD_TERMINATE "terminate"
#define SP_JCMD_THREAD_PAUSE "thread_pause"
#define SP_JCMD_THREAD_RESUME "thread_resume"
#define SP_JCMD_USERNAME "username"
#define SP_JCMD_VERSION "version"
#define SP_JCMD_WSIZE "wsize"
/* strings naming memory-segments */
#define SP_MAP_ANON "Anon"
#define SP_MAP_HEAP "Heap"
#define SP_MAP_STACK "Stack"
#define SP_MAP_SHMEM "SHMid"
#define SP_MAP_UNRESOLVABLE "Unresolvable"
#define SP_UNKNOWN_NAME "(unknown)"
#define MAX_STACKDEPTH 2048
#endif /* _EXPERIMENT_H */

46
gprofng/common/gp-time.h Normal file
View file

@ -0,0 +1,46 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _GP_TIME_H_
#define _GP_TIME_H_
#include <sys/time.h>
typedef long long hrtime_t;
typedef struct timespec timestruc_t;
#define ITIMER_REALPROF ITIMER_PROF
#define NANOSEC 1000000000
#define MICROSEC 1000000
#ifdef __cplusplus
extern "C"
{
#endif
hrtime_t gethrtime (void);
hrtime_t gethrvtime (void);
#ifdef __cplusplus
}
#endif
#endif

198
gprofng/common/hwc_cpus.h Normal file
View file

@ -0,0 +1,198 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/* Hardware counter profiling: cpu types */
#ifndef __HWC_CPUS_H
#define __HWC_CPUS_H
#define MAX_PICS 20 /* Max # of HW ctrs that can be enabled simultaneously */
/* type for specifying CPU register number */
typedef int regno_t;
#define REGNO_ANY ((regno_t)-1)
#define REGNO_INVALID ((regno_t)-2)
/* --- Utilities for use with regno_t and reg_list[] --- */
#define REG_LIST_IS_EMPTY(reg_list) (!(reg_list) || (reg_list)[0] == REGNO_ANY)
#define REG_LIST_EOL(regno) ((regno)==REGNO_ANY)
#define REG_LIST_SINGLE_VALID_ENTRY(reg_list) \
(((reg_list) && (reg_list)[1] == REGNO_ANY && \
(reg_list)[0] != REGNO_ANY ) ? (reg_list)[0] : REGNO_ANY)
/* enum for specifying unknown or uninitialized CPU */
enum
{
CPUVER_GENERIC = 0,
CPUVER_UNDEFINED = -1
};
// Note: changing an values below may make older HWC experiments unreadable.
// --- Sun/Oracle SPARC ---
#define CPC_ULTRA1 1000
#define CPC_ULTRA2 1001
#define CPC_ULTRA3 1002
#define CPC_ULTRA3_PLUS 1003
#define CPC_ULTRA3_I 1004
#define CPC_ULTRA4_PLUS 1005 /* Panther */
#define CPC_ULTRA4 1017 /* Jaguar */
#define CPC_ULTRA_T1 1100 /* Niagara1 */
#define CPC_ULTRA_T2 1101 /* Niagara2 */
#define CPC_ULTRA_T2P 1102
#define CPC_ULTRA_T3 1103
#define CPC_SPARC_T4 1104
#define CPC_SPARC_T5 1110
#define CPC_SPARC_T6 1120
// #define CPC_SPARC_T7 1130 // use CPC_SPARC_M7
#define CPC_SPARC_M4 1204 /* Obsolete */
#define CPC_SPARC_M5 1210
#define CPC_SPARC_M6 1220
#define CPC_SPARC_M7 1230
#define CPC_SPARC_M8 1240
// --- Intel ---
// Pentium
#define CPC_PENTIUM 2000
#define CPC_PENTIUM_MMX 2001
#define CPC_PENTIUM_PRO 2002
#define CPC_PENTIUM_PRO_MMX 2003
#define CPC_PENTIUM_4 2017
#define CPC_PENTIUM_4_HT 2027
// Core Microarchitecture (Merom/Menryn)
#define CPC_INTEL_CORE2 2028
#define CPC_INTEL_NEHALEM 2040
#define CPC_INTEL_WESTMERE 2042
#define CPC_INTEL_SANDYBRIDGE 2045
#define CPC_INTEL_IVYBRIDGE 2047
#define CPC_INTEL_ATOM 2050 /* Atom*/
#define CPC_INTEL_HASWELL 2060
#define CPC_INTEL_BROADWELL 2070
#define CPC_INTEL_SKYLAKE 2080
#define CPC_INTEL_UNKNOWN 2499
#define CPC_AMD_K8C 2500 /* Opteron, Athlon... */
#define CPC_AMD_FAM_10H 2501 /* Barcelona, Shanghai... */
#define CPC_AMD_FAM_11H 2502 /* Griffin... */
#define CPC_AMD_FAM_15H 2503
#define CPC_KPROF 3003 // OBSOLETE (To support 12.3 and earlier)
#define CPC_FOX 3004 /* pseudo-chip */
// --- Fujitsu ---
#define CPC_SPARC64_III 3000
#define CPC_SPARC64_V 3002
#define CPC_SPARC64_VI 4003 /* OPL-C */
#define CPC_SPARC64_VII 4004 /* Jupiter */
#define CPC_SPARC64_X 4006 /* Athena */
#define CPC_SPARC64_XII 4010 /* Athena++ */
// aarch64. Constants from arch/arm64/include/asm/cputype.h
enum {
ARM_CPU_IMP_ARM = 0x41,
ARM_CPU_IMP_BRCM = 0x42,
ARM_CPU_IMP_CAVIUM = 0x43,
ARM_CPU_IMP_APM = 0x50,
ARM_CPU_IMP_QCOM = 0x51
};
#define AARCH64_VENDORSTR_ARM "ARM"
/* strings below must match those returned by cpc_getcpuver() */
typedef struct
{
int cpc2_cpuver;
const char * cpc2_cciname;
} libcpc2_cpu_lookup_t;
#define LIBCPC2_CPU_LOOKUP_LIST \
{CPC_AMD_K8C , "AMD Opteron & Athlon64"}, \
{CPC_AMD_FAM_10H , "AMD Family 10h"}, \
{CPC_AMD_FAM_11H , "AMD Family 11h"}, \
{CPC_AMD_FAM_15H , "AMD Family 15h Model 01h"}, \
{CPC_AMD_FAM_15H , "AMD Family 15h Model 02h"},/*future*/ \
{CPC_AMD_FAM_15H , "AMD Family 15h Model 03h"},/*future*/ \
{CPC_PENTIUM_4_HT , "Pentium 4 with HyperThreading"}, \
{CPC_PENTIUM_4 , "Pentium 4"}, \
{CPC_PENTIUM_PRO_MMX , "Pentium Pro with MMX, Pentium II"}, \
{CPC_PENTIUM_PRO , "Pentium Pro, Pentium II"}, \
{CPC_PENTIUM_MMX , "Pentium with MMX"}, \
{CPC_PENTIUM , "Pentium"}, \
{CPC_INTEL_CORE2 , "Core Microarchitecture"}, \
/* Merom: F6M15: Clovertown, Kentsfield, Conroe, Merom, Woodcrest */ \
/* Merom: F6M22: Merom Conroe */ \
/* Penryn: F6M23: Yorkfield, Wolfdale, Penryn, Harpertown */ \
/* Penryn: F6M29: Dunnington */ \
{CPC_INTEL_NEHALEM , "Intel Arch PerfMon v3 on Family 6 Model 26"},/*Bloomfield, Nehalem EP*/ \
{CPC_INTEL_NEHALEM , "Intel Arch PerfMon v3 on Family 6 Model 30"},/*Clarksfield, Lynnfield, Jasper Forest*/ \
{CPC_INTEL_NEHALEM , "Intel Arch PerfMon v3 on Family 6 Model 31"},/*(TBD)*/ \
{CPC_INTEL_NEHALEM , "Intel Arch PerfMon v3 on Family 6 Model 46"},/*Nehalem EX*/ \
{CPC_INTEL_WESTMERE , "Intel Arch PerfMon v3 on Family 6 Model 37"},/*Arrandale, Clarskdale*/ \
{CPC_INTEL_WESTMERE , "Intel Arch PerfMon v3 on Family 6 Model 44"},/*Gulftown, Westmere EP*/ \
{CPC_INTEL_WESTMERE , "Intel Arch PerfMon v3 on Family 6 Model 47"},/*Westmere EX*/ \
{CPC_INTEL_SANDYBRIDGE , "Intel Arch PerfMon v3 on Family 6 Model 42"},/*Sandy Bridge*/ \
{CPC_INTEL_SANDYBRIDGE , "Intel Arch PerfMon v3 on Family 6 Model 45"},/*Sandy Bridge E, SandyBridge-EN, SandyBridge EP*/ \
{CPC_INTEL_IVYBRIDGE , "Intel Arch PerfMon v3 on Family 6 Model 58"},/*Ivy Bridge*/ \
{CPC_INTEL_IVYBRIDGE , "Intel Arch PerfMon v3 on Family 6 Model 62"},/*(TBD)*/ \
{CPC_INTEL_ATOM , "Intel Arch PerfMon v3 on Family 6 Model 28"},/*Atom*/ \
{CPC_INTEL_HASWELL , "Intel Arch PerfMon v3 on Family 6 Model 60"},/*Haswell*/ \
{CPC_INTEL_HASWELL , "Intel Arch PerfMon v3 on Family 6 Model 63"},/*Haswell*/ \
{CPC_INTEL_HASWELL , "Intel Arch PerfMon v3 on Family 6 Model 69"},/*Haswell*/ \
{CPC_INTEL_HASWELL , "Intel Arch PerfMon v3 on Family 6 Model 70"},/*Haswell*/ \
{CPC_INTEL_BROADWELL , "Intel Arch PerfMon v3 on Family 6 Model 61"},/*Broadwell*/ \
{CPC_INTEL_BROADWELL , "Intel Arch PerfMon v3 on Family 6 Model 71"},/*Broadwell*/ \
{CPC_INTEL_BROADWELL , "Intel Arch PerfMon v3 on Family 6 Model 79"},/*Broadwell*/ \
{CPC_INTEL_BROADWELL , "Intel Arch PerfMon v3 on Family 6 Model 86"},/*Broadwell*/ \
{CPC_INTEL_SKYLAKE , "Intel Arch PerfMon v4 on Family 6 Model 78"},/*Skylake*/ \
{CPC_INTEL_SKYLAKE , "Intel Arch PerfMon v4 on Family 6 Model 85"},/*Skylake*/ \
{CPC_INTEL_SKYLAKE , "Intel Arch PerfMon v4 on Family 6 Model 94"},/*Skylake*/ \
{CPC_INTEL_UNKNOWN , "Intel Arch PerfMon"},/*Not yet in table*/ \
{CPC_SPARC64_III , "SPARC64 III"/*?*/}, \
{CPC_SPARC64_V , "SPARC64 V"/*?*/}, \
{CPC_SPARC64_VI , "SPARC64 VI"}, \
{CPC_SPARC64_VII , "SPARC64 VI & VII"}, \
{CPC_SPARC64_X , "SPARC64 X"}, \
{CPC_SPARC64_XII , "SPARC64 XII"}, \
{CPC_ULTRA_T1 , "UltraSPARC T1"}, \
{CPC_ULTRA_T2 , "UltraSPARC T2"}, \
{CPC_ULTRA_T2P , "UltraSPARC T2+"}, \
{CPC_ULTRA_T3 , "SPARC T3"}, \
{CPC_SPARC_T4 , "SPARC T4"}, \
{CPC_SPARC_M4 , "SPARC M4"}, \
{CPC_SPARC_T5 , "SPARC T5"}, \
{CPC_SPARC_M5 , "SPARC M5"}, \
{CPC_SPARC_T6 , "SPARC T6"}, \
{CPC_SPARC_M6 , "SPARC M6"}, \
{CPC_SPARC_M7 , "SPARC T7"}, \
{CPC_SPARC_M7 , "SPARC 3e40"}, \
{CPC_SPARC_M7 , "SPARC M7"}, \
{CPC_SPARC_M8 , "SPARC 3e50"}, \
{CPC_ULTRA4_PLUS , "UltraSPARC IV+"}, \
{CPC_ULTRA4 , "UltraSPARC IV"}, \
{CPC_ULTRA3_I , "UltraSPARC IIIi"}, \
{CPC_ULTRA3_I , "UltraSPARC IIIi & IIIi+"}, \
{CPC_ULTRA3_PLUS , "UltraSPARC III+"}, \
{CPC_ULTRA3_PLUS , "UltraSPARC III+ & IV"}, \
{CPC_ULTRA3 , "UltraSPARC III"}, \
{CPC_ULTRA2 , "UltraSPARC I&II"}, \
{CPC_ULTRA1 , "UltraSPARC I&II"}, \
{ARM_CPU_IMP_APM , AARCH64_VENDORSTR_ARM}, \
{0, NULL}
/* init like this:
static libcpc2_cpu_lookup_t cpu_table[]={LIBCPC2_CPU_LOOKUP_LIST};
*/
#endif

1454
gprofng/common/hwcdrv.c Normal file

File diff suppressed because it is too large Load diff

330
gprofng/common/hwcdrv.h Normal file
View file

@ -0,0 +1,330 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/* Hardware counter profiling driver's header */
#ifndef __HWCDRV_H
#define __HWCDRV_H
#include "hwcfuncs.h"
#ifdef linux
#define HWCFUNCS_SIGNAL SIGIO
#define HWCFUNCS_SIGNAL_STRING "SIGIO"
#else
#define HWCFUNCS_SIGNAL SIGEMT
#define HWCFUNCS_SIGNAL_STRING "SIGEMT"
#endif
#ifndef LIBCOLLECTOR_SRC /* not running in libcollector */
#include <string.h>
#else /* running in libcollector */
#include "collector_module.h"
#include "libcol_util.h"
#define get_hwcdrv __collector_get_hwcdrv
#define hwcdrv_drivers __collector_hwcdrv_drivers
#define hwcdrv_cpc1_api __collector_hwcdrv_cpc1_api
#define hwcdrv_cpc2_api __collector_hwcdrv_cpc2_api
#define hwcdrv_default __collector_hwcdrv_default
#define hwcdrv_driver __collector_hwcdrv_driver
#define hwcdrv_init __collector_hwcdrv_init
#define hwcdrv_get_info __collector_hwcdrv_get_info
#define hwcdrv_enable_mt __collector_hwcdrv_enable_mt
#define hwcdrv_get_descriptions __collector_hwcdrv_get_descriptions
#define hwcdrv_assign_regnos __collector_hwcdrv_assign_regnos
#define hwcdrv_create_counters __collector_hwcdrv_create_counters
#define hwcdrv_start __collector_hwcdrv_start
#define hwcdrv_overflow __collector_hwcdrv_overflow
#define hwcdrv_read_events __collector_hwcdrv_read_events
#define hwcdrv_sighlr_restart __collector_hwcdrv_sighlr_restart
#define hwcdrv_lwp_suspend __collector_hwcdrv_lwp_suspend
#define hwcdrv_lwp_resume __collector_hwcdrv_lwp_resume
#define hwcdrv_free_counters __collector_hwcdrv_free_counters
#define hwcdrv_lwp_init __collector_hwcdrv_lwp_init
#define hwcdrv_lwp_fini __collector_hwcdrv_lwp_fini
#define hwcdrv_assign_all_regnos __collector_hwcdrv_assign_all_regnos
#define hwcdrv_lookup_cpuver __collector_hwcdrv_lookup_cpuver
#define hwcfuncs_int_capture_errmsg __collector_hwcfuncs_int_capture_errmsg
#define GTXT(x) x
/* Implemented by libcollector */
#define calloc __collector_calloc
#define close CALL_UTIL(close)
#define fcntl CALL_UTIL(fcntl)
#define fprintf CALL_UTIL(fprintf)
//#define free __collector_free
#define free(...)
#define gethrtime __collector_gethrtime
#define ioctl CALL_UTIL(ioctl)
#define malloc __collector_malloc
#define memcpy __collector_memcpy
#define memset CALL_UTIL(memset)
#define mmap CALL_UTIL(mmap)
#define snprintf CALL_UTIL(snprintf)
#define strchr CALL_UTIL(strchr)
#define strcmp CALL_UTIL(strcmp)
#define strncmp CALL_UTIL(strncmp)
#define strcpy CALL_UTIL(strcpy)
#define strdup __collector_strdup
#define strncpy CALL_UTIL(strncpy)
#define strerror CALL_UTIL(strerror)
#define strlen CALL_UTIL(strlen)
#define strstr CALL_UTIL(strstr)
#define strtol CALL_UTIL(strtol)
#define strtoll CALL_UTIL(strtoll)
#define strtoul CALL_UTIL(strtoul)
#define strtoull CALL_UTIL(strtoull)
#define syscall CALL_UTIL(syscall)
#define sysconf CALL_UTIL(sysconf)
#define vsnprintf CALL_UTIL(vsnprintf)
#endif /* --- LIBCOLLECTOR_SRC --- */
/* TprintfT(<level>,...) definitions. Adjust per module as needed */
#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
#define DBG_LT1 1 // for configuration details, warnings
#define DBG_LT2 2
#define DBG_LT3 3
#define DBG_LT4 4
#ifdef __cplusplus
extern "C"
{
#endif
/* hwcdrv api */
typedef struct
{
int (*hwcdrv_init)(hwcfuncs_abort_fn_t abort_ftn, int * tsd_sz);
/* Initialize hwc counter library (do not call again after fork)
Must be called before other functions.
Input:
<abort_ftn>: NULL or callback function to be used for fatal errors
<tsd_sz>: If not NULL, returns size in bytes required for thread-specific storage
Return: 0 if successful
*/
void (*hwcdrv_get_info)(int *cpuver, const char **cciname, uint_t *npics,
const char **docref, uint64_t *support);
/* get info about session
Input:
<cpuver>: if not NULL, returns value of CPC cpu version
<cciname>: if not NULL, returns name of CPU
<npics>: if not NULL, returns maximum # of HWCs
<docref>: if not NULL, returns documentation reference
<support>: if not NULL, returns bitmask (see hwcfuncs.h) of hwc support
Return: 0 if successful, nonzero otherwise
*/
int (*hwcdrv_enable_mt)(hwcfuncs_tsd_get_fn_t tsd_ftn);
/* Enables multi-threaded mode (do not need to call again after fork)
Input:
<tsd_ftn>: If <tsd_sz>==0, this parameter is ignored.
Otherwise:
tsd_ftn() must be able to return a pointer to thread-specific
memory of <tsd_sz> bytes.
For a given thread, tsd_ftn() must
always return the same pointer.
Return: none
*/
int (*hwcdrv_get_descriptions)(hwcf_hwc_cb_t *hwc_find_action,
hwcf_attr_cb_t *attr_find_action);
/* Initiate callbacks with all available HWC names and and HWC attributes.
Input:
<hwc_find_action>: if not NULL, will be called once for each HWC
<attr_find_action>: if not NULL, will be called once for each attribute
Return: 0 if successful
or a cpc return code upon error
*/
int (*hwcdrv_assign_regnos)(Hwcentry* entries[], unsigned numctrs);
/* Assign entries[]->reg_num values as needed by platform
Input:
<entries>: array of counters
<numctrs>: number of items in <entries>
Return: 0 if successful
HWCFUNCS_ERROR_HWCINIT if resources unavailable
HWCFUNCS_ERROR_HWCARGS if counters were not specified correctly
*/
int (*hwcdrv_create_counters)(unsigned hwcdef_cnt, Hwcentry *hwcdef);
/* Create the counters, but don't start them.
call this once in main thread to create counters.
Input:
<defcnt>: number of counter definitions.
<hwcdef>: counter definitions.
Return: 0 if successful
or a cpc return code upon error
*/
int (*hwcdrv_start)(void);
/* Start the counters.
call this once in main thread to start counters.
Return: 0 if successful
or a cpc return code upon error
*/
int (*hwcdrv_overflow)(siginfo_t *si, hwc_event_t *sample,
hwc_event_t *lost_samples);
/* Linux only. Capture current counter values.
This is intended to be called from SIGEMT handler;
Input:
<si>: signal handler context information
<sample>: returns non-zero values for counters that overflowed
<lost_samples>: returns non-zero values for counters that "lost" counts
Return: 0 if successful
or a cpc return code upon error.
*/
int (*hwcdrv_read_events)(hwc_event_t *overflow_data,
hwc_event_samples_t *sampled_data);
/* Read current counter values and samples. Read of samples is destructive.
Note: hwcdrv_read_events is not supported on Linux.
<overflow_data>: returns snapshot of counter values
<sampled_data>: returns sampled data
Return: 0 if successful
HWCFUNCS_ERROR_UNAVAIL if resource unavailable(e.g. called before initted)
(other values may be possible)
*/
int (*hwcdrv_sighlr_restart)(const hwc_event_t* startVals);
/* Restarts the counters at the given value.
This is intended to be called from SIGEMT handler;
Input:
<startVals>: Solaris: new start values.
Linux: pointer may be NULL; startVals is ignored.
Return: 0 if successful
or a cpc return code upon error.
*/
int (*hwcdrv_lwp_suspend)(void);
/* Attempt to stop counters on this lwp only.
hwcdrv_lwp_resume() should be used to restart counters.
Return: 0 if successful
or a cpc return code upon error.
*/
int (*hwcdrv_lwp_resume)(void);
/* Attempt to restart counters on this lwp when counters were
stopped with hwcdrv_lwp_suspend().
Return: 0 if successful
or a cpc return code upon error.
*/
int (*hwcdrv_free_counters)(void);
/* Stops counters on this lwp only and frees resources.
This will fail w/ unpredictable results if other lwps's are
still running. After this call returns,
hwcdrv_create_counters() may be called with new values.
Return: 0 if successful
or a cpc return code upon error.
*/
int (*hwcdrv_lwp_init)(void);
/* per-thread counter init.
Solaris: nop.
Linux: just after thread creation call this from inside thread
to create context and start counters.
Return: 0 if successful
or a perfctr return code upon error
*/
void (*hwcdrv_lwp_fini)(void);
/* per-thread counter cleanup.
Solaris: nop.
Linux: call in each thread upon thread destruction.
*/
int hwcdrv_init_status;
} hwcdrv_api_t;
extern hwcdrv_api_t *get_hwcdrv ();
extern hwcdrv_api_t *__collector_get_hwcdrv ();
extern int __collector_hwcfuncs_bind_descriptor (const char *defstring);
extern Hwcentry **__collector_hwcfuncs_get_ctrs (unsigned *defcnt);
extern hwcdrv_api_t *hwcdrv_drivers[]; // array of available drivers
/* prototypes for internal use by hwcdrv drivers */
typedef struct
{ // see hwcdrv_get_info() for field definitions
int cpcN_cpuver;
uint_t cpcN_npics;
const char *cpcN_docref;
const char *cpcN_cciname;
} hwcdrv_about_t;
extern int hwcdrv_assign_all_regnos (Hwcentry* entries[], unsigned numctrs);
/* assign user's counters to specific CPU registers */
extern int hwcdrv_lookup_cpuver (const char * cpcN_cciname);
/* returns hwc_cpus.h ID for a given string. */
extern void hwcfuncs_int_capture_errmsg (const char *fn, int subcode,
const char *fmt, va_list ap);
#define logerr hwcfuncs_int_logerr
/*---------------------------------------------------------------------------*/
/* prototypes for internal use by linux hwcdrv drivers */
#define PERFCTR_FIXED_MAGIC 0x40000000 /* tells perfctr to use intel fixed pmcs */
#define PERFCTR_UMASK_SHIFT 8
#define EXTENDED_EVNUM_2_EVSEL(evnum) \
( (((eventsel_t)(evnum) & 0x0f00ULL) << 24) | ((eventsel_t)(evnum) & ~0x0f00ULL) )
typedef uint64_t eventsel_t;
extern int hwcfuncs_get_x86_eventsel (unsigned int regno, const char *int_name,
eventsel_t *return_event, uint_t *return_pmc_sel);
typedef int (hwcdrv_get_events_fn_t) (hwcf_hwc_cb_t *hwc_cb);
typedef int (hwcdrv_get_eventnum_fn_t) (const char *eventname, uint_t pmc,
eventsel_t *eventnum,
eventsel_t *valid_umask, uint_t *pmc_sel);
extern hwcdrv_get_eventnum_fn_t *hwcdrv_get_x86_eventnum;
typedef struct
{
const char * attrname; // user-visible name of attribute
int is_inverted; // nonzero means boolean attribute is inverted
eventsel_t mask; // which attribute bits can be set?
eventsel_t shift; // how far to shift bits for use in x86 register
} attr_info_t;
extern const attr_info_t *perfctr_attrs_table;
/* hdrv_pcbe api: cpu-specific drivers for Linux */
typedef struct
{
int (*hdrv_pcbe_init)(void);
uint_t (*hdrv_pcbe_ncounters)(void);
const char *(*hdrv_pcbe_impl_name)(void);
const char *(*hdrv_pcbe_cpuref)(void);
int (*hdrv_pcbe_get_events)(hwcf_hwc_cb_t *hwc_cb);
int (*hdrv_pcbe_get_eventnum)(const char * eventname, uint_t pmc,
eventsel_t *eventnum, eventsel_t *valid_umask,
uint_t *pmc_sel);
} hdrv_pcbe_api_t;
#ifdef __cplusplus
}
#endif
#endif

417
gprofng/common/hwcentry.h Normal file
View file

@ -0,0 +1,417 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _HWCENTRY_H
#define _HWCENTRY_H
#ifndef LIBCOLLECTOR_SRC /* not running in libcollector */
#include <stdio.h> /* FILE */
#endif /* --- LIBCOLLECTOR_SRC --- */
#include <stdlib.h> /* size_t */
#include "hwc_cpus.h"
#include "gp-time.h"
#ifdef __cplusplus
extern "C"
{
#endif
/* ABS backtrack types */
typedef enum
{
/* !! Lowest 2 bits are used to indicate load and store, respectively !! */
/* Example: On SPARC, backtrack.c did this: if (ABS_memop & inst_type) ... */
ABST_NONE = 0x0,
ABST_LOAD = 0x1,
ABST_STORE = 0x2,
ABST_LDST = 0x3,
ABST_COUNT = 0x4,
ABST_US_DTLBM = 0xF,
ABST_NOPC = 0x100,
ABST_CLKDS = 0x103, // Obsolete
ABST_EXACT = 0x203,
ABST_LDST_SPARC64 = 0x303,
ABST_EXACT_PEBS_PLUS1 = 0x403
/* full description below... */
} ABST_type;
#define ABST_PLUS_BY_DEFAULT(n) ((n)==ABST_EXACT || (n)==ABST_EXACT_PEBS_PLUS1)
#define ABST_BACKTRACK_ENABLED(n) ((n)!=ABST_NONE && (n)!=ABST_NOPC)
#define ABST_MEMSPACE_ENABLED(n) ((n)!=ABST_NONE && (n)!=ABST_NOPC && (n)!=ABST_COUNT)
/* ABS determines the type of backtracking available for a particular metric.
* Backtracking is enabled with the "+" in "-h +<countername>...".
*
* When Backtracking is not possible:
*
* ABST_NONE=0: Either the user did not specify "+", or backtracking
* is not applicable to the metric, for example:
* clk cycles,
* instruct counts (dispatch + branch + prefetch),
* i$,
* FP ops
* ABST_NOPC=0x100 Used for non-program-related external events, for example:
* system interface events,
* memory controller counters
* Of all ABST_type options, only ABST_NOPC prevents hwprofile.c
* from recording PC/stack information.
*
* When backtracking is allowed:
*
* ABST_LOAD=1: data read events, used with metrics like:
* D$, E$, P$ read misses and hits.
* [DC+EC+PC]_rd*, Re_*_miss*,
* EC_snoop_cb(?)
* ABST_STORE=2: data write events, used with metrics like:
* D$ writes and write related misses
* DC_wr/wr-miss, EC_wb, WC=writecache, Rstall_storeQ
* [EC+PC=pcache]_snoop_inv(?), WC_snoop_cb(?),
* ABST_LDST=3: data reads/writes, used with metrics like:
* E$ references, misses.
* ABST_COUNT=4: dedicated assembly instruction: '%hi(0xfc000)'
* See SW_count_n metric on sparc.
* ABST_US_DTLBM=0xF: for load-store on Sparc -- seems to be used only
* for "unskidded DTLB_miss" with DTLB_miss metric.
* Checks two adjacent instructions for Data access.
* ABST_CLKDS=0x103: data reads/writes, used with Clock-based Dataspace
* profiling. Ultrasparc T2 and earlier.
* ABST_EXACT=0x203: data reads/writes, precise trap with no skid
* ABST_LDST_SPARC64=0x303: Fujitsu SPARC64 load/store
* ABST_EXACT_PEBS_PLUS1=0x403: data reads/writes, precise sampling with 1 instr. skid
*/
/* Hwcentry - structure for defining a counter.
* Some fields have different usage when returned from
* hwc_lookup(), hwc_post_lookup(), or hwc_scan_*().
* Each function will describe its return values in more detail.
*/
typedef struct
{
char *name; /* user HWC specification */
char *int_name; /* internal HWC specification */
regno_t reg_num; /* register in CPU, aka picnum, or REGNO_ANY */
char *metric; /* descriptive name, for well-known counters only */
volatile int val; /* default or actual overflow value */
int timecvt; /* multiplier to convert metric to time, 0 if N/A */
ABST_type memop; /* type of backtracking allowed */
char *short_desc; /* optional one-liner description, or NULL */
int type; /* Type of perf_event_attr */
long long config; /* perf_event_type -specific configuration */
/* the fields above this line are expected, in order, by the tables in hwctable.c */
/* ================================================== */
/* the fields below this line are more flexible */
int sort_order; /* "tag" to associate experiment record with HWC def */
regno_t *reg_list; /* if not NULL, legal values for <reg_num> field above */
/* Note: reg_list will be terminated by REGNO_ANY */
/* Max size of array is MAX_PICS */
hrtime_t min_time; /* target minimum time between overflow events. 0 is off. See HWCTIME_* macros */
hrtime_t min_time_default; /* if min_time==HWCTIME_AUTO, use this value instead. 0 is off. */
int ref_val; /* if min_time==HWCTIME_AUTO, use this time. 0 is off. */
int lval, hval; /* temporary to allow DBX to build until dbx glue.cc fixed */
} Hwcentry;
// Hwcentry.min_time canned values
#define HWCTIME_TBD ((hrtime_t)( -1LL)) /* self-adjusting enabled but nsecs not yet selected */
#define HWCTIME_HI ( 1 * 1000 * 1000LL ) /* 1 msec represented in nsecs */
#define HWCTIME_ON ( 10 * 1000 * 1000LL ) /* 10 msec represented in nsecs */
#define HWCTIME_LO ( 100 * 1000 * 1000LL ) /* 100 msec represented in nsecs */
#define HWC_VAL_HI(refVal) (((refVal)/10) + 1)
#define HWC_VAL_ON(refVal) (refVal)
#define HWC_VAL_LO(refVal) (((refVal)*10)/100*100 + 1) // zero's out lower digits, add 1
#define HWC_VAL_CUSTOM(refVal, targetNanoSec) ((double)(refVal)*(targetNanoSec)/HWCTIME_ON)
#define HWCENTRY_USES_SAMPLING(h) ((h)->memop==ABST_EXACT_PEBS_PLUS1)
extern int hwc_lookup (int forKernel, hrtime_t min_time_default,
const char *uname, Hwcentry *list[], unsigned listsz,
char **emsg, char **wmsg);
/* Parses counter cmdline string. Returns counter definitions.
* Input:
* <forKernel> lookup using which table: 0-collect or 1-er_kernel
* <min_time_default> minimum nseconds between events if Hwcentry.min_time == HWCTIME_TBD. 0 to disable.
* <uname> command line HWC definition of format:
* <ctr_def>...[{','|(whitespace)}<ctr_n_def>] where
* <ctr_def> == [+]<ctr>[/<reg#>][,<interval>]
* <list> array of pointers to store counter definitions
* <listsz> number of elements in <list>
* Returns:
* Success:
* Returns number of valid counters in <list> and <list>'s elements
* will be initialized as follows:
*
* <list[]->name>:
* Copy of the <uname> with the following modification:
* if backtracking is not supported, the + will be removed.
* <list[]->int_name>:
* For well-known and convenience ctrs, the internal HWC specification,
* e.g. BSQ_cache_reference~emask=0x0100.
* For raw ctrs, this will be a copy of <name>.
* <list[]->reg_num>:
* Register number if specified by user or table, REGNO_ANY otherwise.
* <list[]->metric>:
* For well-known counters, descriptive name, e.g. "D$ Read Misses".
* NULL otherwise.
* <list[]->val>:
* Overflow value selected by user, default value otherwise.
* <list[]->timecvt>:
* Value from tables.
* <list[]->memop>:
* If + is selected and backtracking is allowed, value from table.
* ABST_NONE or ABST_NOPC otherwise.
*
* It is the responsibility of the caller to free 'name' and 'int_name'.
* 'metric' is a static string and shouldn't be freed.
* 'emsg' will point to NULL
*
* Failure:
* Frees all allocated elements.
* emsg will point to a string with an error message to print
* returns -1
*/
extern char *hwc_validate_ctrs (int forKernel, Hwcentry *list[], unsigned listsz);
/* Validates that the vector of specified HW counters can be loaded (more-or-less)
* Some invalid combinations, especially on Linux will not be detected
*/
extern int hwc_get_cpc_cpuver ();
/* Return the cpc_cpuver for this system. Other possible values:
* CPUVER_GENERIC=0, CPU could not be determined, but HWCs are ok.
* CPUVER_UNDEFINED=-1, HWCs are not available.
*/
extern char *hwc_get_docref (char *buf, size_t buflen);
/* Return a CPU HWC document reference, or NULL. */
// TBR
extern char *hwc_get_default_cntrs ();
/* Return a default HW counter string; may be NULL, or zero-length */
/* NULL means none is defined in the table; or zero-length means string defined could not be loaded */
extern char *hwc_get_default_cntrs2 (int forKernel, int style);
/* like hwc_get_default_cntrs() for style==1 */
/* but allows other styles of formatting as well */
/* deprecate and eventually remove hwc_get_default_cntrs() */
extern char *hwc_get_orig_default_cntrs ();
/* Get the default HW counter string as set in the table */
/* NULL means none is defined in the table */
extern void hwc_update_val (Hwcentry *ctr);
/* Check time-based intervals and update Hwcentry.val as needed */
extern char *hwc_get_cpuname (char *buf, size_t buflen);
/* Return the cpc cpu name for this system, or NULL. */
extern unsigned hwc_get_max_regs ();
/* Return number of counters registers for this system. */
extern unsigned hwc_get_max_concurrent (int forKernel);
/* Return the max number of simultaneous counters for this system. */
extern char **hwc_get_attrs (int forKernel);
/* Return:
* Array of attributes (strings) supported by this system.
* Last element in array is null.
* Array and its elements should NOT be freed by the caller.
*/
extern unsigned hwc_scan_attrs (void (*action)(const char *attr,
const char *desc));
/* Scan the HW counter attributes, and call function for each attribute.
* Input:
* <action>:
* If NULL, no action is performed, but count is still returned.
* Otherwise called for each type of attributes, or if none exist,
* called once with NULL parameter.
* Return: count of times <action> would have been called w/ non-NULL data.
*/
extern Hwcentry *hwc_post_lookup (Hwcentry * pret_ctr, char *uname,
char * int_name, int cpc_cpuver);
/* When post-processing a run, look up a Hwcentry for given type of system.
* Input:
* <pret_ctr>: storage for counter definition
* <uname>: well-known name, convenience name, or complete HWC defintion.
* <int_name>: Hwcentry->int_name or NULL for don't care
* <cpc_cpuver>: version of cpu used for experiment.
* Return:
* <pret_ctr>'s elements set as follows:
*
* <pret_ctr->name>:
* Copy of <uname> with the following modifications:
* 1) + and /<regnum> will be stripped off
* 2) attributes will be sorted and values will shown in hex.
* <pret_ctr->int_name>:
* For well-known/convenience counters, the internal HWC specification
* from the table, e.g. BSQ_cache_reference~emask=0x0100.
* Otherwise, a copy of <uname>.
* <pret_ctr->reg_num>:
* Register number if specified by user or table,
* REGNO_ANY othewise.
* <pret_ctr->metric>:
* For well-known counters, descriptive name, e.g. "D$ Read Misses".
* NULL otherwise.
* <pret_ctr->timecvt>:
* For well-known/convenience/hidden counters, value from table.
* 0 otherwise.
* <pret_ctr->memop>:
* For well-known/convenience/hidden counters, value from table.
* ABST_NONE otherwise.
* <pret_ctr->sort_order>:
* Set to 0.
*
* It is the responsibility of the caller to free 'name' and 'int_name'.
* 'metric' is a static string and shouldn't be freed.
*/
extern Hwcentry **hwc_get_std_ctrs (int forKernel);
/* Return:
* Array of well-known counters supported by this system.
* Last element in array will be NULL.
* Array and its elements should NOT be freed by the caller.
*/
extern unsigned hwc_scan_std_ctrs (void (*action)(const Hwcentry *));
/* Call <action> for each well-known counter.
* Input:
* <action>:
* If NULL, no action is performed, but count is still returned.
* Otherwise called for each type of attributes, or if none exist,
* called once with NULL parameter.
* Return:
* Count of times <action> would have been called w/ non-NULL data.
* If <action> is not NULL, Hwcentry fields will be set as follows:
* <ctr->name>:
* HWC alias name, e.g. dcrm.
* <ctr->int_name>:
* The internal HWC specification, e.g. BSQ_cache_reference~emask=0x0100.
* <ctr->reg_num>:
* Register number if specified by the table, REGNO_ANY otherwise.
* <ctr->metric>:
* Descriptive name, e.g. "D$ Read Misses".
* <ctr->lval>:
* Low-resolution overflow value.
* <ctr->val>:
* Default overflow value.
* <ctr->hval>:
* High-resolution overflow value.
* <ctr->timecvt>:
* multiplier to convert metric to time, 0 otherwise.
* <ctr->memop>:
* ABST_* type for this counter.
* <ctr->reg_list>:
* Array of legal <reg_num> values. Terminated by REGNO_ANY.
*
* Note: All fields point to static data, none should be freed.
*/
extern Hwcentry **hwc_get_raw_ctrs (int forKernel);
/* Return:
* Table of raw (not well-known) counters supported by this system.
* Last element in array will be NULL.
* Table and its elements should NOT be freed by the caller.
*/
extern unsigned hwc_scan_raw_ctrs (void (*action)(const Hwcentry *));
/* Call <action> for each raw counter.
* Input:
* <action>:
* If NULL, no action is performed, but count is still returned.
* Otherwise called for each type of attributes, or if none exist,
* called once with NULL parameter.
* Return:
* Count of times <action> would have been called w/ non-NULL data.
* If <action> is not NULL, Hwcentry fields will be set as follows:
* <ctr->name>:
* HWC raw name without attributes, e.g. BSQ_cache_reference.
* <ctr->int_name>:
* NULL.
* <ctr->metric>:
* NULL.
* The remainder of the fields are the same as for
* hwc_scan_std_ctrs().
*
* Note: All fields point to static data, none should be freed.
*/
extern void
hwc_usage (int forKernel, const char *cmd, const char *dataspace_msg);
/* Print an i18n'd description of "-h" usage, used by collect and er_kernel.
*/
extern void hwc_usage_f (int forKernel, FILE *f, const char *cmd,
const char *dataspace_msg, int show_syntax,
int show_short_desc);
/* Print an i18n'd description of "-h" usage to a FILE. Used by GUI. */
extern char *hwc_rate_string (const Hwcentry *pctr, int force_numeric_format);
/* Returns {"on"|"hi"|"lo"|""|<value>}. Return value must be freed by caller. */
extern char *hwc_i18n_metric (const Hwcentry *ctr);
/* Get a basic lable for a counter, properly i18n'd.
* Note: NOT MT SAFE.
* Examples:
* CPU Cycles
* DC_rd Events
* Pseudocode:
* if(ctr->metric != NULL) {
* sprintf(metricbuf, PTXT(ctr->metric) );
* } else if (ctr->name != NULL) {
* sprintf(metricbuf, GTXT("%s Events"), ctr->name );
* } else if (ctr->int_name != NULL) {
* sprintf(metricbuf, GTXT("%s Events"), ctr->int_name );
* }
* Return: pointer to a buffer containing the above description.
*/
extern char *hwc_hwcentry_string (char *buf, size_t buflen, const Hwcentry *ctr);
/* Get a i18n'd description of a HW counter's options.
* Examples of well-known counters:
* cycles[/{0|1}],9999991 ('CPU Cycles', alias for Cycle_cnt; CPU-cycles)
* dcr[/0],1000003 ('D$ Read Refs', alias for DC_rd; load events)
* Examples of raw counters:
* Cycle_cnt[/{0|1}],1000003 (CPU-cycles)
* DC_rd[/0],1000003 (load events)
* Return: <buf>, filled in.
*/
extern char *hwc_hwcentry_specd_string (char *buf, size_t buflen, const Hwcentry *ctr);
/* Get a i18n'd description of a HW counter's specific configuration.
* Examples of well-known counters:
* cycles,9999991 ('CPU Cycles')
* +dcr/0,1000003 ('D$ Read Refs')
* Examples of raw counters:
* Cycle_cnt,1000003
* +DC_rd/0,1000003
* Return: <buf>, filled in.
*/
extern const char *hwc_memop_string (ABST_type memop);
/* Get a i18n'd description of a variable of type ABST_type.
* Return: pointer to static string.
*/
#ifdef __cplusplus
}
#endif
#endif

704
gprofng/common/hwcfuncs.c Normal file
View file

@ -0,0 +1,704 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/* Hardware counter profiling */
#include "hwcdrv.h"
#include "hwcfuncs.h"
/*---------------------------------------------------------------------------*/
/* macros */
#define IS_GLOBAL /* Mark global symbols */
#define HWCDRV_API static /* Mark functions used by hwcdrv API */
/*---------------------------------------------------------------------------*/
/* static variables */
static uint_t cpcN_npics;
static char hwcfuncs_errmsg_buf[1024];
static int hwcfuncs_errmsg_enabled = 1;
static int hwcfuncs_errmsg_valid;
/* --- user counter selections and options */
static unsigned hwcdef_cnt; /* number of *active* hardware counters */
static Hwcentry hwcdef[MAX_PICS]; /* HWC definitions */
static Hwcentry *hwctable[MAX_PICS]; /* HWC definitions */
/* --- drivers --- */
// default driver
HWCDRV_API int
hwcdrv_init (hwcfuncs_abort_fn_t abort_ftn, int* tsd_sz)
{
return -1;
}
HWCDRV_API void
hwcdrv_get_info (
int * cpuver, const char ** cciname,
uint_t * npics, const char ** docref, uint64_t* support) { }
HWCDRV_API int
hwcdrv_enable_mt (hwcfuncs_tsd_get_fn_t tsd_ftn)
{
return -1;
}
HWCDRV_API int
hwcdrv_get_descriptions (hwcf_hwc_cb_t *hwc_find_action,
hwcf_attr_cb_t *attr_find_action)
{
return 0;
}
HWCDRV_API int
hwcdrv_assign_regnos (Hwcentry *entries[], unsigned numctrs)
{
return -1;
}
HWCDRV_API int
hwcdrv_create_counters (unsigned hwcdef_cnt, Hwcentry *hwcdef)
{
return -1;
}
HWCDRV_API int
hwcdrv_read_events (hwc_event_t *events, hwc_event_samples_t*samples)
{
return -1;
}
HWCDRV_API int
hwcdrv_start (void)
{
return -1;
}
HWCDRV_API int
hwcdrv_overflow (siginfo_t *si, hwc_event_t *s, hwc_event_t *t)
{
return 0;
}
HWCDRV_API int
hwcdrv_sighlr_restart (const hwc_event_t *sample)
{
return -1;
}
HWCDRV_API int
hwcdrv_lwp_suspend (void)
{
return -1;
}
HWCDRV_API int
hwcdrv_lwp_resume (void)
{
return -1;
}
HWCDRV_API int
hwcdrv_free_counters (void)
{
return 0;
}
HWCDRV_API int
hwcdrv_lwp_init (void)
{
return 0;
}
HWCDRV_API void
hwcdrv_lwp_fini (void) { }
static hwcdrv_api_t hwcdrv_default = {
hwcdrv_init,
hwcdrv_get_info,
hwcdrv_enable_mt,
hwcdrv_get_descriptions,
hwcdrv_assign_regnos,
hwcdrv_create_counters,
hwcdrv_start,
hwcdrv_overflow,
hwcdrv_read_events,
hwcdrv_sighlr_restart,
hwcdrv_lwp_suspend,
hwcdrv_lwp_resume,
hwcdrv_free_counters,
hwcdrv_lwp_init,
hwcdrv_lwp_fini,
-1 // hwcdrv_init_status
};
static hwcdrv_api_t *hwcdrv_driver = &hwcdrv_default;
/*---------------------------------------------------------------------------*/
/* misc */
/* print a counter definition (for debugging) */
static void
ctrdefprint (int dbg_lvl, const char * hdr, Hwcentry*phwcdef)
{
TprintfT (dbg_lvl, "%s: name='%s', int_name='%s',"
" reg_num=%d, timecvt=%d, memop=%d, "
"interval=%d, tag=%u, reg_list=%p\n",
hdr, phwcdef->name, phwcdef->int_name, phwcdef->reg_num,
phwcdef->timecvt, phwcdef->memop, phwcdef->val,
phwcdef->sort_order, phwcdef->reg_list);
}
/*---------------------------------------------------------------------------*/
/* errmsg buffering */
/* errmsg buffering is needed only because the most descriptive error
messages from CPC are delivered using a callback mechanism.
hwcfuncs_errmsg_get() should only be used during initialization, and
ideally, only to provide feedback to an end user when his counters can't
be bound to HW.
*/
IS_GLOBAL char *
hwcfuncs_errmsg_get (char *buf, size_t bufsize, int enable)
{
hwcfuncs_errmsg_enabled = 0;
if (buf && bufsize)
{
if (hwcfuncs_errmsg_valid)
{
strncpy (buf, hwcfuncs_errmsg_buf, bufsize);
buf[bufsize - 1] = 0;
}
else
*buf = 0;
}
hwcfuncs_errmsg_buf[0] = 0;
hwcfuncs_errmsg_valid = 0;
hwcfuncs_errmsg_enabled = enable;
return buf;
}
/* used by cpc to log an error */
IS_GLOBAL void
hwcfuncs_int_capture_errmsg (const char *fn, int subcode,
const char *fmt, va_list ap)
{
if (hwcfuncs_errmsg_enabled &&
!hwcfuncs_errmsg_valid)
{
vsnprintf (hwcfuncs_errmsg_buf, sizeof (hwcfuncs_errmsg_buf), fmt, ap);
TprintfT (DBG_LT0, "hwcfuncs: cpcN_capture_errmsg(): %s\n",
hwcfuncs_errmsg_buf);
hwcfuncs_errmsg_valid = 1;
}
return;
}
/* Log an internal error to the CPC error buffer.
* Note: only call this during init functions.
* Note: when most cpc calls fail, they will call cpcN_capture_errmsg()
* directly, so only call logerr() when a non-cpc function fails.
*/
IS_GLOBAL void
hwcfuncs_int_logerr (const char *format, ...)
{
va_list va;
va_start (va, format);
hwcfuncs_int_capture_errmsg ("logerr", 0, format, va);
va_end (va);
}
/* utils to parse counter strings */
static void
clear_hwcdefs ()
{
for (unsigned idx = 0; idx < MAX_PICS; idx++)
{
static Hwcentry empty;
hwcdef[idx] = empty; // leaks strings and reg_list array
hwcdef[idx].reg_num = REGNO_ANY;
hwcdef[idx].val = -1;
hwcdef[idx].sort_order = -1;
}
}
/* initialize hwcdef[] based on user's counter definitions */
static int
process_data_descriptor (const char *defstring)
{
/*
* <defstring> format should be of format
* :%s:%s:0x%x:%d:%lld:%d:%d:0x%x[,%s...repeat for each ctr]
* where the counter fields are:
* :<userName>:<internalCtr>:<register>:<timeoutVal>[:m<min_time>]:<tag>:<timecvt>:<memop>
* See Coll_Ctrl::build_data_desc().
*/
int err = 0;
char *ds = NULL;
char *dsp = NULL;
unsigned idx;
clear_hwcdefs ();
if (!defstring || !strlen (defstring))
{
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
ds = strdup (defstring);
if (!ds)
{
err = HWCFUNCS_ERROR_HWCINIT;
goto ext_hw_install_end;
}
dsp = ds;
for (idx = 0; idx < MAX_PICS && *dsp; idx++)
{
char *name = NULL;
char *int_name = NULL;
regno_t reg = REGNO_ANY;
ABST_type memop = ABST_NONE;
int interval = 0;
int timecvt = 0;
unsigned sort_order = (unsigned) - 1;
/* name */
name = dsp;
dsp = strchr (dsp, ':');
if (dsp == NULL)
{
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
*dsp++ = (char) 0;
/* int_name */
int_name = dsp;
dsp = strchr (dsp, ':');
if (dsp == NULL)
{
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
*dsp++ = (char) 0;
/* reg_num */
reg = (int) strtol (dsp, &dsp, 0);
if (*dsp++ != ':')
{
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
if (reg < 0 && reg != -1)
{
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
if (reg >= 0)
hwcdef[idx].reg_num = reg;
/* val */
interval = (int) strtol (dsp, &dsp, 0);
if (*dsp++ != ':')
{
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
if (interval < 0)
{
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
hwcdef[idx].val = interval;
/* min_time */
/*
* This is a new field.
* An old launcher (dbx, etc.) would not include it.
* Detect the presence of the field by the char 'm'.
*/
if (*dsp == 'm')
{
long long tmp_ll = 0;
dsp++;
tmp_ll = strtoll (dsp, &dsp, 0);
if (*dsp++ != ':')
{
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
if (tmp_ll < 0)
{
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
hwcdef[idx].min_time = tmp_ll;
}
else
hwcdef[idx].min_time = 0;
/* sort_order */
sort_order = (int) strtoul (dsp, &dsp, 0);
if (*dsp++ != ':')
{
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
hwcdef[idx].sort_order = sort_order;
/* timecvt */
timecvt = (int) strtol (dsp, &dsp, 0);
if (*dsp++ != ':')
{
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
hwcdef[idx].timecvt = timecvt;
/* memop */
memop = (ABST_type) strtol (dsp, &dsp, 0);
if (*dsp != 0 && *dsp++ != ',')
{
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
hwcdef[idx].memop = memop;
if (*name)
hwcdef[idx].name = strdup (name);
else
hwcdef[idx].name = strdup (int_name);
if (*int_name)
hwcdef[idx].int_name = strdup (int_name);
else
hwcdef[idx].int_name = strdup (name);
ctrdefprint (DBG_LT1, "hwcfuncs: process_data_descriptor", &hwcdef[idx]);
}
if (*dsp)
{
TprintfT (DBG_LT0, "hwcfuncs: ERROR: process_data_descriptor(): "
"ctr string had some trailing garbage:"
" '%s'\n", dsp);
err = HWCFUNCS_ERROR_HWCARGS;
goto ext_hw_install_end;
}
free (ds);
hwcdef_cnt = idx;
return 0;
ext_hw_install_end:
if (dsp && *dsp)
{
TprintfT (DBG_LT0, "hwcfuncs: ERROR: process_data_descriptor(): "
" syntax error just before:"
" '%s;\n", dsp);
logerr (GTXT ("Data descriptor syntax error near `%s'\n"), dsp);
}
else
logerr (GTXT ("Data descriptor syntax error\n"));
free (ds);
return err;
}
/* initialize hwcdef[] based on user's counter definitions */
static int
process_hwcentrylist (const Hwcentry* entries[], unsigned numctrs)
{
int err = 0;
clear_hwcdefs ();
if (numctrs > cpcN_npics)
{
logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
return HWCFUNCS_ERROR_HWCARGS;
}
for (unsigned idx = 0; idx < numctrs; idx++)
{
Hwcentry *phwcdef = &hwcdef[idx];
*phwcdef = *entries[idx];
if (phwcdef->name)
phwcdef->name = strdup (phwcdef->name);
else
phwcdef->name = "NULL";
if (phwcdef->int_name)
phwcdef->int_name = strdup (phwcdef->int_name);
else
phwcdef->int_name = "NULL";
if (phwcdef->val < 0)
{
logerr (GTXT ("Negative interval specified for HW counter `%s'\n"), /*!*/
phwcdef->name);
err = HWCFUNCS_ERROR_HWCARGS;
break;
}
ctrdefprint (DBG_LT1, "hwcfuncs: process_hwcentrylist", phwcdef);
}
if (!err)
hwcdef_cnt = numctrs;
return err;
}
/* see hwcfuncs.h */
IS_GLOBAL void *
hwcfuncs_parse_attrs (const char *countername, hwcfuncs_attr_t attrs[],
unsigned max_attrs, uint_t *pnum_attrs, char**errstring)
{
char *head = NULL;
char *tail = NULL;
uint_t nattrs = 0;
char *counter_copy;
int success = 0;
char errbuf[512];
errbuf[0] = 0;
counter_copy = strdup (countername);
/* advance pointer to first attribute */
tail = strchr (counter_copy, HWCFUNCS_PARSE_ATTR);
if (tail)
*tail = 0;
/* remove regno and value, if supplied */
{
char *tmp = strchr (counter_copy, HWCFUNCS_PARSE_REGNUM);
if (tmp)
*tmp = 0;
tmp = strchr (counter_copy, HWCFUNCS_PARSE_VALUE);
if (tmp)
*tmp = 0;
}
while (tail)
{
char *pch;
if (nattrs >= max_attrs)
{
snprintf (errbuf, sizeof (errbuf),
GTXT ("Too many attributes defined in `%s'"),
countername);
goto mycpc2_parse_attrs_end;
}
/* get attribute name */
head = tail + 1;
tail = strchr (head, HWCFUNCS_PARSE_EQUAL);
if (!tail)
{
snprintf (errbuf, sizeof (errbuf),
GTXT ("Missing value for attribute `%s' in `%s'"),
head, countername);
goto mycpc2_parse_attrs_end;
}
*tail = 0; /* null terminate current component */
attrs[nattrs].ca_name = head;
/* get attribute value */
head = tail + 1;
tail = strchr (head, HWCFUNCS_PARSE_ATTR);
if (tail)
*tail = 0; /* null terminate current component */
attrs[nattrs].ca_val = strtoull (head, &pch, 0);
if (pch == head)
{
snprintf (errbuf, sizeof (errbuf),
GTXT ("Illegal value for attribute `%s' in `%s'"),
attrs[nattrs].ca_name, countername);
goto mycpc2_parse_attrs_end;
}
TprintfT (DBG_LT0, "hwcfuncs: pic_: '%s', attribute[%u]"
" '%s' = 0x%llx\n",
counter_copy, nattrs, attrs[nattrs].ca_name,
(long long unsigned int) attrs[nattrs].ca_val);
nattrs++;
}
success = 1;
mycpc2_parse_attrs_end:
*pnum_attrs = nattrs;
if (success)
{
if (errstring)
*errstring = NULL;
}
else
{
if (errstring)
*errstring = strdup (errbuf);
free (counter_copy);
counter_copy = NULL;
}
return counter_copy;
}
IS_GLOBAL void
hwcfuncs_parse_ctr (const char *counter_def, int *pplus, char **pnameOnly,
char **pattrs, char **pregstr, regno_t *pregno)
{
char *nameptr, *copy, *slash, *attr_delim;
int plus;
regno_t regno;
nameptr = copy = strdup (counter_def);
/* plus */
plus = 0;
if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK)
{
plus = 1;
nameptr++;
}
else if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK_OFF)
{
plus = -1;
nameptr++;
}
if (pplus)
*pplus = plus;
/* regno */
regno = REGNO_ANY;
if (pregstr)
*pregstr = NULL;
slash = strchr (nameptr, HWCFUNCS_PARSE_REGNUM);
if (slash != NULL)
{
/* the remaining string should be a number > 0 */
if (pregstr)
*pregstr = strdup (slash);
char *endchar = NULL;
regno = (regno_t) strtol (slash + 1, &endchar, 0);
if (*endchar != 0)
regno = -2;
if (*(slash + 1) == '-')
regno = -2;
/* terminate previous element up to slash */
*slash = 0;
}
if (pregno)
*pregno = regno;
/* attrs */
if (pattrs)
*pattrs = NULL;
attr_delim = strchr (nameptr, HWCFUNCS_PARSE_ATTR);
if (attr_delim != NULL)
{
if (pattrs)
*pattrs = strdup (attr_delim);
/* terminate previous element up to attr_delim */
*attr_delim++ = 0;
}
if (pnameOnly)
*pnameOnly = strdup (nameptr);
free (copy);
}
/* create counters */
IS_GLOBAL int
hwcfuncs_bind_descriptor (const char *defstring)
{
int err = process_data_descriptor (defstring);
if (err)
{
TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_descriptor failed\n");
return err;
}
err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
return err;
}
/* see hwcfuncs.h */
IS_GLOBAL int
hwcfuncs_bind_hwcentry (const Hwcentry* entries[], unsigned numctrs)
{
int err = -1;
err = process_hwcentrylist (entries, numctrs);
if (err)
{
TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_hwcentry\n");
return err;
}
err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
return err;
}
/* see hwcfuncs.h */
IS_GLOBAL Hwcentry **
hwcfuncs_get_ctrs (unsigned *defcnt)
{
if (defcnt)
*defcnt = hwcdef_cnt;
return hwctable;
}
/* return 1 if <regno> is in Hwcentry's list */
IS_GLOBAL int
regno_is_valid (const Hwcentry * pctr, regno_t regno)
{
regno_t *reg_list = pctr->reg_list;
if (REG_LIST_IS_EMPTY (reg_list))
return 0;
if (regno == REGNO_ANY) /* wildcard */
return 1;
for (int ii = 0; ii < MAX_PICS; ii++)
{
regno_t tmp = reg_list[ii];
if (REG_LIST_EOL (tmp)) /* end of list */
break;
if (tmp == regno) /* is in list */
return 1;
}
return 0;
}
/* supplied by hwcdrv_api drivers */
IS_GLOBAL int
hwcfuncs_assign_regnos (Hwcentry* entries[],
unsigned numctrs)
{
if (numctrs > cpcN_npics)
{
logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
return HWCFUNCS_ERROR_HWCARGS;
}
return hwcdrv_driver->hwcdrv_assign_regnos (entries, numctrs);
}
extern hwcdrv_api_t hwcdrv_pcl_api;
static int hwcdrv_driver_inited = 0;
hwcdrv_api_t *
get_hwcdrv ()
{
if (hwcdrv_driver_inited)
return hwcdrv_driver;
hwcdrv_driver_inited = 1;
cpcN_npics = 0;
for (int i = 0; i < MAX_PICS; i++)
hwctable[i] = &hwcdef[i];
hwcdrv_driver = &hwcdrv_pcl_api;
hwcdrv_driver->hwcdrv_init_status = hwcdrv_driver->hwcdrv_init (NULL, NULL);
if (hwcdrv_driver->hwcdrv_init_status == 0)
{
hwcdrv_driver->hwcdrv_get_info (NULL, NULL, &cpcN_npics, NULL, NULL);
return hwcdrv_driver;
}
hwcdrv_driver = &hwcdrv_default;
return hwcdrv_driver;
}

269
gprofng/common/hwcfuncs.h Normal file
View file

@ -0,0 +1,269 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/* Hardware counter profiling */
#ifndef __HWCFUNCS_H
#define __HWCFUNCS_H
#ifdef LIBCOLLECTOR_SRC /* running in libcollector */
#define hwcfuncs_int_logerr __collector_hwcfuncs_int_logerr
#define hwcfuncs_parse_ctr __collector_hwcfuncs_parse_ctr
#define hwcfuncs_parse_attrs __collector_hwcfuncs_parse_attrs
#define hwcfuncs_bind_descriptor __collector_hwcfuncs_bind_descriptor
#define hwcfuncs_bind_hwcentry __collector_hwcfuncs_bind_hwcentry
#define hwcfuncs_assign_regnos __collector_hwcfuncs_assign_regnos
#define regno_is_valid __collector_regno_is_valid
#define hwcfuncs_get_ctrs __collector_hwcfuncs_get_ctrs
#define hwcfuncs_errmsg_get __collector_hwcfuncs_errmsg_get
#endif /* --- LIBCOLLECTOR_SRC --- */
#include <signal.h> /* siginfo_t */
#include <limits.h> /* UINT64_t */
#include <sys/types.h>
#include <stdint.h>
#include "hwcentry.h" /* for Hwcentry type */
#include "gp-time.h"
typedef unsigned int uint_t;
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------*/
/* compile options */
#define HWC_DEBUG 0 /* 0/1 to enable extra HWC debug */
/*---------------------------------------------------------------------------*/
/* typedefs */
/* generic hw event */
typedef struct _hwc_event_t
{ /* generalized counter event */
hrtime_t ce_hrt; /* gethrtime() */
uint64_t ce_pic[MAX_PICS]; /* counter samples or start values */
} hwc_event_t;
/* supplementary data that accompanies some hw events */
typedef struct
{ /* supplementary data fields */
uint64_t smpl_pc; /* pc related to event */
uint64_t smpl_data_source; /* chip-specific data source encoding */
uint64_t smpl_latency; /* latency related to event */
uint64_t smpl_mem_addr; /* memory address related to event */
} hwc_sample_t;
#define HWCFUNCS_INVALID_U64 0xFEEDBEEFDEADBEEFllu /* identifies fields as unused */
typedef struct { /* supplementary data fields */
hwc_sample_t sample[MAX_PICS]; /* counter samples or start values */
} hwc_event_samples_t;
#define HWCFUNCS_SAMPLE_RESET(sample) \
do { \
(sample)->smpl_pc =HWCFUNCS_INVALID_U64; \
(sample)->smpl_data_source =HWCFUNCS_INVALID_U64; \
(sample)->smpl_latency =HWCFUNCS_INVALID_U64; \
(sample)->smpl_mem_addr =HWCFUNCS_INVALID_U64; \
} while(0)
#define HWCFUNCS_SAMPLE_IS_RESET(sample) \
( \
(sample)->smpl_pc ==HWCFUNCS_INVALID_U64 && \
(sample)->smpl_data_source==HWCFUNCS_INVALID_U64 && \
(sample)->smpl_latency ==HWCFUNCS_INVALID_U64 && \
(sample)->smpl_mem_addr ==HWCFUNCS_INVALID_U64 \
)
/*---------------------------------------------------------------------------*/
/* macros */
#define HW_INTERVAL_MAX UINT64_MAX
#define HW_INTERVAL_PRESET(x) (HW_INTERVAL_MAX - ((uint64_t)(x) - 1))
#define HW_INTERVAL_TYPE(x) ((uint64_t) (x)
/* parsing */
#define HWCFUNCS_MAX_ATTRS 20
#define HWCFUNCS_PARSE_ATTR '~'
#define HWCFUNCS_PARSE_EQUAL '='
#define HWCFUNCS_PARSE_BACKTRACK '+'
#define HWCFUNCS_PARSE_BACKTRACK_OFF '-'
#define HWCFUNCS_PARSE_REGNUM '/'
#define HWCFUNCS_PARSE_VALUE ','
/* error codes */
#define HWCFUNCS_ERROR_GENERIC (-1)
#define HWCFUNCS_ERROR_NOT_SUPPORTED (-2)
#define HWCFUNCS_ERROR_ALREADY_CALLED (-3)
#define HWCFUNCS_ERROR_HWCINIT (-4)
#define HWCFUNCS_ERROR_HWCARGS (-5)
#define HWCFUNCS_ERROR_MEMORY (-6)
#define HWCFUNCS_ERROR_UNAVAIL (-7)
#define HWCFUNCS_ERROR_ERRNO_ZERO (-8)
#define HWCFUNCS_ERROR_UNEXPECTED (-99)
/*---------------------------------------------------------------------------*/
/* prototypes */
typedef void (*hwcfuncs_abort_fn_t) (int errnum, const char *msg);
extern void hwcfuncs_int_logerr(const char *format,...);
/* Log an error to the internal error buffer. See hwcfuncs_errmsg_get().
Note: Not MT-safe; don't even enable logging in an MT environment.
Recommend using this call only during init.
Note: when a libcpc call fails, it may automatically call
cpcN_capture_errmsg() to log the error message in the same internal buffer.
Recommend using this call only for non-cpc failures.
*/
#define HWCFUNCS_SUPPORT_OVERFLOW_PROFILING 0x01llu
#define HWCFUNCS_SUPPORT_PEBS_SAMPLING 0x02llu
#define HWCFUNCS_SUPPORT_OVERFLOW_CTR_ID 0x04llu // OS identifies which counter overflowed
/* get info about session
Input:
<cpuver>: if not NULL, returns value of CPC cpu version
<cciname>: if not NULL, returns name of CPU
<npics>: if not NULL, returns maximum # of HWCs
<docref>: if not NULL, returns documentation reference
<support>: if not NULL, returns bitmask (see above) of hwc support
Return: none
*/
typedef void* (*hwcfuncs_tsd_get_fn_t) (void);
typedef void (hwcf_hwc_cb_t) (uint_t cpcregno, const char *name);
typedef void (hwcf_attr_cb_t) (const char *attr);
extern void
hwcfuncs_parse_ctr (const char *counter_def, int *pplus, char **pnameOnly,
char **pattrs, char **pregstr, regno_t *pregno);
/* Parse a counter definition string (value must already be stripped off).
Input:
<counter_def>: input whose format is
[+|-]<countername>[~attrs...][/<regno>]
pointers to return values: Any can be NULL.
Return:
<plus>: 1 if [+] is found, -1 if [-] is found, 0 otherwise
<pnameonly>: strdup(<countername>)
<pattrs>: strdup([~attrs...]) if specified, NULL otherwise.
<pregstr>: strdup(/<regno>) if specified, NULL otherwise.
<pregno>: <regno> if readable, REGNO_ANY if not specd, or -2 otherwise.
*/
typedef struct
{
char *ca_name;
uint64_t ca_val;
} hwcfuncs_attr_t; /* matches cpc_attr_t */
void * hwcfuncs_parse_attrs (const char *countername,
hwcfuncs_attr_t attrs[], unsigned max_attrs,
uint_t *pnum_attrs, char **errstring);
/* Extract the attribute fields from <countername>.
Input:
<countername>: string whose format is
[+]<ctrname>[~attributes...][/<regno>][,...]
<attrs>: array of attributes to be returned
<max_attrs>: number of elements in <attrs>
<pnum_attrs>: if not NULL, will return how many attrs were found.
<errstring>: pointer to a buffer for storing error info, or NULL.
Return: upon success, a pointer to an allocated copy of <countername>, or
NULL if there's a failure. (A copy is made in order to provide storage
for the ca_name fields in the <attrs> array.)
The pointer should be freed when <attrs> is no longer in use.
<attrs> will be filled in data from countername.
<pnum_attrs> will have the number of elements in <attrs>. May be
non-zero even if return value indicates an error.
<errstring> NULL if no error, otherwise, a malloc'd GTXT string.
*/
extern int hwcfuncs_bind_descriptor (const char *defstring);
/* Bind counters to resources.
Input:
<defstring>: string whose format is
:%s:%s:0x%x:%d:%d,0x%x[:%s...repeat for each ctr]
where the fields are:
:<userName>:<internalCtr>:<register>:<timeoutVal>:<tag>:<memop>
Return: 0 if successful
HWCFUNCS_ERROR_HWCINIT if resources unavailable
HWCFUNCS_ERROR_HWCARGS if counters were not specified correctly
*/
extern int hwcfuncs_bind_hwcentry (const Hwcentry *entries[],
unsigned numctrs);
/* Bind counters to resources.
Input:
<entries>: array of counters
<numctrs>: number of items in <entries>
Return: 0 if successful
HWCFUNCS_ERROR_HWCINIT if resources unavailable
HWCFUNCS_ERROR_HWCARGS if counters were not specified correctly
*/
extern int hwcfuncs_assign_regnos (Hwcentry *entries[], unsigned numctrs);
/* Assign entries[]->reg_num values as needed by platform
Note: modifies <entries> by supplying a regno to each counter
Input:
<entries>: array of counters
<numctrs>: number of items in <entries>
Output:
<entries>: array of counters is modified
Return: 0 if successful
HWCFUNCS_ERROR_HWCINIT if resources unavailable
HWCFUNCS_ERROR_HWCARGS if counters were not specified correctly
*/
extern int regno_is_valid (const Hwcentry *pctr, regno_t regno);
/* return 1 if <regno> is in Hwcentry's list
Input:
<pctr>: counter definition, reg_list[] should be initialized
<regno>: register to check
Return: 1 if <regno> is in Hwcentry's list, 0 otherwise
*/
extern Hwcentry **hwcfuncs_get_ctrs (unsigned *defcnt);
/* Get descriptions of the currently bound counters.
Input:
<defcnt>: if not NULL, returns number of counter definitions.
Return:
table of counter definition pointers
*/
extern char *hwcfuncs_errmsg_get (char * buf, size_t bufsize,
int enable_capture);
/* Gets a recent HWC error message.
To clear previous error messages and insure error message is enabled,
call hwcfuncs_errmsg_get(NULL,0,1).
Once enabled, one error is stored in an internal buffer. A call to this
function will clear the buffer and allow a new message to be captured.
Note: Not MT-safe - don't enable this feature in an MT environment.
Input:
<buf>: pointer to buffer or NULL.
<bufsize>: size of <buf>
<enable_capture>: 0 - disable buffering, 1 - enable buffering.
Return: error string or an empty string.
*/
#ifdef __cplusplus
}
#endif
#endif /* ! __HWCFUNCS_H */

5410
gprofng/common/hwctable.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,448 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/*
* This file contains preset event names from the Performance Application
* Programming Interface v3.5 which included the following notice:
*
* Copyright (c) 2005,6
* Innovative Computing Labs
* Computer Science Department,
* University of Tennessee,
* Knoxville, TN.
* All Rights Reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University of Tennessee nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* This open source software license conforms to the BSD License template.
*/
/*
* Performance Counter Back-End for AMD Opteron and AMD Athlon 64 processors.
*/
#include <sys/types.h>
#include "hwcdrv.h"
#define CPU /* used by cpuid_get*() functions */
typedef struct _amd_event
{
char *name;
uint16_t emask; /* Event mask setting */
uint8_t umask_valid; /* Mask of unreserved UNIT_MASK bits */
} amd_event_t;
typedef struct _amd_generic_event
{
char *name;
char *event;
uint8_t umask;
} amd_generic_event_t;
#define EV_END { NULL, 0, 0 }
#define GEN_EV_END { NULL, NULL, 0 }
#define AMD_cmn_events \
{ "FP_dispatched_fpu_ops", 0x00, 0x3F }, \
{ "FP_cycles_no_fpu_ops_retired", 0x01, 0x0 }, \
{ "FP_dispatched_fpu_ops_ff", 0x02, 0x0 }, \
{ "LS_seg_reg_load", 0x20, 0x7F }, \
{ "LS_uarch_resync_self_modify", 0x21, 0x0 }, \
{ "LS_uarch_resync_snoop", 0x22, 0x0 }, \
{ "LS_buffer_2_full", 0x23, 0x0 }, \
{ "LS_retired_cflush", 0x26, 0x0 }, \
{ "LS_retired_cpuid", 0x27, 0x0 }, \
{ "DC_access", 0x40, 0x0 }, \
{ "DC_miss", 0x41, 0x0 }, \
{ "DC_refill_from_L2", 0x42, 0x1F }, \
{ "DC_refill_from_system", 0x43, 0x1F }, \
{ "DC_misaligned_data_ref", 0x47, 0x0 }, \
{ "DC_uarch_late_cancel_access", 0x48, 0x0 }, \
{ "DC_uarch_early_cancel_access", 0x49, 0x0 }, \
{ "DC_dispatched_prefetch_instr", 0x4B, 0x7 }, \
{ "DC_dcache_accesses_by_locks", 0x4C, 0x2 }, \
{ "BU_memory_requests", 0x65, 0x83}, \
{ "BU_data_prefetch", 0x67, 0x3 }, \
{ "BU_cpu_clk_unhalted", 0x76, 0x0 }, \
{ "IC_fetch", 0x80, 0x0 }, \
{ "IC_miss", 0x81, 0x0 }, \
{ "IC_refill_from_L2", 0x82, 0x0 }, \
{ "IC_refill_from_system", 0x83, 0x0 }, \
{ "IC_itlb_L1_miss_L2_hit", 0x84, 0x0 }, \
{ "IC_uarch_resync_snoop", 0x86, 0x0 }, \
{ "IC_instr_fetch_stall", 0x87, 0x0 }, \
{ "IC_return_stack_hit", 0x88, 0x0 }, \
{ "IC_return_stack_overflow", 0x89, 0x0 }, \
{ "FR_retired_x86_instr_w_excp_intr", 0xC0, 0x0 }, \
{ "FR_retired_uops", 0xC1, 0x0 }, \
{ "FR_retired_branches_w_excp_intr", 0xC2, 0x0 }, \
{ "FR_retired_branches_mispred", 0xC3, 0x0 }, \
{ "FR_retired_taken_branches", 0xC4, 0x0 }, \
{ "FR_retired_taken_branches_mispred", 0xC5, 0x0 }, \
{ "FR_retired_far_ctl_transfer", 0xC6, 0x0 }, \
{ "FR_retired_resyncs", 0xC7, 0x0 }, \
{ "FR_retired_near_rets", 0xC8, 0x0 }, \
{ "FR_retired_near_rets_mispred", 0xC9, 0x0 }, \
{ "FR_retired_taken_branches_mispred_addr_miscomp", 0xCA, 0x0 }, \
{ "FR_retired_fastpath_double_op_instr", 0xCC, 0x7 }, \
{ "FR_intr_masked_cycles", 0xCD, 0x0 }, \
{ "FR_intr_masked_while_pending_cycles", 0xCE, 0x0 }, \
{ "FR_taken_hardware_intrs", 0xCF, 0x0 }, \
{ "FR_nothing_to_dispatch", 0xD0, 0x0 }, \
{ "FR_dispatch_stalls", 0xD1, 0x0 }, \
{ "FR_dispatch_stall_branch_abort_to_retire", 0xD2, 0x0 }, \
{ "FR_dispatch_stall_serialization", 0xD3, 0x0 }, \
{ "FR_dispatch_stall_segment_load", 0xD4, 0x0 }, \
{ "FR_dispatch_stall_reorder_buffer_full", 0xD5, 0x0 }, \
{ "FR_dispatch_stall_resv_stations_full", 0xD6, 0x0 }, \
{ "FR_dispatch_stall_fpu_full", 0xD7, 0x0 }, \
{ "FR_dispatch_stall_ls_full", 0xD8, 0x0 }, \
{ "FR_dispatch_stall_waiting_all_quiet", 0xD9, 0x0 }, \
{ "FR_dispatch_stall_far_ctl_trsfr_resync_branch_pend", 0xDA, 0x0 },\
{ "FR_fpu_exception", 0xDB, 0xF }, \
{ "FR_num_brkpts_dr0", 0xDC, 0x0 }, \
{ "FR_num_brkpts_dr1", 0xDD, 0x0 }, \
{ "FR_num_brkpts_dr2", 0xDE, 0x0 }, \
{ "FR_num_brkpts_dr3", 0xDF, 0x0 }, \
{ "NB_mem_ctrlr_bypass_counter_saturation", 0xE4, 0xF }
#define OPT_events \
{ "LS_locked_operation", 0x24, 0x7 }, \
{ "DC_copyback", 0x44, 0x1F }, \
{ "DC_dtlb_L1_miss_L2_hit", 0x45, 0x0 }, \
{ "DC_dtlb_L1_miss_L2_miss", 0x46, 0x0 }, \
{ "DC_1bit_ecc_error_found", 0x4A, 0x3 }, \
{ "BU_system_read_responses", 0x6C, 0x7 }, \
{ "BU_quadwords_written_to_system", 0x6D, 0x1 }, \
{ "BU_internal_L2_req", 0x7D, 0x1F }, \
{ "BU_fill_req_missed_L2", 0x7E, 0x7 }, \
{ "BU_fill_into_L2", 0x7F, 0x1 }, \
{ "IC_itlb_L1_miss_L2_miss", 0x85, 0x0 }, \
{ "FR_retired_fpu_instr", 0xCB, 0xF }, \
{ "NB_mem_ctrlr_page_access", 0xE0, 0x7 }, \
{ "NB_mem_ctrlr_page_table_overflow", 0xE1, 0x0 }, \
{ "NB_mem_ctrlr_turnaround", 0xE3, 0x7 }, \
{ "NB_ECC_errors", 0xE8, 0x80}, \
{ "NB_sized_commands", 0xEB, 0x7F }, \
{ "NB_probe_result", 0xEC, 0x7F}, \
{ "NB_gart_events", 0xEE, 0x7 }, \
{ "NB_ht_bus0_bandwidth", 0xF6, 0xF }, \
{ "NB_ht_bus1_bandwidth", 0xF7, 0xF }, \
{ "NB_ht_bus2_bandwidth", 0xF8, 0xF }
#define OPT_RevD_events \
{ "NB_sized_blocks", 0xE5, 0x3C }
#define OPT_RevE_events \
{ "NB_cpu_io_to_mem_io", 0xE9, 0xFF}, \
{ "NB_cache_block_commands", 0xEA, 0x3D}
#define AMD_FAMILY_10h_cmn_events \
{ "FP_retired_sse_ops", 0x3, 0x7F}, \
{ "FP_retired_move_ops", 0x4, 0xF}, \
{ "FP_retired_serialize_ops", 0x5, 0xF}, \
{ "FP_serialize_ops_cycles", 0x6, 0x3}, \
{ "DC_copyback", 0x44, 0x7F }, \
{ "DC_dtlb_L1_miss_L2_hit", 0x45, 0x3 }, \
{ "DC_dtlb_L1_miss_L2_miss", 0x46, 0x7 }, \
{ "DC_1bit_ecc_error_found", 0x4A, 0xF }, \
{ "DC_dtlb_L1_hit", 0x4D, 0x7 }, \
{ "BU_system_read_responses", 0x6C, 0x17 }, \
{ "BU_octwords_written_to_system", 0x6D, 0x1 }, \
{ "BU_internal_L2_req", 0x7D, 0x3F }, \
{ "BU_fill_req_missed_L2", 0x7E, 0xF }, \
{ "BU_fill_into_L2", 0x7F, 0x3 }, \
{ "IC_itlb_L1_miss_L2_miss", 0x85, 0x3 }, \
{ "IC_eviction", 0x8B, 0x0 }, \
{ "IC_cache_lines_invalidate", 0x8C, 0xF }, \
{ "IC_itlb_reload", 0x99, 0x0 }, \
{ "IC_itlb_reload_aborted", 0x9A, 0x0 }, \
{ "FR_retired_mmx_sse_fp_instr", 0xCB, 0x7 }, \
{ "NB_mem_ctrlr_page_access", 0xE0, 0xFF }, \
{ "NB_mem_ctrlr_page_table_overflow", 0xE1, 0x3 }, \
{ "NB_mem_ctrlr_turnaround", 0xE3, 0x3F }, \
{ "NB_thermal_status", 0xE8, 0x7C}, \
{ "NB_sized_commands", 0xEB, 0x3F }, \
{ "NB_probe_results_upstream_req", 0xEC, 0xFF}, \
{ "NB_gart_events", 0xEE, 0xFF }, \
{ "NB_ht_bus0_bandwidth", 0xF6, 0xBF }, \
{ "NB_ht_bus1_bandwidth", 0xF7, 0xBF }, \
{ "NB_ht_bus2_bandwidth", 0xF8, 0xBF }, \
{ "NB_ht_bus3_bandwidth", 0x1F9, 0xBF }, \
{ "LS_locked_operation", 0x24, 0xF }, \
{ "LS_cancelled_store_to_load_fwd_ops", 0x2A, 0x7 }, \
{ "LS_smi_received", 0x2B, 0x0 }, \
{ "LS_ineffective_prefetch", 0x52, 0x9 }, \
{ "LS_global_tlb_flush", 0x54, 0x0 }, \
{ "NB_mem_ctrlr_dram_cmd_slots_missed", 0xE2, 0x3 }, \
{ "NB_mem_ctrlr_req", 0x1F0, 0xFF }, \
{ "CB_cpu_to_dram_req_to_target", 0x1E0, 0xFF }, \
{ "CB_io_to_dram_req_to_target", 0x1E1, 0xFF }, \
{ "CB_cpu_read_cmd_latency_to_target_0_to_3", 0x1E2, 0xFF }, \
{ "CB_cpu_read_cmd_req_to_target_0_to_3", 0x1E3, 0xFF }, \
{ "CB_cpu_read_cmd_latency_to_target_4_to_7", 0x1E4, 0xFF }, \
{ "CB_cpu_read_cmd_req_to_target_4_to_7", 0x1E5, 0xFF }, \
{ "CB_cpu_cmd_latency_to_target_0_to_7", 0x1E6, 0xFF }, \
{ "CB_cpu_req_to_target_0_to_7", 0x1E7, 0xFF }, \
{ "L3_read_req", 0x4E0, 0xF7 }, \
{ "L3_miss", 0x4E1, 0xF7 }, \
{ "L3_l2_eviction_l3_fill", 0x4E2, 0xFF }, \
{ "L3_eviction", 0x4E3, 0xF }
#define AMD_cmn_generic_events \
{ "PAPI_br_ins", "FR_retired_branches_w_excp_intr", 0x0 },\
{ "PAPI_br_msp", "FR_retired_branches_mispred", 0x0 }, \
{ "PAPI_br_tkn", "FR_retired_taken_branches", 0x0 }, \
{ "PAPI_fp_ops", "FP_dispatched_fpu_ops", 0x3 }, \
{ "PAPI_fad_ins", "FP_dispatched_fpu_ops", 0x1 }, \
{ "PAPI_fml_ins", "FP_dispatched_fpu_ops", 0x2 }, \
{ "PAPI_fpu_idl", "FP_cycles_no_fpu_ops_retired", 0x0 }, \
{ "PAPI_tot_cyc", "BU_cpu_clk_unhalted", 0x0 }, \
{ "PAPI_tot_ins", "FR_retired_x86_instr_w_excp_intr", 0x0 }, \
{ "PAPI_l1_dca", "DC_access", 0x0 }, \
{ "PAPI_l1_dcm", "DC_miss", 0x0 }, \
{ "PAPI_l1_ldm", "DC_refill_from_L2", 0xe }, \
{ "PAPI_l1_stm", "DC_refill_from_L2", 0x10 }, \
{ "PAPI_l1_ica", "IC_fetch", 0x0 }, \
{ "PAPI_l1_icm", "IC_miss", 0x0 }, \
{ "PAPI_l1_icr", "IC_fetch", 0x0 }, \
{ "PAPI_l2_dch", "DC_refill_from_L2", 0x1e }, \
{ "PAPI_l2_dcm", "DC_refill_from_system", 0x1e }, \
{ "PAPI_l2_dcr", "DC_refill_from_L2", 0xe }, \
{ "PAPI_l2_dcw", "DC_refill_from_L2", 0x10 }, \
{ "PAPI_l2_ich", "IC_refill_from_L2", 0x0 }, \
{ "PAPI_l2_icm", "IC_refill_from_system", 0x0 }, \
{ "PAPI_l2_ldm", "DC_refill_from_system", 0xe }, \
{ "PAPI_l2_stm", "DC_refill_from_system", 0x10 }, \
{ "PAPI_res_stl", "FR_dispatch_stalls", 0x0 }, \
{ "PAPI_stl_icy", "FR_nothing_to_dispatch", 0x0 }, \
{ "PAPI_hw_int", "FR_taken_hardware_intrs", 0x0 }
#define OPT_cmn_generic_events \
{ "PAPI_tlb_dm", "DC_dtlb_L1_miss_L2_miss", 0x0 }, \
{ "PAPI_tlb_im", "IC_itlb_L1_miss_L2_miss", 0x0 }, \
{ "PAPI_fp_ins", "FR_retired_fpu_instr", 0xd }, \
{ "PAPI_vec_ins", "FR_retired_fpu_instr", 0x4 }
#define AMD_FAMILY_10h_generic_events \
{ "PAPI_tlb_dm", "DC_dtlb_L1_miss_L2_miss", 0x7 }, \
{ "PAPI_tlb_im", "IC_itlb_L1_miss_L2_miss", 0x3 }, \
{ "PAPI_l3_dcr", "L3_read_req", 0xf1 }, \
{ "PAPI_l3_icr", "L3_read_req", 0xf2 }, \
{ "PAPI_l3_tcr", "L3_read_req", 0xf7 }, \
{ "PAPI_l3_stm", "L3_miss", 0xf4 }, \
{ "PAPI_l3_ldm", "L3_miss", 0xf3 }, \
{ "PAPI_l3_tcm", "L3_miss", 0xf7 }
static amd_event_t opt_events_rev_E[] = {
AMD_cmn_events,
OPT_events,
OPT_RevD_events,
OPT_RevE_events,
EV_END
};
static amd_event_t family_10h_events[] = {
AMD_cmn_events,
OPT_RevE_events,
AMD_FAMILY_10h_cmn_events,
EV_END
};
static amd_generic_event_t opt_generic_events[] = {
AMD_cmn_generic_events,
OPT_cmn_generic_events,
GEN_EV_END
};
static amd_generic_event_t family_10h_generic_events[] = {
AMD_cmn_generic_events,
AMD_FAMILY_10h_generic_events,
GEN_EV_END
};
static amd_event_t *amd_events = NULL;
static uint_t amd_family;
static amd_generic_event_t *amd_generic_events = NULL;
#define BITS(v, u, l) (((v) >> (l)) & ((1 << (1 + (u) - (l))) - 1))
#define OPTERON_FAMILY 0x0f
#define AMD_FAMILY_10H 0x10
static int
opt_pcbe_init (void)
{
amd_family = cpuid_getfamily ();
/*
* Make sure this really _is_ an Opteron or Athlon 64 system. The kernel
* loads this module based on its name in the module directory, but it
* could have been renamed.
*/
if (cpuid_getvendor () != X86_VENDOR_AMD
|| (amd_family != OPTERON_FAMILY && amd_family != AMD_FAMILY_10H))
return (-1);
/*
* Figure out processor revision here and assign appropriate
* event configuration.
*/
if (amd_family == OPTERON_FAMILY)
{
amd_events = opt_events_rev_E;
amd_generic_events = opt_generic_events;
}
else
{
amd_events = family_10h_events;
amd_generic_events = family_10h_generic_events;
}
return (0);
}
static uint_t
opt_pcbe_ncounters (void)
{
return (4);
}
static const char *
opt_pcbe_impl_name (void)
{
if (amd_family == OPTERON_FAMILY)
return ("AMD Opteron & Athlon64");
else if (amd_family == AMD_FAMILY_10H)
return ("AMD Family 10h");
else
return ("Unknown AMD processor");
}
static const char *
opt_pcbe_cpuref (void)
{
if (amd_family == OPTERON_FAMILY)
return GTXT ("See Chapter 10 of the \"BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD Opteron Processors,\"\nAMD publication #26094");
else if (amd_family == AMD_FAMILY_10H)
return GTXT ("See section 3.15 of the \"BIOS and Kernel Developer's Guide (BKDG) For AMD Family 10h Processors,\"\nAMD publication #31116");
else
return GTXT ("Unknown AMD processor");
}
static int
opt_pcbe_get_events (hwcf_hwc_cb_t *hwc_cb)
{
int count = 0;
for (uint_t kk = 0; amd_events && amd_events[kk].name; kk++)
for (uint_t jj = 0; jj < opt_pcbe_ncounters (); jj++)
{
hwc_cb (jj, amd_events[kk].name);
count++;
}
for (uint_t kk = 0; amd_generic_events && amd_generic_events[kk].name; kk++)
for (uint_t jj = 0; jj < opt_pcbe_ncounters (); jj++)
{
hwc_cb (jj, amd_generic_events[kk].name);
count++;
}
return count;
}
static int
opt_pcbe_get_eventnum (const char *eventname, uint_t pmc, eventsel_t *eventsel,
eventsel_t *event_valid_umask, uint_t *pmc_sel)
{
uint_t kk;
*pmc_sel = pmc; /* for AMD, pmc doesn't need to be adjusted */
*eventsel = (eventsel_t) - 1;
*event_valid_umask = 0x0;
/* search table */
for (kk = 0; amd_events && amd_events[kk].name; kk++)
{
if (strcmp (eventname, amd_events[kk].name) == 0)
{
*eventsel = EXTENDED_EVNUM_2_EVSEL (amd_events[kk].emask);
*event_valid_umask = amd_events[kk].umask_valid;
return 0;
}
}
/* search generic */
int generic = 0;
eventsel_t tmp_umask = 0;
for (kk = 0; amd_generic_events && amd_generic_events[kk].name; kk++)
{
if (strcmp (eventname, amd_generic_events[kk].name) == 0)
{
generic = 1;
eventname = amd_generic_events[kk].event;
tmp_umask = amd_generic_events[kk].umask;
break;
}
}
if (!generic)
return -1;
/* find real event # for generic event */
for (kk = 0; amd_events && amd_events[kk].name; kk++)
{
if (strcmp (eventname, amd_events[kk].name) == 0)
{
*eventsel = EXTENDED_EVNUM_2_EVSEL (amd_events[kk].emask);
*eventsel |= (tmp_umask << PERFCTR_UMASK_SHIFT);
*event_valid_umask = 0; /* user umask not allowed w/generic events */
return 0;
}
}
return -1;
}
static hdrv_pcbe_api_t hdrv_pcbe_opteron_api = {
opt_pcbe_init,
opt_pcbe_ncounters,
opt_pcbe_impl_name,
opt_pcbe_cpuref,
opt_pcbe_get_events,
opt_pcbe_get_eventnum
};

92
gprofng/config/bison.m4 Normal file
View file

@ -0,0 +1,92 @@
# serial 10
# Copyright (C) 2002-2006, 2008-2021 Free Software Foundation, Inc.
# This file 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.
# There are two types of parser skeletons:
#
# * Those that can be used with any Yacc implementation, including bison.
# For these, in the configure.ac, up to Autoconf 2.69, you could use
# AC_PROG_YACC
# In newer Autoconf versions, however, this macro is broken. See
# https://lists.gnu.org/archive/html/autoconf-patches/2013-03/msg00000.html
# https://lists.gnu.org/archive/html/bug-autoconf/2018-12/msg00001.html
# In the Makefile.am you could use
# $(SHELL) $(YLWRAP) $(srcdir)/foo.y \
# y.tab.c foo.c \
# y.tab.h foo.h \
# y.output foo.output \
# -- $(YACC) $(YFLAGS) $(AM_YFLAGS)
# or similar.
#
# * Those that make use of Bison extensions. For example,
# - %define api.pure requires bison 2.7 or newer,
# - %precedence requires bison 3.0 or newer.
# For these, in the configure.ac you will need an invocation of
# gl_PROG_BISON([VARIABLE], [MIN_BISON_VERSION])
# Example:
# gl_PROG_BISON([PARSE_DATETIME_BISON], [2.4])
# With this preparation, in the Makefile.am there are two ways to formulate
# the invocation. Both are direct, without use of 'ylwrap'.
# (a) You can invoke
# $(VARIABLE) -d $(SOME_BISON_OPTIONS) --output foo.c $(srcdir)/foo.y
# or similar.
# (b) If you want the invocation to honor an YFLAGS=... parameter passed to
# 'configure' or an YFLAGS environment variable present at 'configure'
# time, add an invocation of gl_BISON to the configure.ac, and write
# $(VARIABLE) -d $(YFLAGS) $(AM_YFLAGS) $(srcdir)/foo.y
# or similar.
# This macro defines the autoconf variable VARIABLE to 'bison' if the specified
# minimum version of bison is found in $PATH, or to ':' otherwise.
AC_DEFUN([gl_PROG_BISON],
[
AC_CHECK_PROGS([$1], [bison])
if test -z "$[$1]"; then
ac_verc_fail=yes
else
cat >conftest.y <<_ACEOF
%require "$2"
%%
exp:
_ACEOF
AC_MSG_CHECKING([for bison $2 or newer])
ac_prog_version=`$$1 --version 2>&1 | sed -n 's/^.*GNU Bison.* \([[0-9]]*\.[[0-9.]]*\).*$/\1/p'`
: ${ac_prog_version:='v. ?.??'}
if $$1 conftest.y -o conftest.c 2>/dev/null; then
ac_prog_version="$ac_prog_version, ok"
ac_verc_fail=no
else
ac_prog_version="$ac_prog_version, bad"
ac_verc_fail=yes
fi
rm -f conftest.y conftest.c
AC_MSG_RESULT([$ac_prog_version])
fi
if test $ac_verc_fail = yes; then
[$1]=:
fi
AC_SUBST([$1])
])
# This macro sets the autoconf variables YACC (for old-style yacc Makefile
# rules) and YFLAGS (to allow options to be passed as 'configure' time).
AC_DEFUN([gl_BISON],
[
: ${YACC='bison -o y.tab.c'}
dnl
dnl Declaring YACC & YFLAGS precious will not be necessary after GNULIB
dnl requires an Autoconf greater than 2.59c, but it will probably still be
dnl useful to override the description of YACC in the --help output, re
dnl parse-datetime.y assuming 'bison -o y.tab.c'.
AC_ARG_VAR([YACC],
[The "Yet Another C Compiler" implementation to use. Defaults to
'bison -o y.tab.c'. Values other than 'bison -o y.tab.c' will most likely
break on most systems.])dnl
AC_ARG_VAR([YFLAGS],
[YFLAGS contains the list arguments that will be passed by default to Bison.
This script will default YFLAGS to the empty string to avoid a default value of
'-d' given by some make applications.])dnl
])

19350
gprofng/configure vendored Executable file

File diff suppressed because it is too large Load diff

189
gprofng/configure.ac Normal file
View file

@ -0,0 +1,189 @@
dnl Process this file with autoconf to produce a configure script.
dnl
dnl Copyright (C) 2021 Free Software Foundation, Inc.
dnl
dnl This file is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 3 of the License, or
dnl (at your option) any later version.
dnl
dnl This program is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program; see the file COPYING3. If not see
dnl <http://www.gnu.org/licenses/>.
m4_include([../bfd/version.m4])
AC_INIT([gprofng], BFD_VERSION)
AM_INIT_AUTOMAKE([subdir-objects])
AM_MAINTAINER_MODE
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_PROG_RANLIB
AM_PROG_AR
AC_DISABLE_SHARED
LT_INIT
GPROFNG_LIBADD="-L../../libiberty -liberty"
if test "$enable_shared" = "yes"; then
GPROFNG_LIBADD="-L../../libiberty/pic -liberty"
fi
AC_SUBST(GPROFNG_LIBADD)
# Figure out what compiler warnings we can enable.
# See config/warnings.m4 for details.
ACX_PROG_CC_WARNINGS_ARE_ERRORS([manual])
ACX_PROG_CC_WARNING_OPTS([-Wall], [gprofng_cflags])
gprofng_cppflags="-U_ASM"
build_collector=
build_src=
# This is annoying: it means we have to pass --enable-shared explicitly to
# get gprofng, while the configure default is supposed to be that shared libs
# are on by default. But as long as libiberty has code like this, so must
# we...
case "${target}" in
x86_64-*-linux*)
build_src=true
build_collector=true
;;
i?86-*-linux*)
build_collector=true
build_collector=true
;;
aarch64-*-linux*)
build_src=true
build_collector=true
;;
esac
AC_ARG_ENABLE(gprofng-tools,
AS_HELP_STRING([--disable-gprofng-tools], [do not build gprofng/src directory]),
build_src=$enableval)
AM_CONDITIONAL([BUILD_COLLECTOR], [test x$build_collector = xtrue])
AM_CONDITIONAL([BUILD_SRC], [test x$build_src = xtrue])
run_tests=false
if test x$build_collector = xtrue; then
AC_CONFIG_SUBDIRS([libcollector])
if test x${host} = x${target}; then
run_tests=true
fi
fi
AM_CONDITIONAL([RUN_TESTS], [test x$run_tests = xtrue])
AX_PTHREAD
# Specify a location for JDK
enable_gprofng_jp=
jdk_inc=
AC_ARG_WITH(jdk,
[AS_HELP_STRING([--with-jdk=PATH],
[specify prefix directory for installed JDK.])])
if test "x$with_jdk" != x; then
jdk_inc="-I$with_jdk/include -I$with_jdk/include/linux"
enable_gprofng_jp=yes
else
AC_PATH_PROG([JAVAC], [javac], [javac])
if test -f $JAVAC; then
x=`readlink -f $JAVAC`
x=`dirname $x`
x=`dirname $x`
if ! test -f $x/include/jni.h; then
x=`dirname $x`
fi
if test -f $x/include/jni.h; then
jdk_inc="-I$x/include -I$x/include/linux"
enable_gprofng_jp=yes
fi
fi
fi
if test "x$enable_gprofng_jp" = x; then
AC_PATH_PROG([JAVA], [java], [java])
if test -f $JAVA; then
x=`readlink -f $JAVA`
x=`dirname $x`
x=`dirname $x`
if ! test -f $x/include/jni.h; then
x=`dirname $x`
fi
if test -f $x/include/jni.h; then
jdk_inc="-I$x/include -I$x/include/linux"
enable_gprofng_jp=yes
fi
fi
fi
if test "x$enable_gprofng_jp" = x; then
AC_CHECK_HEADER([jni.h], [ enable_gprofng_jp=yes ], [], [] )
fi
if test "x$enable_gprofng_jp" = x; then
AC_MSG_WARN([ Cannot find the JDK include directory.
gprofng will be build without support for profiling Java applications.
Use --with-jdk=PATH to specify directory for the installed JDK])
else
AC_DEFINE(GPROFNG_JAVA_PROFILING, 1, [Enable java profiling])
fi
AC_SUBST(jdk_inc)
DEBUG=
GCC_ENABLE([gprofng-debug], [no], [], [Enable debugging output])
if test "${enable_gprofng_debug}" = yes; then
AC_DEFINE(DEBUG, 1, [Enable debugging output.])
fi
# Check if linker supports --as-needed and --no-as-needed options.
AC_CACHE_CHECK(linker --as-needed support, bfd_cv_ld_as_needed,
[bfd_cv_ld_as_needed=no
if $LD --help 2>/dev/null | grep as-needed > /dev/null; then
bfd_cv_ld_as_needed=yes
fi
])
no_as_needed=
if test x"$bfd_cv_ld_as_needed" = xyes; then
no_as_needed='-Wl,--no-as-needed'
fi
AC_PATH_PROG([EXPECT], [expect])
AC_CACHE_CHECK([for Tcl supporting try/catch], [ac_cv_libctf_tcl_try],
[ac_cv_libctf_tcl_try=`if test -z $EXPECT; then echo no; else $EXPECT << EOF
if @<:@llength @<:@info commands try@:>@@:>@ then { puts yes } else { puts no }
EOF
fi`
])
AM_CONDITIONAL(TCL_TRY, test "${ac_cv_libctf_tcl_try}" = yes)
# Generate manpages, if possible.
if test $cross_compiling = no; then
AM_MISSING_PROG(HELP2MAN, help2man)
build_man=true
else
build_man=false
fi
AM_CONDITIONAL([BUILD_MAN], [test x$build_man = xtrue])
AC_SUBST(LD_NO_AS_NEEDED, [${no_as_needed}])
AC_SUBST(GPROFNG_CFLAGS, [${gprofng_cflags}])
AC_SUBST(GPROFNG_CPPFLAGS, [${gprofng_cppflags}])
AC_SUBST(GPROFNG_LIBDIR, [${libdir}])
AC_CHECK_DECLS([basename])
AC_CHECK_FUNCS([strsignal])
AC_SUBST(BUILD_SUBDIRS)
AC_CONFIG_FILES([Makefile src/Makefile gp-display-html/Makefile doc/Makefile])
AC_CONFIG_HEADERS([config.h:common/config.h.in])
AC_OUTPUT

37
gprofng/doc/Makefile.am Normal file
View file

@ -0,0 +1,37 @@
## Process this file with automake to generate Makefile.in
#
# Copyright (C) 2012-2021 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
#
AUTOMAKE_OPTIONS = foreign no-texinfo.tex
info_TEXINFOS = gprofng.texi
gprofng_TEXINFOS = fdl.texi
BUILT_SOURCES = version.texi
CLEANFILES = version.texi
TEXINFO_TEX = .
MAKEINFOHTML = $(MAKEINFO) --html --no-split
version.texi:
@echo "@set EDITION 1.0" > $@
@echo "@set VERSION 1.0" >> $@
@echo "@set UPDATED 22 February 2022" >> $@
@echo "@set UPDATED-MONTH February 2022" >> $@
# @echo "@set UPDATED `date +"%-d %B %Y"`" >> $@
# @echo "@set UPDATED-MONTH `date +"%B %Y"`" >> $@
MAINTAINERCLEANFILES = gprofng.info

834
gprofng/doc/Makefile.in Normal file
View file

@ -0,0 +1,834 @@
# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2017 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@
#
# Copyright (C) 2012-2021 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
#
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
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 = :
build_triplet = @build@
host_triplet = @host@
subdir = doc
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../libtool.m4 \
$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
$(top_srcdir)/acinclude.m4 $(top_srcdir)/../config/warnings.m4 \
$(top_srcdir)/../config/enable.m4 \
$(top_srcdir)/../config/ax_pthread.m4 \
$(top_srcdir)/config/bison.m4 $(top_srcdir)/../bfd/version.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/version.texi \
$(srcdir)/stamp-vti $(am__DIST_COMMON)
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
SOURCES =
DIST_SOURCES =
AM_V_DVIPS = $(am__v_DVIPS_@AM_V@)
am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@)
am__v_DVIPS_0 = @echo " DVIPS " $@;
am__v_DVIPS_1 =
AM_V_MAKEINFO = $(am__v_MAKEINFO_@AM_V@)
am__v_MAKEINFO_ = $(am__v_MAKEINFO_@AM_DEFAULT_V@)
am__v_MAKEINFO_0 = @echo " MAKEINFO" $@;
am__v_MAKEINFO_1 =
AM_V_INFOHTML = $(am__v_INFOHTML_@AM_V@)
am__v_INFOHTML_ = $(am__v_INFOHTML_@AM_DEFAULT_V@)
am__v_INFOHTML_0 = @echo " INFOHTML" $@;
am__v_INFOHTML_1 =
AM_V_TEXI2DVI = $(am__v_TEXI2DVI_@AM_V@)
am__v_TEXI2DVI_ = $(am__v_TEXI2DVI_@AM_DEFAULT_V@)
am__v_TEXI2DVI_0 = @echo " TEXI2DVI" $@;
am__v_TEXI2DVI_1 =
AM_V_TEXI2PDF = $(am__v_TEXI2PDF_@AM_V@)
am__v_TEXI2PDF_ = $(am__v_TEXI2PDF_@AM_DEFAULT_V@)
am__v_TEXI2PDF_0 = @echo " TEXI2PDF" $@;
am__v_TEXI2PDF_1 =
AM_V_texinfo = $(am__v_texinfo_@AM_V@)
am__v_texinfo_ = $(am__v_texinfo_@AM_DEFAULT_V@)
am__v_texinfo_0 = -q
am__v_texinfo_1 =
AM_V_texidevnull = $(am__v_texidevnull_@AM_V@)
am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@)
am__v_texidevnull_0 = > /dev/null
am__v_texidevnull_1 =
INFO_DEPS = $(srcdir)/gprofng.info
am__TEXINFO_TEX_DIR = $(srcdir)/.
DVIS = gprofng.dvi
PDFS = gprofng.pdf
PSS = gprofng.ps
HTMLS = gprofng.html
TEXINFOS = gprofng.texi
TEXI2DVI = texi2dvi
TEXI2PDF = $(TEXI2DVI) --pdf --batch
AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS)
DVIPS = dvips
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__installdirs = "$(DESTDIR)$(infodir)"
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
am__DIST_COMMON = $(gprofng_TEXINFOS) $(srcdir)/Makefile.in \
$(top_srcdir)/../mkinstalldirs mdate-sh texinfo.tex
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BUILD_SUBDIRS = @BUILD_SUBDIRS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
EXPECT = @EXPECT@
FGREP = @FGREP@
GPROFNG_CFLAGS = @GPROFNG_CFLAGS@
GPROFNG_CPPFLAGS = @GPROFNG_CPPFLAGS@
GPROFNG_LIBADD = @GPROFNG_LIBADD@
GPROFNG_LIBDIR = @GPROFNG_LIBDIR@
GREP = @GREP@
HELP2MAN = @HELP2MAN@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
JAVA = @JAVA@
JAVAC = @JAVAC@
LD = @LD@
LDFLAGS = @LDFLAGS@
LD_NO_AS_NEEDED = @LD_NO_AS_NEEDED@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PTHREAD_CC = @PTHREAD_CC@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
PTHREAD_LIBS = @PTHREAD_LIBS@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
WERROR = @WERROR@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
ax_pthread_config = @ax_pthread_config@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
gprofng_cflags = @gprofng_cflags@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
jdk_inc = @jdk_inc@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
subdirs = @subdirs@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = foreign no-texinfo.tex
info_TEXINFOS = gprofng.texi
gprofng_TEXINFOS = fdl.texi
BUILT_SOURCES = version.texi
CLEANFILES = version.texi
TEXINFO_TEX = .
MAKEINFOHTML = $(MAKEINFO) --html --no-split
# @echo "@set UPDATED `date +"%-d %B %Y"`" >> $@
# @echo "@set UPDATED-MONTH `date +"%B %Y"`" >> $@
MAINTAINERCLEANFILES = gprofng.info
all: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
.SUFFIXES: .dvi .html .info .pdf .ps .texi
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign doc/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: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
.texi.info:
$(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \
am__cwd=`pwd` && $(am__cd) $(srcdir) && \
rm -rf $$backupdir && mkdir $$backupdir && \
if ($(MAKEINFO) --version) >/dev/null 2>&1; then \
for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \
if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \
done; \
else :; fi && \
cd "$$am__cwd"; \
if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
-o $@ $<; \
then \
rc=0; \
$(am__cd) $(srcdir); \
else \
rc=$$?; \
$(am__cd) $(srcdir) && \
$$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \
fi; \
rm -rf $$backupdir; exit $$rc
.texi.dvi:
$(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
$(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \
$<
.texi.pdf:
$(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
$(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \
$<
.texi.html:
$(AM_V_MAKEINFO)rm -rf $(@:.html=.htp)
$(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
-o $(@:.html=.htp) $<; \
then \
rm -rf $@ && mv $(@:.html=.htp) $@; \
else \
rm -rf $(@:.html=.htp); exit 1; \
fi
$(srcdir)/gprofng.info: gprofng.texi $(srcdir)/version.texi $(gprofng_TEXINFOS)
gprofng.dvi: gprofng.texi $(srcdir)/version.texi $(gprofng_TEXINFOS)
gprofng.pdf: gprofng.texi $(srcdir)/version.texi $(gprofng_TEXINFOS)
gprofng.html: gprofng.texi $(srcdir)/version.texi $(gprofng_TEXINFOS)
$(srcdir)/version.texi: @MAINTAINER_MODE_TRUE@ $(srcdir)/stamp-vti
$(srcdir)/stamp-vti: gprofng.texi $(top_srcdir)/configure
@(dir=.; test -f ./gprofng.texi || dir=$(srcdir); \
set `$(SHELL) $(srcdir)/mdate-sh $$dir/gprofng.texi`; \
echo "@set UPDATED $$1 $$2 $$3"; \
echo "@set UPDATED-MONTH $$2 $$3"; \
echo "@set EDITION $(VERSION)"; \
echo "@set VERSION $(VERSION)") > vti.tmp$$$$ && \
(cmp -s vti.tmp$$$$ $(srcdir)/version.texi \
|| (echo "Updating $(srcdir)/version.texi" && \
cp vti.tmp$$$$ $(srcdir)/version.texi.tmp$$$$ && \
mv $(srcdir)/version.texi.tmp$$$$ $(srcdir)/version.texi)) && \
rm -f vti.tmp$$$$ $(srcdir)/version.texi.$$$$
@cp $(srcdir)/version.texi $@
mostlyclean-vti:
-rm -f vti.tmp* $(srcdir)/version.texi.tmp*
maintainer-clean-vti:
@MAINTAINER_MODE_TRUE@ -rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi
.dvi.ps:
$(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
$(DVIPS) $(AM_V_texinfo) -o $@ $<
uninstall-dvi-am:
@$(NORMAL_UNINSTALL)
@list='$(DVIS)'; test -n "$(dvidir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \
rm -f "$(DESTDIR)$(dvidir)/$$f"; \
done
uninstall-html-am:
@$(NORMAL_UNINSTALL)
@list='$(HTMLS)'; test -n "$(htmldir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \
rm -rf "$(DESTDIR)$(htmldir)/$$f"; \
done
uninstall-info-am:
@$(PRE_UNINSTALL)
@if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \
list='$(INFO_DEPS)'; \
for file in $$list; do \
relfile=`echo "$$file" | sed 's|^.*/||'`; \
echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \
if install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \
then :; else test ! -f "$(DESTDIR)$(infodir)/$$relfile" || exit 1; fi; \
done; \
else :; fi
@$(NORMAL_UNINSTALL)
@list='$(INFO_DEPS)'; \
for file in $$list; do \
relfile=`echo "$$file" | sed 's|^.*/||'`; \
relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \
(if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \
echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \
rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \
else :; fi); \
done
uninstall-pdf-am:
@$(NORMAL_UNINSTALL)
@list='$(PDFS)'; test -n "$(pdfdir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \
rm -f "$(DESTDIR)$(pdfdir)/$$f"; \
done
uninstall-ps-am:
@$(NORMAL_UNINSTALL)
@list='$(PSS)'; test -n "$(psdir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \
rm -f "$(DESTDIR)$(psdir)/$$f"; \
done
dist-info: $(INFO_DEPS)
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
list='$(INFO_DEPS)'; \
for base in $$list; do \
case $$base in \
$(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \
esac; \
if test -f $$base; then d=.; else d=$(srcdir); fi; \
base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \
for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \
if test -f $$file; then \
relfile=`expr "$$file" : "$$d/\(.*\)"`; \
test -f "$(distdir)/$$relfile" || \
cp -p $$file "$(distdir)/$$relfile"; \
else :; fi; \
done; \
done
mostlyclean-aminfo:
-rm -rf gprofng.t2d gprofng.t2p
clean-aminfo:
-test -z "gprofng.dvi gprofng.pdf gprofng.ps gprofng.html" \
|| rm -rf gprofng.dvi gprofng.pdf gprofng.ps gprofng.html
maintainer-clean-aminfo:
@list='$(INFO_DEPS)'; for i in $$list; do \
i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \
echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \
rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \
done
tags TAGS:
ctags CTAGS:
cscope cscopelist:
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
$(MAKE) $(AM_MAKEFLAGS) \
top_distdir="$(top_distdir)" distdir="$(distdir)" \
dist-info
check-am: all-am
check: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) check-am
all-am: Makefile $(INFO_DEPS)
installdirs:
for dir in "$(DESTDIR)$(infodir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) 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:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
clean: clean-am
clean-am: clean-aminfo clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
-rm -f Makefile
distclean-am: clean-am distclean-generic
dvi: dvi-am
dvi-am: $(DVIS)
html: html-am
html-am: $(HTMLS)
info: info-am
info-am: $(INFO_DEPS)
install-data-am: install-info-am
install-dvi: install-dvi-am
install-dvi-am: $(DVIS)
@$(NORMAL_INSTALL)
@list='$(DVIS)'; test -n "$(dvidir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \
$(MKDIR_P) "$(DESTDIR)$(dvidir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dvidir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(dvidir)" || exit $$?; \
done
install-exec-am:
install-html: install-html-am
install-html-am: $(HTMLS)
@$(NORMAL_INSTALL)
@list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \
$(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \
$(am__strip_dir) \
d2=$$d$$p; \
if test -d "$$d2"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \
$(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \
$(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \
else \
list2="$$list2 $$d2"; \
fi; \
done; \
test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \
done; }
install-info: install-info-am
install-info-am: $(INFO_DEPS)
@$(NORMAL_INSTALL)
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \
$(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \
fi; \
for file in $$list; do \
case $$file in \
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
esac; \
if test -f $$file; then d=.; else d=$(srcdir); fi; \
file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \
for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \
$$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \
if test -f $$ifile; then \
echo "$$ifile"; \
else : ; fi; \
done; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done
@$(POST_INSTALL)
@if $(am__can_run_installinfo); then \
list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
for file in $$list; do \
relfile=`echo "$$file" | sed 's|^.*/||'`; \
echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\
install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\
done; \
else : ; fi
install-man:
install-pdf: install-pdf-am
install-pdf-am: $(PDFS)
@$(NORMAL_INSTALL)
@list='$(PDFS)'; test -n "$(pdfdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(pdfdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pdfdir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; done
install-ps: install-ps-am
install-ps-am: $(PSS)
@$(NORMAL_INSTALL)
@list='$(PSS)'; test -n "$(psdir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(psdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(psdir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(psdir)" || exit $$?; done
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-aminfo \
maintainer-clean-generic maintainer-clean-vti
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-aminfo mostlyclean-generic \
mostlyclean-libtool mostlyclean-vti
pdf: pdf-am
pdf-am: $(PDFS)
ps: ps-am
ps-am: $(PSS)
uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \
uninstall-pdf-am uninstall-ps-am
.MAKE: all check install install-am install-strip
.PHONY: all all-am check check-am clean clean-aminfo clean-generic \
clean-libtool cscopelist-am ctags-am dist-info distclean \
distclean-generic distclean-libtool distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-pdf install-pdf-am \
install-ps install-ps-am install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-aminfo maintainer-clean-generic \
maintainer-clean-vti mostlyclean mostlyclean-aminfo \
mostlyclean-generic mostlyclean-libtool mostlyclean-vti pdf \
pdf-am ps ps-am tags-am uninstall uninstall-am \
uninstall-dvi-am uninstall-html-am uninstall-info-am \
uninstall-pdf-am uninstall-ps-am
.PRECIOUS: Makefile
version.texi:
@echo "@set EDITION 1.0" > $@
@echo "@set VERSION 1.0" >> $@
@echo "@set UPDATED 22 February 2022" >> $@
@echo "@set UPDATED-MONTH February 2022" >> $@
# 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:

506
gprofng/doc/fdl.texi Normal file
View file

@ -0,0 +1,506 @@
@c The GNU Free Documentation License.
@center Version 1.3, 3 November 2008
@c This file is intended to be included within another document,
@c hence no sectioning command or @node.
@display
Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
@uref{http://fsf.org/}
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@end display
@enumerate 0
@item
PREAMBLE
The purpose of this License is to make a manual, textbook, or other
functional and useful document @dfn{free} in the sense of freedom: to
assure everyone the effective freedom to copy and redistribute it,
with or without modifying it, either commercially or noncommercially.
Secondarily, this License preserves for the author and publisher a way
to get credit for their work, while not being considered responsible
for modifications made by others.
This License is a kind of ``copyleft'', which means that derivative
works of the document must themselves be free in the same sense. It
complements the GNU General Public License, which is a copyleft
license designed for free software.
We have designed this License in order to use it for manuals for free
software, because free software needs free documentation: a free
program should come with manuals providing the same freedoms that the
software does. But this License is not limited to software manuals;
it can be used for any textual work, regardless of subject matter or
whether it is published as a printed book. We recommend this License
principally for works whose purpose is instruction or reference.
@item
APPLICABILITY AND DEFINITIONS
This License applies to any manual or other work, in any medium, that
contains a notice placed by the copyright holder saying it can be
distributed under the terms of this License. Such a notice grants a
world-wide, royalty-free license, unlimited in duration, to use that
work under the conditions stated herein. The ``Document'', below,
refers to any such manual or work. Any member of the public is a
licensee, and is addressed as ``you''. You accept the license if you
copy, modify or distribute the work in a way requiring permission
under copyright law.
A ``Modified Version'' of the Document means any work containing the
Document or a portion of it, either copied verbatim, or with
modifications and/or translated into another language.
A ``Secondary Section'' is a named appendix or a front-matter section
of the Document that deals exclusively with the relationship of the
publishers or authors of the Document to the Document's overall
subject (or to related matters) and contains nothing that could fall
directly within that overall subject. (Thus, if the Document is in
part a textbook of mathematics, a Secondary Section may not explain
any mathematics.) The relationship could be a matter of historical
connection with the subject or with related matters, or of legal,
commercial, philosophical, ethical or political position regarding
them.
The ``Invariant Sections'' are certain Secondary Sections whose titles
are designated, as being those of Invariant Sections, in the notice
that says that the Document is released under this License. If a
section does not fit the above definition of Secondary then it is not
allowed to be designated as Invariant. The Document may contain zero
Invariant Sections. If the Document does not identify any Invariant
Sections then there are none.
The ``Cover Texts'' are certain short passages of text that are listed,
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
the Document is released under this License. A Front-Cover Text may
be at most 5 words, and a Back-Cover Text may be at most 25 words.
A ``Transparent'' copy of the Document means a machine-readable copy,
represented in a format whose specification is available to the
general public, that is suitable for revising the document
straightforwardly with generic text editors or (for images composed of
pixels) generic paint programs or (for drawings) some widely available
drawing editor, and that is suitable for input to text formatters or
for automatic translation to a variety of formats suitable for input
to text formatters. A copy made in an otherwise Transparent file
format whose markup, or absence of markup, has been arranged to thwart
or discourage subsequent modification by readers is not Transparent.
An image format is not Transparent if used for any substantial amount
of text. A copy that is not ``Transparent'' is called ``Opaque''.
Examples of suitable formats for Transparent copies include plain
@sc{ascii} without markup, Texinfo input format, La@TeX{} input
format, @acronym{SGML} or @acronym{XML} using a publicly available
@acronym{DTD}, and standard-conforming simple @acronym{HTML},
PostScript or @acronym{PDF} designed for human modification. Examples
of transparent image formats include @acronym{PNG}, @acronym{XCF} and
@acronym{JPG}. Opaque formats include proprietary formats that can be
read and edited only by proprietary word processors, @acronym{SGML} or
@acronym{XML} for which the @acronym{DTD} and/or processing tools are
not generally available, and the machine-generated @acronym{HTML},
PostScript or @acronym{PDF} produced by some word processors for
output purposes only.
The ``Title Page'' means, for a printed book, the title page itself,
plus such following pages as are needed to hold, legibly, the material
this License requires to appear in the title page. For works in
formats which do not have any title page as such, ``Title Page'' means
the text near the most prominent appearance of the work's title,
preceding the beginning of the body of the text.
The ``publisher'' means any person or entity that distributes copies
of the Document to the public.
A section ``Entitled XYZ'' means a named subunit of the Document whose
title either is precisely XYZ or contains XYZ in parentheses following
text that translates XYZ in another language. (Here XYZ stands for a
specific section name mentioned below, such as ``Acknowledgements'',
``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title''
of such a section when you modify the Document means that it remains a
section ``Entitled XYZ'' according to this definition.
The Document may include Warranty Disclaimers next to the notice which
states that this License applies to the Document. These Warranty
Disclaimers are considered to be included by reference in this
License, but only as regards disclaiming warranties: any other
implication that these Warranty Disclaimers may have is void and has
no effect on the meaning of this License.
@item
VERBATIM COPYING
You may copy and distribute the Document in any medium, either
commercially or noncommercially, provided that this License, the
copyright notices, and the license notice saying this License applies
to the Document are reproduced in all copies, and that you add no other
conditions whatsoever to those of this License. You may not use
technical measures to obstruct or control the reading or further
copying of the copies you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large enough
number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and
you may publicly display copies.
@item
COPYING IN QUANTITY
If you publish printed copies (or copies in media that commonly have
printed covers) of the Document, numbering more than 100, and the
Document's license notice requires Cover Texts, you must enclose the
copies in covers that carry, clearly and legibly, all these Cover
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
the back cover. Both covers must also clearly and legibly identify
you as the publisher of these copies. The front cover must present
the full title with all words of the title equally prominent and
visible. You may add other material on the covers in addition.
Copying with changes limited to the covers, as long as they preserve
the title of the Document and satisfy these conditions, can be treated
as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit
legibly, you should put the first ones listed (as many as fit
reasonably) on the actual cover, and continue the rest onto adjacent
pages.
If you publish or distribute Opaque copies of the Document numbering
more than 100, you must either include a machine-readable Transparent
copy along with each Opaque copy, or state in or with each Opaque copy
a computer-network location from which the general network-using
public has access to download using public-standard network protocols
a complete Transparent copy of the Document, free of added material.
If you use the latter option, you must take reasonably prudent steps,
when you begin distribution of Opaque copies in quantity, to ensure
that this Transparent copy will remain thus accessible at the stated
location until at least one year after the last time you distribute an
Opaque copy (directly or through your agents or retailers) of that
edition to the public.
It is requested, but not required, that you contact the authors of the
Document well before redistributing any large number of copies, to give
them a chance to provide you with an updated version of the Document.
@item
MODIFICATIONS
You may copy and distribute a Modified Version of the Document under
the conditions of sections 2 and 3 above, provided that you release
the Modified Version under precisely this License, with the Modified
Version filling the role of the Document, thus licensing distribution
and modification of the Modified Version to whoever possesses a copy
of it. In addition, you must do these things in the Modified Version:
@enumerate A
@item
Use in the Title Page (and on the covers, if any) a title distinct
from that of the Document, and from those of previous versions
(which should, if there were any, be listed in the History section
of the Document). You may use the same title as a previous version
if the original publisher of that version gives permission.
@item
List on the Title Page, as authors, one or more persons or entities
responsible for authorship of the modifications in the Modified
Version, together with at least five of the principal authors of the
Document (all of its principal authors, if it has fewer than five),
unless they release you from this requirement.
@item
State on the Title page the name of the publisher of the
Modified Version, as the publisher.
@item
Preserve all the copyright notices of the Document.
@item
Add an appropriate copyright notice for your modifications
adjacent to the other copyright notices.
@item
Include, immediately after the copyright notices, a license notice
giving the public permission to use the Modified Version under the
terms of this License, in the form shown in the Addendum below.
@item
Preserve in that license notice the full lists of Invariant Sections
and required Cover Texts given in the Document's license notice.
@item
Include an unaltered copy of this License.
@item
Preserve the section Entitled ``History'', Preserve its Title, and add
to it an item stating at least the title, year, new authors, and
publisher of the Modified Version as given on the Title Page. If
there is no section Entitled ``History'' in the Document, create one
stating the title, year, authors, and publisher of the Document as
given on its Title Page, then add an item describing the Modified
Version as stated in the previous sentence.
@item
Preserve the network location, if any, given in the Document for
public access to a Transparent copy of the Document, and likewise
the network locations given in the Document for previous versions
it was based on. These may be placed in the ``History'' section.
You may omit a network location for a work that was published at
least four years before the Document itself, or if the original
publisher of the version it refers to gives permission.
@item
For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
the Title of the section, and preserve in the section all the
substance and tone of each of the contributor acknowledgements and/or
dedications given therein.
@item
Preserve all the Invariant Sections of the Document,
unaltered in their text and in their titles. Section numbers
or the equivalent are not considered part of the section titles.
@item
Delete any section Entitled ``Endorsements''. Such a section
may not be included in the Modified Version.
@item
Do not retitle any existing section to be Entitled ``Endorsements'' or
to conflict in title with any Invariant Section.
@item
Preserve any Warranty Disclaimers.
@end enumerate
If the Modified Version includes new front-matter sections or
appendices that qualify as Secondary Sections and contain no material
copied from the Document, you may at your option designate some or all
of these sections as invariant. To do this, add their titles to the
list of Invariant Sections in the Modified Version's license notice.
These titles must be distinct from any other section titles.
You may add a section Entitled ``Endorsements'', provided it contains
nothing but endorsements of your Modified Version by various
parties---for example, statements of peer review or that the text has
been approved by an organization as the authoritative definition of a
standard.
You may add a passage of up to five words as a Front-Cover Text, and a
passage of up to 25 words as a Back-Cover Text, to the end of the list
of Cover Texts in the Modified Version. Only one passage of
Front-Cover Text and one of Back-Cover Text may be added by (or
through arrangements made by) any one entity. If the Document already
includes a cover text for the same cover, previously added by you or
by arrangement made by the same entity you are acting on behalf of,
you may not add another; but you may replace the old one, on explicit
permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License
give permission to use their names for publicity for or to assert or
imply endorsement of any Modified Version.
@item
COMBINING DOCUMENTS
You may combine the Document with other documents released under this
License, under the terms defined in section 4 above for modified
versions, provided that you include in the combination all of the
Invariant Sections of all of the original documents, unmodified, and
list them all as Invariant Sections of your combined work in its
license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and
multiple identical Invariant Sections may be replaced with a single
copy. If there are multiple Invariant Sections with the same name but
different contents, make the title of each such section unique by
adding at the end of it, in parentheses, the name of the original
author or publisher of that section if known, or else a unique number.
Make the same adjustment to the section titles in the list of
Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled ``History''
in the various original documents, forming one section Entitled
``History''; likewise combine any sections Entitled ``Acknowledgements'',
and any sections Entitled ``Dedications''. You must delete all
sections Entitled ``Endorsements.''
@item
COLLECTIONS OF DOCUMENTS
You may make a collection consisting of the Document and other documents
released under this License, and replace the individual copies of this
License in the various documents with a single copy that is included in
the collection, provided that you follow the rules of this License for
verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute
it individually under this License, provided you insert a copy of this
License into the extracted document, and follow this License in all
other respects regarding verbatim copying of that document.
@item
AGGREGATION WITH INDEPENDENT WORKS
A compilation of the Document or its derivatives with other separate
and independent documents or works, in or on a volume of a storage or
distribution medium, is called an ``aggregate'' if the copyright
resulting from the compilation is not used to limit the legal rights
of the compilation's users beyond what the individual works permit.
When the Document is included in an aggregate, this License does not
apply to the other works in the aggregate which are not themselves
derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these
copies of the Document, then if the Document is less than one half of
the entire aggregate, the Document's Cover Texts may be placed on
covers that bracket the Document within the aggregate, or the
electronic equivalent of covers if the Document is in electronic form.
Otherwise they must appear on printed covers that bracket the whole
aggregate.
@item
TRANSLATION
Translation is considered a kind of modification, so you may
distribute translations of the Document under the terms of section 4.
Replacing Invariant Sections with translations requires special
permission from their copyright holders, but you may include
translations of some or all Invariant Sections in addition to the
original versions of these Invariant Sections. You may include a
translation of this License, and all the license notices in the
Document, and any Warranty Disclaimers, provided that you also include
the original English version of this License and the original versions
of those notices and disclaimers. In case of a disagreement between
the translation and the original version of this License or a notice
or disclaimer, the original version will prevail.
If a section in the Document is Entitled ``Acknowledgements'',
``Dedications'', or ``History'', the requirement (section 4) to Preserve
its Title (section 1) will typically require changing the actual
title.
@item
TERMINATION
You may not copy, modify, sublicense, or distribute the Document
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense, or distribute it is void, and
will automatically terminate your rights under this License.
However, if you cease all violation of this License, then your license
from a particular copyright holder is reinstated (a) provisionally,
unless and until the copyright holder explicitly and finally
terminates your license, and (b) permanently, if the copyright holder
fails to notify you of the violation by some reasonable means prior to
60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, receipt of a copy of some or all of the same material does
not give you any rights to use it.
@item
FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised versions
of the GNU Free Documentation License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns. See
@uref{http://www.gnu.org/copyleft/}.
Each version of the License is given a distinguishing version number.
If the Document specifies that a particular numbered version of this
License ``or any later version'' applies to it, you have the option of
following the terms and conditions either of that specified version or
of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a version
number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation. If the Document
specifies that a proxy can decide which future versions of this
License can be used, that proxy's public statement of acceptance of a
version permanently authorizes you to choose that version for the
Document.
@item
RELICENSING
``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any
World Wide Web server that publishes copyrightable works and also
provides prominent facilities for anybody to edit those works. A
public wiki that anybody can edit is an example of such a server. A
``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the
site means any set of copyrightable works thus published on the MMC
site.
``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0
license published by Creative Commons Corporation, a not-for-profit
corporation with a principal place of business in San Francisco,
California, as well as future copyleft versions of that license
published by that same organization.
``Incorporate'' means to publish or republish a Document, in whole or
in part, as part of another Document.
An MMC is ``eligible for relicensing'' if it is licensed under this
License, and if all works that were first published under this License
somewhere other than this MMC, and subsequently incorporated in whole
or in part into the MMC, (1) had no cover texts or invariant sections,
and (2) were thus incorporated prior to November 1, 2008.
The operator of an MMC Site may republish an MMC contained in the site
under CC-BY-SA on the same site at any time before August 1, 2009,
provided the MMC is eligible for relicensing.
@end enumerate
@page
@heading ADDENDUM: How to use this License for your documents
To use this License in a document you have written, include a copy of
the License in the document and put the following copyright and
license notices just after the title page:
@smallexample
@group
Copyright (C) @var{year} @var{your name}.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the section entitled ``GNU
Free Documentation License''.
@end group
@end smallexample
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
replace the ``with@dots{}Texts.'' line with this:
@smallexample
@group
with the Invariant Sections being @var{list their titles}, with
the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
being @var{list}.
@end group
@end smallexample
If you have Invariant Sections without Cover Texts, or some other
combination of the three, merge those two alternatives to suit the
situation.
If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of
free software license, such as the GNU General Public License,
to permit their use in free software.
@c Local Variables:
@c ispell-local-pdict: "ispell-dict"
@c End:

3399
gprofng/doc/gprofng.texi Normal file

File diff suppressed because it is too large Load diff

224
gprofng/doc/mdate-sh Executable file
View file

@ -0,0 +1,224 @@
#!/bin/sh
# Get modification time of a file or directory and pretty-print it.
scriptversion=2016-01-11.22; # UTC
# Copyright (C) 1995-2017 Free Software Foundation, Inc.
# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
emulate sh
NULLCMD=:
# Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
setopt NO_GLOB_SUBST
fi
case $1 in
'')
echo "$0: No file. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: mdate-sh [--help] [--version] FILE
Pretty-print the modification day of FILE, in the format:
1 January 1970
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "mdate-sh $scriptversion"
exit $?
;;
esac
error ()
{
echo "$0: $1" >&2
exit 1
}
# Prevent date giving response in another language.
LANG=C
export LANG
LC_ALL=C
export LC_ALL
LC_TIME=C
export LC_TIME
# GNU ls changes its time format in response to the TIME_STYLE
# variable. Since we cannot assume 'unset' works, revert this
# variable to its documented default.
if test "${TIME_STYLE+set}" = set; then
TIME_STYLE=posix-long-iso
export TIME_STYLE
fi
save_arg1=$1
# Find out how to get the extended ls output of a file or directory.
if ls -L /dev/null 1>/dev/null 2>&1; then
ls_command='ls -L -l -d'
else
ls_command='ls -l -d'
fi
# Avoid user/group names that might have spaces, when possible.
if ls -n /dev/null 1>/dev/null 2>&1; then
ls_command="$ls_command -n"
fi
# A 'ls -l' line looks as follows on OS/2.
# drwxrwx--- 0 Aug 11 2001 foo
# This differs from Unix, which adds ownership information.
# drwxrwx--- 2 root root 4096 Aug 11 2001 foo
#
# To find the date, we split the line on spaces and iterate on words
# until we find a month. This cannot work with files whose owner is a
# user named "Jan", or "Feb", etc. However, it's unlikely that '/'
# will be owned by a user whose name is a month. So we first look at
# the extended ls output of the root directory to decide how many
# words should be skipped to get the date.
# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below.
set x`$ls_command /`
# Find which argument is the month.
month=
command=
until test $month
do
test $# -gt 0 || error "failed parsing '$ls_command /' output"
shift
# Add another shift to the command.
command="$command shift;"
case $1 in
Jan) month=January; nummonth=1;;
Feb) month=February; nummonth=2;;
Mar) month=March; nummonth=3;;
Apr) month=April; nummonth=4;;
May) month=May; nummonth=5;;
Jun) month=June; nummonth=6;;
Jul) month=July; nummonth=7;;
Aug) month=August; nummonth=8;;
Sep) month=September; nummonth=9;;
Oct) month=October; nummonth=10;;
Nov) month=November; nummonth=11;;
Dec) month=December; nummonth=12;;
esac
done
test -n "$month" || error "failed parsing '$ls_command /' output"
# Get the extended ls output of the file or directory.
set dummy x`eval "$ls_command \"\\\$save_arg1\""`
# Remove all preceding arguments
eval $command
# Because of the dummy argument above, month is in $2.
#
# On a POSIX system, we should have
#
# $# = 5
# $1 = file size
# $2 = month
# $3 = day
# $4 = year or time
# $5 = filename
#
# On Darwin 7.7.0 and 7.6.0, we have
#
# $# = 4
# $1 = day
# $2 = month
# $3 = year or time
# $4 = filename
# Get the month.
case $2 in
Jan) month=January; nummonth=1;;
Feb) month=February; nummonth=2;;
Mar) month=March; nummonth=3;;
Apr) month=April; nummonth=4;;
May) month=May; nummonth=5;;
Jun) month=June; nummonth=6;;
Jul) month=July; nummonth=7;;
Aug) month=August; nummonth=8;;
Sep) month=September; nummonth=9;;
Oct) month=October; nummonth=10;;
Nov) month=November; nummonth=11;;
Dec) month=December; nummonth=12;;
esac
case $3 in
???*) day=$1;;
*) day=$3; shift;;
esac
# Here we have to deal with the problem that the ls output gives either
# the time of day or the year.
case $3 in
*:*) set `date`; eval year=\$$#
case $2 in
Jan) nummonthtod=1;;
Feb) nummonthtod=2;;
Mar) nummonthtod=3;;
Apr) nummonthtod=4;;
May) nummonthtod=5;;
Jun) nummonthtod=6;;
Jul) nummonthtod=7;;
Aug) nummonthtod=8;;
Sep) nummonthtod=9;;
Oct) nummonthtod=10;;
Nov) nummonthtod=11;;
Dec) nummonthtod=12;;
esac
# For the first six month of the year the time notation can also
# be used for files modified in the last year.
if (expr $nummonth \> $nummonthtod) > /dev/null;
then
year=`expr $year - 1`
fi;;
*) year=$3;;
esac
# The result.
echo $day $month $year
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

11731
gprofng/doc/texinfo.tex Normal file

File diff suppressed because it is too large Load diff

4
gprofng/doc/version.texi Normal file
View file

@ -0,0 +1,4 @@
@set EDITION 1.0
@set VERSION 1.0
@set UPDATED 22 February 2022
@set UPDATED-MONTH February 2022

View file

@ -0,0 +1,60 @@
## Process this file with automake to generate Makefile.in
#
# Copyright (C) 2021 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I . -I .. -I ../..
dist_man_MANS = gp-display-html.1
bin_SCRIPTS = gp-display-html
CLEANFILES = $(bin_SCRIPTS)
MAINTAINERCLEANFILES = $(dist_man_MANS)
do_subst = sed -e 's/BINUTILS_VERSION/$(VERSION)/'
gp-display-html: gp-display-html.in Makefile
$(do_subst) < $(srcdir)/gp-display-html.in > $@
chmod +x $@
if BUILD_MAN
# Use this if the man pages depend on the version number.
# common_mandeps = $(top_srcdir)/../bfd/version.m4
#
# Also change the dependence line below to this:
# gp-display-html.1: $(common_mandeps) gp-display-html
#
# Currently, the version number shown in the man page is derived from
# the output printed with --version.
# These variables are used by help2man to generate the man pages.
INFO_PAGE = "gprofng"
MANUAL = "User Commands"
TEXT_GP_DISPLAY_HTML = "generate an HTML based directory structure to browse the profiles"
HELP2MAN_OPT = --libtool --no-info --info-page=$(INFO_PAGE) --manual=$(MANUAL)
H2M_FILTER = | sed 's/\.TP/\.TP\n.B/' | sed 's/Commands:/\.SH COMMANDS/' \
| sed 's/See also:/\.SH SEE ALSO/' | sed 's/Documentation:/.SH DOCUMENTATION/' \
| sed 's/Limitations:/.SH LIMITATIONS/'
gp-display-html.1: gp-display-html
$(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
--name=$(TEXT_GP_DISPLAY_HTML) ./gp-display-html $(H2M_FILTER) > $@
endif

View file

@ -0,0 +1,630 @@
# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2017 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@
#
# Copyright (C) 2021 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
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 = :
build_triplet = @build@
host_triplet = @host@
subdir = gp-display-html
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../libtool.m4 \
$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
$(top_srcdir)/acinclude.m4 $(top_srcdir)/../config/warnings.m4 \
$(top_srcdir)/../config/enable.m4 \
$(top_srcdir)/../config/ax_pthread.m4 \
$(top_srcdir)/config/bison.m4 $(top_srcdir)/../bfd/version.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"
SCRIPTS = $(bin_SCRIPTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
SOURCES =
DIST_SOURCES =
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
man1dir = $(mandir)/man1
NROFF = nroff
MANS = $(dist_man_MANS)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
am__DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.in \
$(top_srcdir)/../mkinstalldirs
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BUILD_SUBDIRS = @BUILD_SUBDIRS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
EXPECT = @EXPECT@
FGREP = @FGREP@
GPROFNG_CFLAGS = @GPROFNG_CFLAGS@
GPROFNG_CPPFLAGS = @GPROFNG_CPPFLAGS@
GPROFNG_LIBADD = @GPROFNG_LIBADD@
GPROFNG_LIBDIR = @GPROFNG_LIBDIR@
GREP = @GREP@
HELP2MAN = @HELP2MAN@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
JAVA = @JAVA@
JAVAC = @JAVAC@
LD = @LD@
LDFLAGS = @LDFLAGS@
LD_NO_AS_NEEDED = @LD_NO_AS_NEEDED@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PTHREAD_CC = @PTHREAD_CC@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
PTHREAD_LIBS = @PTHREAD_LIBS@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
WERROR = @WERROR@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
ax_pthread_config = @ax_pthread_config@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
gprofng_cflags = @gprofng_cflags@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
jdk_inc = @jdk_inc@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
subdirs = @subdirs@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I . -I .. -I ../..
dist_man_MANS = gp-display-html.1
bin_SCRIPTS = gp-display-html
CLEANFILES = $(bin_SCRIPTS)
MAINTAINERCLEANFILES = $(dist_man_MANS)
do_subst = sed -e 's/BINUTILS_VERSION/$(VERSION)/'
# Use this if the man pages depend on the version number.
# common_mandeps = $(top_srcdir)/../bfd/version.m4
#
# Also change the dependence line below to this:
# gp-display-html.1: $(common_mandeps) gp-display-html
#
# Currently, the version number shown in the man page is derived from
# the output printed with --version.
# These variables are used by help2man to generate the man pages.
@BUILD_MAN_TRUE@INFO_PAGE = "gprofng"
@BUILD_MAN_TRUE@MANUAL = "User Commands"
@BUILD_MAN_TRUE@TEXT_GP_DISPLAY_HTML = "generate an HTML based directory structure to browse the profiles"
@BUILD_MAN_TRUE@HELP2MAN_OPT = --libtool --no-info --info-page=$(INFO_PAGE) --manual=$(MANUAL)
@BUILD_MAN_TRUE@H2M_FILTER = | sed 's/\.TP/\.TP\n.B/' | sed 's/Commands:/\.SH COMMANDS/' \
@BUILD_MAN_TRUE@ | sed 's/See also:/\.SH SEE ALSO/' | sed 's/Documentation:/.SH DOCUMENTATION/' \
@BUILD_MAN_TRUE@ | sed 's/Limitations:/.SH LIMITATIONS/'
all: all-am
.SUFFIXES:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gp-display-html/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign gp-display-html/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: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-binSCRIPTS: $(bin_SCRIPTS)
@$(NORMAL_INSTALL)
@list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
$(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n' \
-e 'h;s|.*|.|' \
-e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) { files[d] = files[d] " " $$1; \
if (++n[d] == $(am__install_max)) { \
print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
else { print "f", d "/" $$4, $$1 } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \
$(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
} \
; done
uninstall-binSCRIPTS:
@$(NORMAL_UNINSTALL)
@list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 's,.*/,,;$(transform)'`; \
dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir)
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
install-man1: $(dist_man_MANS)
@$(NORMAL_INSTALL)
@list1=''; \
list2='$(dist_man_MANS)'; \
test -n "$(man1dir)" \
&& test -n "`echo $$list1$$list2`" \
|| exit 0; \
echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
$(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
{ for i in $$list1; do echo "$$i"; done; \
if test -n "$$list2"; then \
for i in $$list2; do echo "$$i"; done \
| sed -n '/\.1[a-z]*$$/p'; \
fi; \
} | while read p; do \
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; echo "$$p"; \
done | \
sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
sed 'N;N;s,\n, ,g' | { \
list=; while read file base inst; do \
if test "$$base" = "$$inst"; then list="$$list $$file"; else \
echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
$(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
fi; \
done; \
for i in $$list; do echo "$$i"; done | $(am__base_list) | \
while read files; do \
test -z "$$files" || { \
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
$(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
done; }
uninstall-man1:
@$(NORMAL_UNINSTALL)
@list=''; test -n "$(man1dir)" || exit 0; \
files=`{ for i in $$list; do echo "$$i"; done; \
l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \
sed -n '/\.1[a-z]*$$/p'; \
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
tags TAGS:
ctags CTAGS:
cscope cscopelist:
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$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 $(SCRIPTS) $(MANS)
installdirs:
for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
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:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
clean: clean-am
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
-rm -f Makefile
distclean-am: clean-am distclean-generic
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am: install-man
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-binSCRIPTS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man: install-man1
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-binSCRIPTS uninstall-man
uninstall-man: uninstall-man1
.MAKE: install-am install-strip
.PHONY: all all-am check check-am clean clean-generic clean-libtool \
cscopelist-am ctags-am distclean distclean-generic \
distclean-libtool distdir dvi dvi-am html html-am info info-am \
install install-am install-binSCRIPTS install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-man1 install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-generic \
mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
uninstall-am uninstall-binSCRIPTS uninstall-man uninstall-man1
.PRECIOUS: Makefile
gp-display-html: gp-display-html.in Makefile
$(do_subst) < $(srcdir)/gp-display-html.in > $@
chmod +x $@
@BUILD_MAN_TRUE@gp-display-html.1: gp-display-html
@BUILD_MAN_TRUE@ $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
@BUILD_MAN_TRUE@ --name=$(TEXT_GP_DISPLAY_HTML) ./gp-display-html $(H2M_FILTER) > $@
# 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:

View file

@ -0,0 +1,256 @@
#!/usr/bin/perl
# Copyright (C) 2021 Free Software Foundation, Inc.
# Contributed by Oracle.
#
# This file is part of GNU Binutils.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, 51 Franklin Street - Fifth Floor, Boston,
# MA 02110-1301, USA.
#------------------------------------------------------------------------------
# gp-display-html, last updated July 2021
#
# NOTE: This is a skeleton version. The real code will follow as an update.
#------------------------------------------------------------------------------
use strict;
use warnings;
#------------------------------------------------------------------------------
# Poor man's version of a boolean.
#------------------------------------------------------------------------------
my $TRUE = 1;
my $FALSE = 0;
#-------------------------------------------------------------------------------
# Define the driver command, tool name and version number.
#-------------------------------------------------------------------------------
my $driver_cmd = "gprofng display html";
my $tool_name = "gp-display-html";
my $binutils_version = "BINUTILS_VERSION";
my $version_info = $tool_name . " GNU binutils version " . $binutils_version;
#------------------------------------------------------------------------------
# This is cosmetic, but helps with the scoping of variables.
#------------------------------------------------------------------------------
main ();
exit (0);
#------------------------------------------------------------------------------
# THE SUBROUTINES
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# This is the driver part of the program.
#------------------------------------------------------------------------------
sub
main
{
my $subr_name = "main";
my $ignore_value;
#------------------------------------------------------------------------------
# If no options are given, print the help info and exit.
#------------------------------------------------------------------------------
$ignore_value = early_scan_specific_options();
$ignore_value = be_patient ();
return (0);
} #-- End of subroutine main
sub
be_patient
{
print "Functionality not implemented yet - please stay tuned for updates\n";
} #-- End of subroutine be_patient
#------------------------------------------------------------------------------
# Prints the version number and license information.
#------------------------------------------------------------------------------
sub
print_version_info
{
print "$version_info\n";
print "Copyright (C) 2021 Free Software Foundation, Inc.\n";
print "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.\n";
print "This is free software: you are free to change and redistribute it.\n";
print "There is NO WARRANTY, to the extent permitted by law.\n";
return (0);
} #-- End of subroutine print_version_info
#-------------------------------------------------------------------------------
# Print the help overview
#-------------------------------------------------------------------------------
sub
print_help_info
{
print
"Usage: $driver_cmd [OPTION(S)] EXPERIMENT(S)\n".
"\n".
"Process one or more experiments to generate a directory containing an index.html\n".
"file that can be used to browse the experiment data\n".
"\n".
"Options:\n".
"\n".
" --help print usage information and exit.\n".
" --version print the version number and exit.\n".
" --verbose {on|off} enable (on) or disable (off) verbose mode; the default is \"off\".\n".
"\n".
"\n".
" -o, --output <dir-name> use <dir-name> to store the results in; the default\n".
" name is ./display.<n>.html with <n> the first number\n".
" not in use; an existing directory is not overwritten.\n".
"\n".
" -O, --overwrite <dir-name> use <dir-name> to store the results in and overwrite\n".
" any existing directory with the same name; make sure\n".
" that umask is set to the correct access permissions.\n".
"\n".
" -fl, --func_limit <limit> impose a limit on the number of functions processed;\n".
" this is an integer number; set to 0 to process all\n".
" functions; the default value is 100.\n".
"\n".
" -ct, --calltree {on|off} enable or disable an html page with a call tree linked\n".
" from the bottom of the first page; default is off.\n".
"\n".
" -tp, --threshold_percentage <percentage> provide a percentage of metric accountability; the\n".
" inclusion of functions for each metric will take\n".
" place in sort order until the percentage has been\n".
" reached.\n".
"\n".
" -dm, --default_metrics {on|off} enable or disable automatic selection of metrics\n".
" and use a default set of metrics; the default is off.\n".
"\n".
" -im, --ignore_metrics <metric-list> ignore the metrics from <metric-list>.\n".
"\n".
" -db, --debug {on|off} enable/disable debug mode; print detailed information to assist with troubleshooting\n".
" or further development of this tool; default is off.\n".
"\n".
" -q, --quiet {on|off} disable/enable the display of warnings; default is off.\n".
"\n".
"Environment:\n".
"\n".
"The options can be set in a configuration file called .gp-display-html.rc. This\n".
"file needs to be either in the current directory, or in the home directory of the user.\n".
"The long name of the option without the leading dashes is supported. For example calltree\n".
"to enable or disable the call tree. Note that some options take a value. In case the same option\n".
"occurs multiple times in this file, only the last setting encountered is preserved.\n".
"\n".
"Documentation:\n".
"\n".
"A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n".
"gprofng programs are properly installed at your site, the command \"info gprofng\"\n".
"should give you access to this document.\n".
"\n".
"See also:\n".
"\n".
"gprofng(1), gp-archive(1), gp-collect-app(1), gp-display-src(1), gp-display-text(1)\n";
return (0);
} #-- End of subroutine print_help_info
#------------------------------------------------------------------------------
# Scan the command line for specific options.
#------------------------------------------------------------------------------
sub
early_scan_specific_options
{
my $subr_name = "early_scan_specific_options";
my $ignore_value;
my $found_option;
my $option_has_value;
my $option_value;
my $verbose_setting = $FALSE;
my $debug_setting = $FALSE;
my $quiet_setting = $FALSE;
$option_has_value = $FALSE;
($found_option, $option_value) = find_target_option (\@ARGV, $option_has_value, "--version");
if ($found_option)
{
$ignore_value = print_version_info ();
exit(0);
}
$option_has_value = $FALSE;
($found_option, $option_value) = find_target_option (\@ARGV, $option_has_value, "--help");
if ($found_option)
{
$ignore_value = print_help_info ();
exit(0);
}
return (0);
} #-- End of subroutine early_scan_specific_options
#------------------------------------------------------------------------------
# Scan the command line to see if the specified option is present.
#
# Two types of options are supported: options without value (e.g. --help) or
# those that are set to "on" or "off".
#------------------------------------------------------------------------------
sub
find_target_option
{
my ($command_line_ref, $has_value, $target_option) = @_;
my @command_line = @{ $command_line_ref };
my ($command_line_string) = join(" ", @command_line);
my $option_value = "not set";
my $found_option = $FALSE;
if ($command_line_string =~ /\s*($target_option)\s*(on|off)*\s*/)
{
if ($has_value)
{
#------------------------------------------------------------------------------
# We are looking for this kind if substring: "--verbose on"
#------------------------------------------------------------------------------
if (defined($1) and defined($2))
{
if ( ($2 eq "on") or ($2 eq "off") )
{
$found_option = $TRUE;
$option_value = $2;
}
}
}
else
{
#------------------------------------------------------------------------------
# We are looking for this kind if substring: "--help"
#------------------------------------------------------------------------------
if (defined($1))
{
$found_option = $TRUE;
}
}
}
return($found_option, $option_value);
} #-- End of subroutine find_target_option

View file

@ -0,0 +1,82 @@
#!/bin/sh
#
# Copyright (C) 2021 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
#
# CHK_LIBC_OBJ -- a script to scan the .o's in an output directory,
# which is one of ../{intel-S2,sparc-S2,intel-Linux,sparc-Linux}
#
# usage: cd to the output directory, and invoke ../src/CHK_LIBC_OBJ
check_obj() {
logF="nm.`basename $1`.log"
if [ `uname` = 'Linux' ]; then
nm $1 | grep -v GLIBC_ > ${logF}
else
nm $1 > ${logF}
fi
FUNC_LIST="strcpy strlcpy strncpy strcat strlcat strncat strncmp strlen \
strerror strchr strrchr strpbrk strstr strtok strtok_r \
printf fprintf sprintf snprintf asprintf wsprintf \
vprintf vfprintf vsprintf vsnprintf vasprintf \
memset memcmp memcpy strtol strtoll strtoul strtoull \
getcpuid calloc malloc free strdup"
res=0
echo " -- Checking Object file '$1' for functions from libc"
for j in `echo ${FUNC_LIST}` ; do
grep -w ${j} ${logF} | grep UNDEF> grep.log 2>&1
if [ $? -eq 0 ]; then
grep -w ${j} ${logF}
res=1
fi
done
return ${res}
}
STATUS=0
for i in *.o ; do
echo ""
check_obj ${i}
res=$?
if [ ${res} -eq 0 ]; then
echo "Object file ${i} does not reference functions in libc"
else
echo "======Object file: ${i} DOES reference functions in libc"
fi
if [ ${STATUS} -eq 0 ]; then
STATUS=${res}
fi
done
for i in *.so ; do
echo ""
check_obj ${i}
res=$?
if [ ${res} -eq 0 ]; then
echo "Object file ${i} does not reference functions in libc"
else
echo "======Object file: ${i} DOES reference functions in libc"
fi
if [ ${STATUS} -eq 0 ]; then
STATUS=${res}
fi
done
exit $STATUS

View file

@ -0,0 +1,79 @@
## Process this file with automake to generate Makefile.in
#
# Copyright (C) 2021 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I . -I ../..
GPROFNG_VARIANT = @GPROFNG_VARIANT@
CSOURCES = \
gethrtime.c \
dispatcher.c \
iolib.c \
mmaptrace.c \
memmgr.c \
tsd.c \
profile.c \
envmgmt.c \
linetrace.c \
libcol_hwcdrv.c \
libcol_hwcfuncs.c \
libcol-i386-dis.c \
hwprofile.c \
jprofile.c \
unwind.c \
libcol_util.c \
collector.c \
$(NULL)
AM_CFLAGS = $(GPROFNG_CFLAGS) -Wno-nonnull-compare
AM_CPPFLAGS = $(GPROFNG_CPPFLAGS) -I.. -I$(srcdir) \
-I$(srcdir)/../common -I$(srcdir)/../src \
-I$(srcdir)/../../include
AM_LDFLAGS = -module -avoid-version \
-Wl,--version-script,$(srcdir)/mapfile.$(GPROFNG_VARIANT) \
$(LD_NO_AS_NEEDED) -Wl,-lrt -Wl,-ldl
myincludedir = @includedir@
myinclude_HEADERS = $(srcdir)/../../include/collectorAPI.h \
$(srcdir)/../../include/libcollector.h \
$(srcdir)/../../include/libfcollector.h
lib_LTLIBRARIES = libgp-collector.la libgp-collectorAPI.la libgp-heap.la \
libgp-sync.la libgp-iotrace.la
libgp_collector_la_SOURCES = $(CSOURCES)
libgp_collector_la_CPPFLAGS = $(AM_CPPFLAGS) $(jdk_inc) \
-I../../bfd -I$(srcdir)/../..
# Prevent libtool from reordering -Wl,--no-as-needed after -lrt by
# disguising -lrt as a linker flag.
libgp_collector_la_LDFLAGS = $(AM_LDFLAGS)
libgp_collector_la_LIBADD =
libgp_heap_la_SOURCES = heaptrace.c
libgp_heap_la_LDFLAGS = $(AM_LDFLAGS)
libgp_sync_la_SOURCES = synctrace.c
libgp_sync_la_LDFLAGS = $(AM_LDFLAGS)
libgp_iotrace_la_SOURCES = iotrace.c
libgp_iotrace_la_LDFLAGS = $(AM_LDFLAGS)
libgp_collectorAPI_la_SOURCES = collectorAPI.c
libgp_collectorAPI_la_LIBADD = -lc -ldl

File diff suppressed because it is too large Load diff

1237
gprofng/libcollector/aclocal.m4 vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,236 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _COLLECTOR_H
#define _COLLECTOR_H
#include <ucontext.h>
#include <signal.h>
#include "gp-defs.h"
#include "data_pckts.h"
#include "libcol_util.h"
#include "collector_module.h"
#define GETRELTIME() (__collector_gethrtime() - __collector_start_time)
extern hrtime_t __collector_start_time;
/* ========================================================== */
/* ------- internal function prototypes ----------------- */
/* These will not be exported from libcollector.so */
struct DataHandle;
struct Heap;
extern struct DataHandle *__collector_create_handle (char*);
extern void __collector_delete_handle (struct DataHandle*);
extern int __collector_write_record (struct DataHandle*, Common_packet*);
extern int __collector_write_packet (struct DataHandle*, CM_Packet*);
extern int __collector_write_string (struct DataHandle*, char*, int);
extern FrameInfo __collector_get_frame_info (hrtime_t, int, void *);
extern FrameInfo __collector_getUID (CM_Array *arg, FrameInfo uid);
extern int __collector_getStackTrace (void *buf, int size, void *bptr, void *eptr, void *arg);
extern void *__collector_ext_return_address (unsigned level);
extern void __collector_mmap_fork_child_cleanup ();
extern int __collector_ext_mmap_install (int);
extern int __collector_ext_mmap_deinstall (int);
extern int __collector_ext_update_map_segments (void);
extern int __collector_check_segment (unsigned long addr,
unsigned long *base,
unsigned long *end, int maxnretries);
extern int __collector_check_readable_segment (unsigned long addr,
unsigned long *base,
unsigned long *end, int maxnretries);
extern int __collector_ext_line_init (int * pfollow_this_experiment,
const char * progspec,
const char *progname);
extern int __collector_ext_line_install (char *, const char *);
extern void __collector_ext_line_close ();
extern void __collector_ext_unwind_init (int);
extern void __collector_ext_unwind_close ();
extern int __collector_ext_jstack_unwind (char*, int, ucontext_t *);
extern void __collector_ext_dispatcher_fork_child_cleanup ();
extern void __collector_ext_unwind_key_init (int isPthread, void * stack);
extern void __collector_ext_dispatcher_tsd_create_key ();
extern void __collector_ext_dispatcher_thread_timer_suspend ();
extern int __collector_ext_dispatcher_thread_timer_resume ();
extern int __collector_ext_dispatcher_install ();
extern void __collector_ext_dispatcher_suspend ();
extern void __collector_ext_dispatcher_restart ();
extern void __collector_ext_dispatcher_deinstall ();
extern void __collector_ext_usage_sample (Smpl_type type, char *name);
extern void __collector_ext_profile_handler (siginfo_t *, ucontext_t *);
extern int __collector_ext_clone_pthread (int (*fn)(void *), void *child_stack, int flags, void *arg,
va_list va /* pid_t *ptid, struct user_desc *tlspid_t *" ctid" */);
/* D-light related functions */
extern int __collector_sigprof_install ();
extern int __collector_ext_hwc_active ();
extern void __collector_ext_hwc_check (siginfo_t *, ucontext_t *);
extern int __collector_ext_hwc_lwp_init ();
extern void __collector_ext_hwc_lwp_fini ();
extern int __collector_ext_hwc_lwp_suspend ();
extern int __collector_ext_hwc_lwp_resume ();
extern int (*__collector_VM_ReadByteInstruction)(unsigned char *);
extern int (*__collector_omp_stack_trace)(char*, int, hrtime_t, void*);
extern hrtime_t (*__collector_gethrtime)();
extern int (*__collector_mpi_stack_trace)(char*, int, hrtime_t);
extern int __collector_open_experiment (const char *exp, const char *par, sp_origin_t origin);
extern void __collector_suspend_experiment (char *why);
extern void __collector_resume_experiment ();
extern void __collector_clean_state ();
extern void __collector_close_experiment ();
extern void __collector_terminate_expt ();
extern void __collector_terminate_hook ();
extern void __collector_sample (char *name);
extern void __collector_pause ();
extern void __collector_pause_m ();
extern void __collector_resume ();
extern int collector_sigemt_sigaction (const struct sigaction*,
struct sigaction*);
extern int collector_sigchld_sigaction (const struct sigaction*,
struct sigaction*);
extern int
__collector_log_write (char *format, ...) __attribute__ ((format (printf, 1, 2)));
/* ------- internal global data ----------------- */
/* These will not be exported from libcollector.so */
extern struct Heap *__collector_heap;
/* experiment state flag */
typedef enum
{
EXP_INIT, EXP_OPEN, EXP_PAUSED, EXP_CLOSED
} sp_state_t;
extern volatile sp_state_t __collector_expstate;
/* global flag, defines whether target is threaded or not
* if set, put _lwp_self() for thread id instead of thr_self()
* in output packets; should be set before any data packets
* are written, i.e., before signal handlers are installed.
*/
extern int __collector_no_threads;
extern int __collector_libthread_T1; /* T1 or not T1 */
extern int __collector_sample_sig; /* set to signal used to trigger a sample */
extern int __collector_sample_sig_warn; /* if 1, warning given on target use */
extern int __collector_pause_sig; /* set to signal used to toggle pause-resume */
extern int __collector_pause_sig_warn; /* if 1, warning given on target use */
extern hrtime_t __collector_delay_start;
extern int __collector_exp_active;
/* global hrtime_t for next periodic sample */
extern hrtime_t __collector_next_sample;
extern int __collector_sample_period;
/* global hrtime_t for experiment termination (-t) */
extern hrtime_t __collector_terminate_time;
extern int __collector_terminate_duration;
extern char __collector_exp_dir_name[];
extern int __collector_java_mode;
extern int __collector_java_asyncgetcalltrace_loaded;
extern int __collector_jprofile_start_attach ();
/* --------- information controlling debug tracing ------------- */
/* global flag, defines level of trace information */
extern void __collector_dlog (int, int, char *, ...) __attribute__ ((format (printf, 3, 4)));
#define STR(x) ((x) ? (x) : "NULL")
// To set collector_debug_opt use:
// SP_COLLECTOR_DEBUG=4 ; export SP_COLLECTOR_DEBUG ; collect ...
enum
{
SP_DUMP_TIME = 1,
SP_DUMP_FLAG = 2,
SP_DUMP_JAVA = 4,
SP_DUMP_NOHEADER = 8,
SP_DUMP_UNWIND = 16,
SP_DUMP_STACK = 32,
};
#ifndef DEBUG
#define DprintfT(flag, ...)
#define tprintf(...)
#define Tprintf(...)
#define TprintfT(...)
#else
#define DprintfT(flag, ...) __collector_dlog(SP_DUMP_FLAG | (flag), 0, __VA_ARGS__ )
#define tprintf(...) __collector_dlog( SP_DUMP_NOHEADER, __VA_ARGS__ )
#define Tprintf(...) __collector_dlog( 0, __VA_ARGS__ )
#define TprintfT(...) __collector_dlog( SP_DUMP_TIME, __VA_ARGS__ )
#endif /* DEBUG */
// To find the glibc version:
// objdump -T /lib*/*so /lib*/*/*.so | grep popen
// IMPORTANT: The GLIBC_* versions below must match those in mapfile.<variant>
#if ARCH(Aarch64)
#define SYS_LIBC_NAME "libc.so.6"
#define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.17"
#define SYS_DLOPEN_VERSION "GLIBC_2.17"
#define SYS_POPEN_VERSION "GLIBC_2.17"
#define SYS_FOPEN_X_VERSION "GLIBC_2.17"
#define SYS_FGETPOS_X_VERSION "GLIBC_2.17"
#elif ARCH(Intel)
#define SYS_LIBC_NAME "libc.so.6"
#define SYS_POSIX_SPAWN_VERSION "GLIBC_2.15"
#if WSIZE(32)
#define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.1"
#define SYS_DLOPEN_VERSION "GLIBC_2.1"
#define SYS_POPEN_VERSION "GLIBC_2.1"
#define SYS_TIMER_X_VERSION "GLIBC_2.2"
#define SYS_FOPEN_X_VERSION "GLIBC_2.1"
#define SYS_FGETPOS_X_VERSION "GLIBC_2.2"
#define SYS_FGETPOS64_X_VERSION "GLIBC_2.2"
#define SYS_OPEN64_X_VERSION "GLIBC_2.2"
#define SYS_PREAD_X_VERSION "GLIBC_2.2"
#define SYS_PWRITE_X_VERSION "GLIBC_2.2"
#define SYS_PWRITE64_X_VERSION "GLIBC_2.2"
#else /* WSIZE(64) */
#define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.2.5"
#define SYS_DLOPEN_VERSION "GLIBC_2.2.5"
#define SYS_POPEN_VERSION "GLIBC_2.2.5"
#define SYS_TIMER_X_VERSION "GLIBC_2.3.3"
#define SYS_FOPEN_X_VERSION "GLIBC_2.2.5"
#define SYS_FGETPOS_X_VERSION "GLIBC_2.2.5"
#endif
#elif ARCH(SPARC)
#define SYS_LIBC_NAME "libc.so.6"
#define SYS_DLOPEN_VERSION "GLIBC_2.1"
#if WSIZE(32)
#define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.1"
#define SYS_POPEN_VERSION "GLIBC_2.1"
#define SYS_FOPEN_X_VERSION "GLIBC_2.1"
#define SYS_FGETPOS_X_VERSION "GLIBC_2.2"
#else /* WSIZE(64) */
#define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.2"
#define SYS_POPEN_VERSION "GLIBC_2.2"
#define SYS_TIMER_X_VERSION "GLIBC_2.3.3"
#define SYS_FOPEN_X_VERSION "GLIBC_2.2"
#define SYS_FGETPOS_X_VERSION "GLIBC_2.2"
#endif
#endif
#endif

View file

@ -0,0 +1,140 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/* C and Fortran stubs for collector API */
#include "config.h"
#include <dlfcn.h>
#include "gp-defs.h"
#include "collectorAPI.h"
#include "gp-experiment.h"
static void *__real_collector_sample = NULL;
static void *__real_collector_pause = NULL;
static void *__real_collector_resume = NULL;
static void *__real_collector_terminate_expt = NULL;
static void *__real_collector_func_load = NULL;
static void *__real_collector_func_unload = NULL;
#define INIT_API if (init_API == 0) collectorAPI_initAPI()
#define NULL_PTR(x) (__real_##x == NULL)
#define CALL_REAL(x) (*(void(*)())__real_##x)
#define CALL_IF_REAL(x) INIT_API; if (!NULL_PTR(x)) CALL_REAL(x)
static int init_API = 0;
void
collectorAPI_initAPI (void)
{
void *libcollector = dlopen (SP_LIBCOLLECTOR_NAME, RTLD_NOLOAD);
if (libcollector == NULL)
libcollector = RTLD_DEFAULT;
__real_collector_sample = dlsym (libcollector, "__collector_sample");
__real_collector_pause = dlsym (libcollector, "__collector_pause");
__real_collector_resume = dlsym (libcollector, "__collector_resume");
__real_collector_terminate_expt = dlsym (libcollector, "__collector_terminate_expt");
__real_collector_func_load = dlsym (libcollector, "__collector_func_load");
__real_collector_func_unload = dlsym (libcollector, "__collector_func_unload");
init_API = 1;
}
/* initialization -- init section routine */
static void collectorAPI_init () __attribute__ ((constructor));
static void
collectorAPI_init (void)
{
collectorAPI_initAPI ();
}
/* C API */
void
collector_pause (void)
{
CALL_IF_REAL (collector_pause)();
}
void
collector_resume (void)
{
CALL_IF_REAL (collector_resume)();
}
void
collector_sample (const char *name)
{
CALL_IF_REAL (collector_sample)(name);
}
void
collector_terminate_expt (void)
{
CALL_IF_REAL (collector_terminate_expt)();
}
void
collector_func_load (const char *name, const char *alias, const char *sourcename,
void *vaddr, int size, int lntsize, Lineno *lntable)
{
CALL_IF_REAL (collector_func_load)(name, alias, sourcename,
vaddr, size, lntsize, lntable);
}
void
collector_func_unload (void *vaddr)
{
CALL_IF_REAL (collector_func_unload)(vaddr);
}
/* Fortran API */
void
collector_pause_ (void)
{
CALL_IF_REAL (collector_pause)();
}
void
collector_resume_ (void)
{
CALL_IF_REAL (collector_resume)();
}
void
collector_terminate_expt_ (void)
{
CALL_IF_REAL (collector_terminate_expt)();
}
void
collector_sample_ (char *name, long name_length)
{
INIT_API;
if (!NULL_PTR (collector_sample))
{
char name_string[256];
long length = sizeof (name_string) - 1;
if (name_length < length)
length = name_length;
for (long i = 0; i < length; i++)
name_string[i] = name[i];
name_string[length] = '\0';
CALL_REAL (collector_sample)(name_string);
}
}

18081
gprofng/libcollector/configure vendored Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,60 @@
dnl Process this file with autoconf to produce a configure script.
dnl
dnl Copyright (C) 2021 Free Software Foundation, Inc.
dnl
dnl This file is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 3 of the License, or
dnl (at your option) any later version.
dnl
dnl This program is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program; see the file COPYING3. If not see
dnl <http://www.gnu.org/licenses/>.
m4_include([../../bfd/version.m4])
AC_INIT([gprofng], BFD_VERSION)
AC_CONFIG_MACRO_DIRS([../../config ../..])
AC_CONFIG_AUX_DIR(../..)
AM_INIT_AUTOMAKE
AM_MAINTAINER_MODE
AC_CONFIG_SRCDIR(libcol_util.c)
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_PROG_RANLIB
AM_PROG_AR
LT_INIT
AC_ENABLE_SHARED
AC_DISABLE_STATIC
if test "$enable_shared" != "yes"; then
AC_MSG_ERROR([Cannot set --enable-shared for gprofng/libcollector.])
fi
GPROFNG_VARIANT=unknown
case "${target}" in
x86_64-*-linux*)
GPROFNG_VARIANT=amd64-Linux
;;
i?86-*-linux*)
GPROFNG_VARIANT=intel-Linux
;;
aarch64-*-linux*)
GPROFNG_VARIANT=aarch64-Linux
;;
esac
AC_SUBST(GPROFNG_VARIANT)
AC_CONFIG_FILES([Makefile])
AC_CONFIG_HEADERS([lib-config.h:../common/config.h.in])
AC_OUTPUT

View file

@ -0,0 +1,81 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/* Lineage events for process fork, exec, etc. */
#ifndef DESCENDANTS_H
#define DESCENDANTS_H
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <alloca.h>
#include <assert.h>
#include "gp-defs.h"
#include "gp-experiment.h"
#include "collector.h"
#include "memmgr.h"
#include "cc_libcollector.h"
#include "tsd.h"
/* configuration, not changed after init. */
typedef enum
{
LM_DORMANT = -2, /* env vars preserved, not recording */
LM_CLOSED = -1, /* env vars cleared, not recording */
LM_TRACK_LINEAGE = 1, /* env vars preserved, recording */
} line_mode_t;
extern line_mode_t line_mode;
extern int user_follow_mode;
extern int java_mode;
extern int dbg_current_mode; /* for debug only */
extern unsigned line_key;
extern char **sp_env_backup;
#define INIT_REENTRANCE(x) ((x) = __collector_tsd_get_by_key (line_key))
#define CHCK_REENTRANCE(x) (((INIT_REENTRANCE(x)) == NULL) || (*(x) != 0))
#define PUSH_REENTRANCE(x) ((*(x))++)
#define POP_REENTRANCE(x) ((*(x))--)
/* environment variables that must be forwarded to descendents */
#define SP_COLLECTOR_PARAMS "SP_COLLECTOR_PARAMS"
#define SP_COLLECTOR_EXPNAME "SP_COLLECTOR_EXPNAME"
#define SP_COLLECTOR_FOLLOW_SPEC "SP_COLLECTOR_FOLLOW_SPEC"
#define SP_COLLECTOR_FOUNDER "SP_COLLECTOR_FOUNDER"
#define SP_PRELOAD_STRINGS "SP_COLLECTOR_PRELOAD"
#define LD_PRELOAD_STRINGS "LD_PRELOAD"
#define SP_LIBPATH_STRINGS "SP_COLLECTOR_LIBRARY_PATH"
#define LD_LIBPATH_STRINGS "LD_LIBRARY_PATH"
#define JAVA_TOOL_OPTIONS "JAVA_TOOL_OPTIONS"
#define COLLECTOR_JVMTI_OPTION "-agentlib:gp-collector"
extern int __collector_linetrace_shutdown_hwcs_6830763_XXXX;
extern void __collector_env_unset (char *envp[]);
extern void __collector_env_save_preloads ();
extern char ** __collector_env_backup ();
extern void __collector_env_backup_free ();
extern void __collector_env_update (char *envp[]);
extern void __collector_env_print (char *label);
extern void __collector_env_printall (char *label, char *envp[]);
extern char ** __collector_env_allocate (char *const old_env[], int allocate_env);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,840 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/*
* Routines for managing the target's environment array
*/
#include "config.h"
#include "descendants.h"
#define MAX_LD_PRELOADS 2
/* TprintfT(<level>,...) definitions. Adjust per module as needed */
#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
#define DBG_LT1 1 // for configuration details, warnings
#define DBG_LT2 2
#define DBG_LT3 3
#define DBG_LT4 4
/* original environment settings to be saved for later restoration */
static char *sp_preloads[MAX_LD_PRELOADS];
static char *sp_libpaths[MAX_LD_PRELOADS];
char **sp_env_backup;
static const char *SP_ENV[];
static const char *LD_ENV[];
static const char *SP_PRELOAD[];
static const char *LD_PRELOAD[];
static const char *SP_LIBRARY_PATH[];
static const char *LD_LIBRARY_PATH[];
static int NUM_SP_ENV_VARS;
static int NUM_LD_ENV_VARS;
static int NUM_SP_PRELOADS;
static int NUM_LD_PRELOADS;
static int NUM_SP_LIBPATHS;
static int NUM_LD_LIBPATHS;
static const char *SP_ENV[] = {
SP_COLLECTOR_PARAMS, /* data descriptor */
SP_COLLECTOR_EXPNAME, /* experiment name */
SP_COLLECTOR_FOLLOW_SPEC, /* linetrace */
SP_COLLECTOR_FOUNDER, /* determine founder exp */
SP_PRELOAD_STRINGS, /* LD_PRELOADs for data collection */
SP_LIBPATH_STRINGS, /* LD_LIBRARY_PATHs for data collection */
"SP_COLLECTOR_TRACELEVEL", /* tprintf */
#if DEBUG
"SP_COLLECTOR_SIGACTION", /* dispatcher, hwprofile */
#endif
/* JAVA* */
/* LD_DEBUG=audit,bindings,detail */
/* LD_ORIGIN=yes */
NULL
};
static const char *LD_ENV[] = {
LD_PRELOAD_STRINGS, /* LD_PRELOADs */
LD_LIBPATH_STRINGS, /* LD_LIBRARY_PATHs */
JAVA_TOOL_OPTIONS, /* enable -agentlib:collector for JVMTI */
NULL
};
static const char *SP_PRELOAD[] = {
SP_PRELOAD_STRINGS,
NULL
};
static const char *LD_PRELOAD[] = {
LD_PRELOAD_STRINGS,
NULL
};
static const char *SP_LIBRARY_PATH[] = {
SP_LIBPATH_STRINGS,
NULL
};
static const char *LD_LIBRARY_PATH[] = {
LD_LIBPATH_STRINGS,
NULL
};
void
__collector_env_save_preloads ()
{
/* save the list of SP_PRELOADs */
int v;
for (v = 0; SP_PRELOAD[v]; v++)
{
sp_preloads[v] = __collector_strdup (CALL_UTIL (getenv)(SP_PRELOAD[v]));
TprintfT (DBG_LT3, "__collector_env_save_preloads: %s=%s\n", SP_PRELOAD[v], sp_preloads[v]);
}
NUM_SP_PRELOADS = v;
for (v = 0; SP_LIBRARY_PATH[v]; v++)
{
sp_libpaths[v] = __collector_strdup (CALL_UTIL (getenv)(SP_LIBRARY_PATH[v]));
TprintfT (DBG_LT4, "__collector_env_save_preloads: %s=%s\n", SP_LIBRARY_PATH[v],
sp_libpaths[v] ? sp_libpaths[v] : "NULL");
}
NUM_SP_LIBPATHS = v;
for (v = 0; LD_PRELOAD[v]; v++)
;
NUM_LD_PRELOADS = v;
for (v = 0; LD_LIBRARY_PATH[v]; v++)
;
NUM_LD_LIBPATHS = v;
for (v = 0; SP_ENV[v]; v++)
;
NUM_SP_ENV_VARS = v;
for (v = 0; LD_ENV[v]; v++)
;
NUM_LD_ENV_VARS = v;
}
/* free the memory involved in backing up the environment */
void
__collector_env_backup_free ()
{
int v = 0;
TprintfT (DBG_LT2, "env_backup_free()\n");
for (v = 0; sp_env_backup[v]; v++)
{
TprintfT (DBG_LT2, "env_backup_free():sp_env_backup[%d]=%s \n", v, sp_env_backup[v]);
__collector_freeCSize (__collector_heap, (char *) sp_env_backup[v], __collector_strlen (sp_env_backup[v]) + 1);
}
__collector_freeCSize (__collector_heap, (char**) sp_env_backup,
(NUM_SP_ENV_VARS + NUM_LD_ENV_VARS + 1) * sizeof (char*));
}
char **
__collector_env_backup ()
{
TprintfT (DBG_LT2, "env_backup_()\n");
char **backup = __collector_env_allocate (NULL, 1);
__collector_env_update (backup);
TprintfT (DBG_LT2, "env_backup_()\n");
return backup;
}
/*
function: env_prepend()
given an <old_str>, check to see if <str>
is already defined by it. If not, allocate
a new string and concat <envvar>=<str><separator><old_str>
params:
old_str: original string
str: substring to prepend
return: pointer to updated string or NULL if string was not updated.
*/
static char *
env_prepend (const char *envvar, const char *str, const char *separator,
const char *old_str)
{
if (!envvar || *envvar == 0 || !str || *str == 0)
{
/* nothing to do */
TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\") -- nothing to do\n",
envvar, str, separator, old_str);
return NULL;
}
TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\")\n",
envvar, str, separator, old_str);
char *ev;
size_t strsz;
if (!old_str || *old_str == 0)
{
strsz = __collector_strlen (envvar) + 1 + __collector_strlen (str) + 1;
ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1);
if (ev)
{
CALL_UTIL (snprintf)(ev, strsz, "%s=%s", envvar, str);
assert (__collector_strlen (ev) + 1 == strsz);
}
else
TprintfT (DBG_LT2, "env_prepend(): could not allocate memory\n");
}
else
{
char *p = CALL_UTIL (strstr)(old_str, str);
if (p)
{
TprintfT (DBG_LT2, "env_prepend(): %s=%s was already set\n",
envvar, old_str);
return NULL;
}
strsz = __collector_strlen (envvar) + 1 + __collector_strlen (str) +
__collector_strlen (separator) + __collector_strlen (old_str) + 1;
ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1);
if (ev)
{
CALL_UTIL (snprintf)(ev, strsz, "%s=%s%s%s", envvar, str, separator, old_str);
assert (__collector_strlen (ev) + 1 == strsz);
}
else
TprintfT (DBG_LT2, "env_prepend(): could not allocate memory\n");
}
TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\") returns \"%s\"\n",
envvar, str, separator, old_str, (ev == NULL ? "NULL" : ev));
return ev;
}
/*
function: putenv_prepend()
get environment variable <envvar>, check to see if <str>
is already defined by it. If not prepend <str>
and put it back to environment.
params:
envvar: environment variable
str: substring to find
return: 0==success, nonzero on failure.
*/
int
putenv_prepend (const char *envvar, const char *str, const char *separator)
{
if (!envvar || *envvar == 0)
return 1;
const char * old_str = CALL_UTIL (getenv)(envvar);
char * newstr = env_prepend (envvar, str, separator, old_str);
if (newstr)
// now put the new variable into the environment
if (CALL_UTIL (putenv)(newstr) != 0)
{
TprintfT (DBG_LT2, "putenv_prepend(): ERROR %s is not set!\n", newstr);
return 1;
}
return 0;
}
/*
function: env_strip()
Finds substr in origstr; Removes
all characters from previous ':' or ' '
up to and including any trailing ':' or ' '.
params:
env: environment variable contents
str: substring to find
return: count of instances removed from env
*/
static int
env_strip (char *origstr, const char *substr)
{
int removed = 0;
char *p, *q;
if (origstr == NULL || substr == NULL || *substr == 0)
return 0;
while ((p = q = CALL_UTIL (strstr)(origstr, substr)))
{
p += __collector_strlen (substr);
while (*p == ':' || *p == ' ') /* strip trailing separator */
p++;
while (*q != ':' && *q != ' ' && *q != '=' && q != origstr) /* strip path */
q--;
if (q != origstr) /* restore leading separator (if any) */
q++;
__collector_strlcpy (q, p, __collector_strlen (p) + 1);
removed++;
}
return removed;
}
/*
function: env_ld_preload_strip()
Removes known libcollector shared objects from envv.
params:
var: shared object name (leading characters don't have to match)
return: 0 = so's removed, non-zero = so's not found.
*/
static int
env_ld_preload_strip (char *envv)
{
if (!envv || *envv == 0)
{
TprintfT (DBG_LT2, "env_ld_preload_strip(): WARNING - envv is NULL\n");
return -1;
}
for (int v = 0; SP_PRELOAD[v]; v++)
if (env_strip (envv, sp_preloads[v]))
return 0;
if (line_mode != LM_CLOSED)
TprintfT (DBG_LT2, "env_ld_preload_strip(): WARNING - could not strip SP_PRELOADS from '%s'\n",
envv);
return -2;
}
void
__collector_env_print (char * label)
{
#if DEBUG
TprintfT (DBG_LT2, "__collector_env_print(%s)\n", label);
for (int v = 0; v < MAX_LD_PRELOADS; v++)
TprintfT (DBG_LT2, " %s sp_preloads[%d] (0x%p)=%s\n", label,
v, sp_preloads[v], (sp_preloads[v] == NULL ? "NULL" : sp_preloads[v]));
for (int v = 0; SP_ENV[v]; v++)
{
char *s = CALL_UTIL (getenv)(SP_ENV[v]);
if (s == NULL)
s = "<null>";
TprintfT (DBG_LT2, " %s SP_ENV[%d] (0x%p): %s=\"%s\"\n", label, v, SP_ENV[v], SP_ENV[v], s);
}
for (int v = 0; LD_ENV[v]; v++)
{
char *s = CALL_UTIL (getenv)(LD_ENV[v]);
if (s == NULL)
s = "<null>";
TprintfT (DBG_LT2, " %s LD_ENV[%d] (0x%p): %s=\"%s\"\n", label, v, LD_ENV[v], LD_ENV[v], s);
}
#endif
}
void
__collector_env_printall (char *label, char *envp[])
{
#if DEBUG
TprintfT (DBG_LT2, "__collector_env_printall(%s): environment @ 0x%p\n", label, envp);
for (int i = 0; envp[i]; i++)
Tprintf (DBG_LT2, "\tenv[%d]@0x%p == %s\n", i, envp[i], envp[i]);
#endif
}
/* match collector environment variable */
int
env_match (char *envp[], const char *envvar)
{
int match = -1;
if (envp == NULL)
TprintfT (DBG_LT1, "env_match(%s): NULL envp!\n", envvar);
else
{
int i = 0;
while ((envp[i] != NULL) && (__collector_strStartWith (envp[i], envvar)))
i++;
if ((envp[i] == NULL) || (envp[i][__collector_strlen (envvar)] != '='))
TprintfT (DBG_LT4, "env_match(): @%p []%s not defined in envp\n", envp, envvar);
else
{
TprintfT (DBG_LT4, "env_match(): @%p [%d]%s defined in envp\n", envp, i, envp[i]);
match = i;
}
}
TprintfT (DBG_LT1, "env_match(%s): found in slot %d\n", envvar, match);
return (match);
}
/* allocate new environment with collector variables */
/* 1) copy all current envp[] ptrs into a new array, coll_env[] */
/* 2) if collector-related env ptrs not in envp[], append them to coll_env */
/* from processes' "environ" (allocate_env==1) */
/* or from sp_env_backup (allocate_env==0)*/
/* If they already exist in envp, probably is an error... */
/* 3) return coll_env */
/* __collector__env_update() need be called after this to set LD_ENV*/
char **
__collector_env_allocate (char *const old_env[], int allocate_env)
{
extern char **environ; /* the process' actual environment */
char **new_env; /* a new environment for collection */
TprintfT (DBG_LT3, "__collector_env_allocate(old_env=0x%p %s environ=0x%p)\n",
old_env, (old_env == environ) ? "==" : "!=", environ);
/* set up a copy of the provided old_env for collector use */
int old_env_size = 0;
/* determine number of (used) slots in old_env */
if (old_env)
while (old_env[old_env_size] != NULL)
old_env_size++;
/* allocate a new vector with additional slots */
int new_env_alloc_sz = old_env_size + NUM_SP_ENV_VARS + NUM_LD_ENV_VARS + 1;
new_env = (char**) __collector_allocCSize (__collector_heap, new_env_alloc_sz * sizeof (char*), 1);
if (new_env == NULL)
return NULL;
TprintfT (DBG_LT4, "__collector_env_allocate(): old_env has %d entries, new_env @ 0x%p\n", old_env_size, new_env);
/* copy provided old_env pointers to new collector environment */
int new_env_size = 0;
for (new_env_size = 0; new_env_size < old_env_size; new_env_size++)
new_env[new_env_size] = old_env[new_env_size];
/* check each required environment variable, adding as required */
const char * env_var;
int v;
for (v = 0; (env_var = SP_ENV[v]) != NULL; v++)
{
if (env_match ((char**) old_env, env_var) == -1)
{
int idx;
/* not found in old_env */
if (allocate_env)
{
if ((idx = env_match (environ, env_var)) != -1)
{
/* found in environ */
TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
new_env_size, environ[idx]);
int varsz = __collector_strlen (environ[idx]) + 1;
char * var = (char*) __collector_allocCSize (__collector_heap, varsz, 1);
if (var == NULL)
return NULL;
__collector_strlcpy (var, environ[idx], varsz);
new_env[new_env_size++] = var;
}
else
{
/* not found in environ */
if ((__collector_strcmp (env_var, SP_COLLECTOR_PARAMS) == 0) ||
(__collector_strcmp (env_var, SP_COLLECTOR_EXPNAME) == 0))
TprintfT (DBG_LT1, "__collector_env_allocate(): note: %s environment variable not found\n",
env_var);
}
}
else
{
if ((idx = env_match (sp_env_backup, env_var)) != -1)
{
/* found in backup */
TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
new_env_size, sp_env_backup[idx]);
new_env[new_env_size++] = sp_env_backup[idx];
}
else
{
/* not found in environ */
if ((__collector_strcmp (env_var, SP_COLLECTOR_PARAMS) == 0) ||
(__collector_strcmp (env_var, SP_COLLECTOR_EXPNAME) == 0))
TprintfT (DBG_LT1, "__collector_env_allocate(): note: %s environment variable not found\n",
env_var);
}
}
}
}
for (v = 0; (env_var = LD_ENV[v]) != NULL; v++)
{
if (env_match ((char**) old_env, env_var) == -1)
{
int idx;
/* not found in old_env */
if (allocate_env)
{
if ((idx = env_match (environ, env_var)) != -1)
{
/* found in environ */
TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
new_env_size, environ[idx]);
int varsz = __collector_strlen (env_var) + 2;
char * var = (char*) __collector_allocCSize (__collector_heap, varsz, 1);
if (var == NULL)
return NULL;
// assume __collector_env_update() will fill content of env_var
CALL_UTIL (snprintf)(var, varsz, "%s=", env_var);
new_env[new_env_size++] = var;
}
}
else
{
if ((idx = env_match (sp_env_backup, env_var)) != -1)
{
/* found in backup */
TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
new_env_size, sp_env_backup[idx]);
new_env[new_env_size++] = sp_env_backup[idx];
}
}
}
}
/* ensure new_env vector ends with NULL */
new_env[new_env_size] = NULL;
assert (new_env_size <= new_env_alloc_sz);
TprintfT (DBG_LT4, "__collector_env_allocate(): new_env has %d entries (%d added), new_env=0x%p\n",
new_env_size, new_env_size - old_env_size, new_env);
if (new_env_size != old_env_size && !allocate_env)
__collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
SP_JCMD_CWARN, COL_WARN_EXECENV, new_env_size - old_env_size);
__collector_env_printall ("__collector_env_allocate", new_env);
return (new_env);
}
/* unset collection environment variables */
/* if they exist in env... */
/* 1) push non-collectorized version to env */
/* Not mt safe */
void
__collector_env_unset (char *envp[])
{
int v;
const char * env_name;
TprintfT (DBG_LT3, "env_unset(envp=0x%p)\n", envp);
if (envp == NULL)
{
for (v = 0; (env_name = LD_PRELOAD[v]); v++)
{
const char *env_val = CALL_UTIL (getenv)(env_name);
if (env_val && CALL_UTIL (strstr)(env_val, sp_preloads[v]))
{
size_t sz = __collector_strlen (env_name) + 1 + __collector_strlen (env_val) + 1;
char * ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
if (ev == NULL)
return;
CALL_UTIL (snprintf)(ev, sz, "%s=%s", env_name, env_val);
assert (__collector_strlen (ev) + 1 == sz);
TprintfT (DBG_LT4, "env_unset(): old %s\n", ev);
env_ld_preload_strip (ev);
CALL_UTIL (putenv)(ev);
TprintfT (DBG_LT4, "env_unset(): new %s\n", ev);
}
}
// unset JAVA_TOOL_OPTIONS
env_name = JAVA_TOOL_OPTIONS;
const char * env_val = CALL_UTIL (getenv)(env_name);
if (env_val && CALL_UTIL (strstr)(env_val, COLLECTOR_JVMTI_OPTION))
{
size_t sz = __collector_strlen (env_name) + 1 + __collector_strlen (env_val) + 1;
char * ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
if (ev == NULL)
return;
CALL_UTIL (snprintf)(ev, sz, "%s=%s", env_name, env_val);
assert (__collector_strlen (ev) + 1 == sz);
TprintfT (DBG_LT4, "env_unset(): old %s\n", ev);
env_strip (ev, COLLECTOR_JVMTI_OPTION);
CALL_UTIL (putenv)(ev);
TprintfT (DBG_LT4, "env_unset(): new %s\n", ev);
}
__collector_env_print ("__collector_env_unset");
}
else
{
__collector_env_printall ("__collector_env_unset, before", envp);
for (v = 0; (env_name = LD_PRELOAD[v]); v++)
{
int idx = env_match (envp, env_name);
if (idx != -1)
{
char *env_val = envp[idx];
TprintfT (DBG_LT4, "env_unset(): old %s\n", env_val);
envp[idx] = "junk="; /* xxxx is it ok to use original string? */
env_ld_preload_strip (env_val);
envp[idx] = env_val;
TprintfT (DBG_LT4, "env_unset(): new %s\n", envp[idx]);
}
}
// unset JAVA_TOOL_OPTIONS
env_name = JAVA_TOOL_OPTIONS;
int idx = env_match(envp, env_name);
if (idx != -1) {
char *env_val = envp[idx];
TprintfT(DBG_LT4, "env_unset(): old %s\n", env_val);
envp[idx] = "junk="; /* xxxx is it ok to use original string? */
env_strip(env_val, COLLECTOR_JVMTI_OPTION);
envp[idx] = env_val;
TprintfT(DBG_LT4, "env_unset(): new %s\n", envp[idx]);
}
__collector_env_printall ("__collector_env_unset, after", envp );
}
}
/* update collection environment variables */
/* update LD_PRELOADs and push them */
/* not mt safe */
void
__collector_env_update (char *envp[])
{
const char *env_name;
TprintfT (DBG_LT1, "__collector_env_update(envp=0x%p)\n", envp);
extern char **environ;
if (envp == NULL)
{
int v;
TprintfT (DBG_LT2, "__collector_env_update(envp=NULL)\n");
__collector_env_printall (" environ array, before", environ);
__collector_env_print (" env_update at entry ");
/* SP_ENV */
for (v = 0; (env_name = SP_ENV[v]) != NULL; v++)
{
if (env_match (environ, env_name) == -1)
{
int idx;
if ((idx = env_match (sp_env_backup, env_name)) != -1)
{
unsigned strsz = __collector_strlen (sp_env_backup[idx]) + 1;
char *ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1);
CALL_UTIL (snprintf)(ev, strsz, "%s", sp_env_backup[idx]);
if (CALL_UTIL (putenv)(ev) != 0)
TprintfT (DBG_LT2, "__collector_env_update(): ERROR %s is not set!\n",
sp_env_backup[idx]);
}
}
}
__collector_env_print (" env_update after SP_ENV settings ");
/* LD_LIBRARY_PATH */
for (v = 0; (env_name = LD_LIBRARY_PATH[v]); v++)
/* assumes same index used between LD and SP vars */
if (putenv_prepend (env_name, sp_libpaths[v], ":"))
TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n",
env_name, sp_libpaths[v]);
__collector_env_print (" env_update after LD_LIBRARY_PATH settings ");
/* LD_PRELOAD */
for (v = 0; (env_name = LD_PRELOAD[v]); v++)
/* assumes same index used between LD and SP vars */
if (putenv_prepend (env_name, sp_preloads[v], " "))
TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n",
env_name, sp_preloads[v]);
__collector_env_print (" env_update after LD_PRELOAD settings ");
/* JAVA_TOOL_OPTIONS */
if (java_mode)
if (putenv_prepend (JAVA_TOOL_OPTIONS, COLLECTOR_JVMTI_OPTION, " "))
TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n",
JAVA_TOOL_OPTIONS, COLLECTOR_JVMTI_OPTION);
__collector_env_print (" env_update after JAVA_TOOL settings ");
}
else
{
int v;
int idx;
TprintfT (DBG_LT2, "__collector_env_update(envp=0x%p) not NULL\n", envp);
__collector_env_printall ("__collector_env_update, before", envp);
/* LD_LIBRARY_PATH */
for (v = 0; (env_name = LD_LIBRARY_PATH[v]); v++)
{
int idx = env_match (envp, env_name);
if (idx != -1)
{
char *env_val = __collector_strchr (envp[idx], '=');
if (env_val)
env_val++; /* skip '=' */
/* assumes same index used between LD and SP vars */
char *new_str = env_prepend (env_name, sp_libpaths[v],
":", env_val);
if (new_str)
envp[idx] = new_str;
}
}
/* LD_PRELOAD */
for (v = 0; (env_name = LD_PRELOAD[v]); v++)
{
int idx = env_match (envp, env_name);
if (idx != -1)
{
char *env_val = __collector_strchr (envp[idx], '=');
if (env_val)
env_val++; /* skip '=' */
/* assumes same index used between LD and SP vars */
char *new_str = env_prepend (env_name, sp_preloads[v],
" ", env_val);
if (new_str)
envp[idx] = new_str;
}
}
/* JAVA_TOOL_OPTIONS */
if (java_mode)
{
env_name = JAVA_TOOL_OPTIONS;
idx = env_match (envp, env_name);
if (idx != -1)
{
char *env_val = __collector_strchr (envp[idx], '=');
if (env_val)
env_val++; /* skip '=' */
char *new_str = env_prepend (env_name, COLLECTOR_JVMTI_OPTION,
" ", env_val);
if (new_str)
envp[idx] = new_str;
}
}
}
__collector_env_printall ("__collector_env_update, after", environ);
}
/*------------------------------------------------------------- putenv */
int putenv () __attribute__ ((weak, alias ("__collector_putenv")));
int _putenv () __attribute__ ((weak, alias ("__collector_putenv")));
int
__collector_putenv (char * string)
{
if (CALL_UTIL (putenv) == __collector_putenv ||
CALL_UTIL (putenv) == NULL)
{ // __collector_libc_funcs_init failed
CALL_UTIL (putenv) = (int(*)())dlsym (RTLD_NEXT, "putenv");
if (CALL_UTIL (putenv) == NULL || CALL_UTIL (putenv) == __collector_putenv)
CALL_UTIL (putenv) = (int(*)())dlsym (RTLD_DEFAULT, "putenv");
if (CALL_UTIL (putenv) == NULL || CALL_UTIL (putenv) == __collector_putenv)
{
TprintfT (DBG_LT2, "__collector_putenv(): ERROR: no pointer found.\n");
errno = EBUSY;
return -1;
}
}
if (user_follow_mode == FOLLOW_NONE)
return CALL_UTIL (putenv)(string);
char * envp[] = {string, NULL};
__collector_env_update (envp);
return CALL_UTIL (putenv)(envp[0]);
}
/*------------------------------------------------------------- setenv */
int setenv () __attribute__ ((weak, alias ("__collector_setenv")));
int _setenv () __attribute__ ((weak, alias ("__collector_setenv")));
int
__collector_setenv (const char *name, const char *value, int overwrite)
{
if (CALL_UTIL (setenv) == __collector_setenv ||
CALL_UTIL (setenv) == NULL)
{ // __collector_libc_funcs_init failed
CALL_UTIL (setenv) = (int(*)())dlsym (RTLD_NEXT, "setenv");
if (CALL_UTIL (setenv) == NULL || CALL_UTIL (setenv) == __collector_setenv)
CALL_UTIL (setenv) = (int(*)())dlsym (RTLD_DEFAULT, "setenv");
if (CALL_UTIL (setenv) == NULL || CALL_UTIL (setenv) == __collector_setenv)
{
TprintfT (DBG_LT2, "__collector_setenv(): ERROR: no pointer found.\n");
errno = EBUSY;
return -1;
}
}
if (user_follow_mode == FOLLOW_NONE || !overwrite)
return CALL_UTIL (setenv)(name, value, overwrite);
size_t sz = __collector_strlen (name) + 1 + __collector_strlen (value) + 1;
char *ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
if (ev == NULL)
return CALL_UTIL (setenv)(name, value, overwrite);
CALL_UTIL (snprintf)(ev, sz, "%s=%s", name, value);
char * envp[] = {ev, NULL};
__collector_env_update (envp);
if (envp[0] == ev)
{
__collector_freeCSize (__collector_heap, ev, sz);
return CALL_UTIL (setenv)(name, value, overwrite);
}
else
{
char *env_val = __collector_strchr (envp[0], '=');
if (env_val)
{
*env_val = '\0';
env_val++; /* skip '=' */
}
return CALL_UTIL (setenv)(envp[0], env_val, overwrite);
}
}
/*------------------------------------------------------------- unsetenv */
int unsetenv () __attribute__ ((weak, alias ("__collector_unsetenv")));
int _unsetenv () __attribute__ ((weak, alias ("__collector_unsetenv")));
int
__collector_unsetenv (const char *name)
{
if (CALL_UTIL (unsetenv) == __collector_unsetenv ||
CALL_UTIL (unsetenv) == NULL)
{ // __collector_libc_funcs_init failed
CALL_UTIL (unsetenv) = (int(*)())dlsym (RTLD_NEXT, "unsetenv");
if (CALL_UTIL (unsetenv) == NULL || CALL_UTIL (unsetenv) == __collector_unsetenv)
CALL_UTIL (unsetenv) = (int(*)())dlsym (RTLD_DEFAULT, "unsetenv");
if (CALL_UTIL (unsetenv) == NULL || CALL_UTIL (unsetenv) == __collector_unsetenv)
{
TprintfT (DBG_LT2, "__collector_unsetenv(): ERROR: no pointer found.\n");
errno = EBUSY;
return -1;
}
}
int ret = CALL_UTIL (unsetenv)(name);
if (user_follow_mode == FOLLOW_NONE)
return ret;
TprintfT (DBG_LT2, "__collector_unsetenv(): %d.\n", user_follow_mode);
size_t sz = __collector_strlen (name) + 1 + 1;
char *ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
if (ev == NULL)
return ret;
CALL_UTIL (snprintf)(ev, sz, "%s=", name);
char * envp[] = {ev, NULL};
__collector_env_update (envp);
if (envp[0] == ev)
__collector_freeCSize (__collector_heap, ev, sz);
else
CALL_UTIL (putenv)(envp[0]);
return ret;
}
/*------------------------------------------------------------- clearenv */
int clearenv () __attribute__ ((weak, alias ("__collector_clearenv")));
int
__collector_clearenv (void)
{
if (CALL_UTIL (clearenv) == __collector_clearenv || CALL_UTIL (clearenv) == NULL)
{
/* __collector_libc_funcs_init failed; look up clearenv now */
CALL_UTIL (clearenv) = (int(*)())dlsym (RTLD_NEXT, "clearenv");
if (CALL_UTIL (clearenv) == NULL || CALL_UTIL (clearenv) == __collector_clearenv)
/* still not found; try again */
CALL_UTIL (clearenv) = (int(*)())dlsym (RTLD_DEFAULT, "clearenv");
if (CALL_UTIL (clearenv) == NULL || CALL_UTIL (clearenv) == __collector_clearenv)
{
/* still not found -- a fatal error */
TprintfT (DBG_LT2, "__collector_clearenv(): ERROR: %s\n", dlerror ());
CALL_UTIL (fprintf)(stderr, "__collector_clearenv(): ERROR: %s\n", dlerror ());
errno = EBUSY;
return -1;
}
}
int ret = CALL_UTIL (clearenv)();
if (user_follow_mode == FOLLOW_NONE)
return ret;
if (sp_env_backup == NULL)
{
TprintfT (DBG_LT2, "__collector_clearenv: ERROR sp_env_backup is not set!\n");
return ret;
}
for (int v = 0; v < NUM_SP_ENV_VARS + NUM_LD_ENV_VARS; v++)
if (sp_env_backup[v] && CALL_UTIL (putenv)(sp_env_backup[v]) != 0)
TprintfT (DBG_LT2, "__collector_clearenv: ERROR %s is not set!\n",
sp_env_backup[v]);
return ret;
}

View file

@ -0,0 +1,41 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <time.h>
#include "gp-time.h"
/*
* CLOCK_MONOTONIC
* Clock that cannot be set and represents monotonic time since some
* unspecified starting point.
*/
static hrtime_t
linux_gethrtime ()
{
struct timespec tp;
hrtime_t rc = 0;
int r = clock_gettime (CLOCK_MONOTONIC_RAW, &tp);
if (r == 0)
rc = ((hrtime_t) tp.tv_sec)*1000000000 + (hrtime_t) tp.tv_nsec;
return rc;
}
hrtime_t (*__collector_gethrtime)() = linux_gethrtime;

View file

@ -0,0 +1,503 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/*
* Heap tracing events
*/
#include "config.h"
#include <dlfcn.h>
#include "gp-defs.h"
#include "collector_module.h"
#include "gp-experiment.h"
#include "data_pckts.h"
#include "tsd.h"
/* TprintfT(<level>,...) definitions. Adjust per module as needed */
#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
#define DBG_LT1 1 // for configuration details, warnings
#define DBG_LT2 2
#define DBG_LT3 3
#define DBG_LT4 4
/* define the packets to be written out */
typedef struct Heap_packet
{ /* Malloc/free tracing packet */
Common_packet comm;
Heap_type mtype; /* subtype of packet */
Size_type size; /* size of malloc/realloc request */
Vaddr_type vaddr; /* vaddr given to free or returned from malloc/realloc */
Vaddr_type ovaddr; /* Previous vaddr given to realloc */
} Heap_packet;
static int init_heap_intf ();
static int open_experiment (const char *);
static int start_data_collection (void);
static int stop_data_collection (void);
static int close_experiment (void);
static int detach_experiment (void);
static ModuleInterface module_interface = {
SP_HEAPTRACE_FILE, /* description */
NULL, /* initInterface */
open_experiment, /* openExperiment */
start_data_collection, /* startDataCollection */
stop_data_collection, /* stopDataCollection */
close_experiment, /* closeExperiment */
detach_experiment /* detachExperiment (fork child) */
};
static CollectorInterface *collector_interface = NULL;
static int heap_mode = 0;
static CollectorModule heap_hndl = COLLECTOR_MODULE_ERR;
static unsigned heap_key = COLLECTOR_TSD_INVALID_KEY;
#define CHCK_REENTRANCE(x) ( !heap_mode || ((x) = collector_interface->getKey( heap_key )) == NULL || (*(x) != 0) )
#define PUSH_REENTRANCE(x) ((*(x))++)
#define POP_REENTRANCE(x) ((*(x))--)
#define CALL_REAL(x) (__real_##x)
#define NULL_PTR(x) (__real_##x == NULL)
#define gethrtime collector_interface->getHiResTime
#ifdef DEBUG
#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
#else
#define Tprintf(...)
#define TprintfT(...)
#endif
static void *(*__real_malloc)(size_t) = NULL;
static void (*__real_free)(void *);
static void *(*__real_realloc)(void *, size_t);
static void *(*__real_memalign)(size_t, size_t);
static void *(*__real_calloc)(size_t, size_t);
static void *(*__real_valloc)(size_t);
static char *(*__real_strchr)(const char *, int);
void *__libc_malloc (size_t);
void __libc_free (void *);
void *__libc_realloc (void *, size_t);
static void
collector_memset (void *s, int c, size_t n)
{
unsigned char *s1 = s;
while (n--)
*s1++ = (unsigned char) c;
}
void
__collector_module_init (CollectorInterface *_collector_interface)
{
if (_collector_interface == NULL)
return;
collector_interface = _collector_interface;
Tprintf (0, "heaptrace: __collector_module_init\n");
heap_hndl = collector_interface->registerModule (&module_interface);
/* Initialize next module */
ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_NEXT, "__collector_module_init");
if (next_init != NULL)
next_init (_collector_interface);
return;
}
static int
open_experiment (const char *exp)
{
if (collector_interface == NULL)
{
Tprintf (0, "heaptrace: collector_interface is null.\n");
return COL_ERROR_HEAPINIT;
}
if (heap_hndl == COLLECTOR_MODULE_ERR)
{
Tprintf (0, "heaptrace: handle create failed.\n");
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n",
SP_JCMD_CERROR, COL_ERROR_HEAPINIT);
return COL_ERROR_HEAPINIT;
}
TprintfT (0, "heaptrace: open_experiment %s\n", exp);
if (NULL_PTR (malloc))
init_heap_intf ();
const char *params = collector_interface->getParams ();
while (params)
{
if ((params[0] == 'H') && (params[1] == ':'))
{
params += 2;
break;
}
params = CALL_REAL (strchr)(params, ';');
if (params)
params++;
}
if (params == NULL) /* Heap data collection not specified */
return COL_ERROR_HEAPINIT;
heap_key = collector_interface->createKey (sizeof ( int), NULL, NULL);
if (heap_key == (unsigned) - 1)
{
Tprintf (0, "heaptrace: TSD key create failed.\n");
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
SP_JCMD_CERROR, COL_ERROR_HEAPINIT);
return COL_ERROR_HEAPINIT;
}
collector_interface->writeLog ("<profile name=\"%s\">\n", SP_JCMD_HEAPTRACE);
collector_interface->writeLog (" <profdata fname=\"%s\"/>\n",
module_interface.description);
/* Record Heap_packet description */
Heap_packet *pp = NULL;
collector_interface->writeLog (" <profpckt kind=\"%d\" uname=\"Heap tracing data\">\n", HEAP_PCKT);
collector_interface->writeLog (" <field name=\"LWPID\" uname=\"Lightweight process id\" offset=\"%d\" type=\"%s\"/>\n",
&pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"THRID\" uname=\"Thread number\" offset=\"%d\" type=\"%s\"/>\n",
&pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"CPUID\" uname=\"CPU id\" offset=\"%d\" type=\"%s\"/>\n",
&pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"High resolution timestamp\" offset=\"%d\" type=\"%s\"/>\n",
&pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
&pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"HTYPE\" uname=\"Heap trace function type\" offset=\"%d\" type=\"%s\"/>\n",
&pp->mtype, sizeof (pp->mtype) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"HSIZE\" uname=\"Memory size\" offset=\"%d\" type=\"%s\"/>\n",
&pp->size, sizeof (pp->size) == 4 ? "UINT32" : "UINT64");
collector_interface->writeLog (" <field name=\"HVADDR\" uname=\"Memory address\" offset=\"%d\" type=\"%s\"/>\n",
&pp->vaddr, sizeof (pp->vaddr) == 4 ? "UINT32" : "UINT64");
collector_interface->writeLog (" <field name=\"HOVADDR\" uname=\"Previous memory address\" offset=\"%d\" type=\"%s\"/>\n",
&pp->ovaddr, sizeof (pp->ovaddr) == 4 ? "UINT32" : "UINT64");
collector_interface->writeLog (" </profpckt>\n");
collector_interface->writeLog ("</profile>\n");
return COL_ERROR_NONE;
}
static int
start_data_collection (void)
{
heap_mode = 1;
Tprintf (0, "heaptrace: start_data_collection\n");
return 0;
}
static int
stop_data_collection (void)
{
heap_mode = 0;
Tprintf (0, "heaptrace: stop_data_collection\n");
return 0;
}
static int
close_experiment (void)
{
heap_mode = 0;
heap_key = COLLECTOR_TSD_INVALID_KEY;
Tprintf (0, "heaptrace: close_experiment\n");
return 0;
}
static int
detach_experiment (void)
/* fork child. Clean up state but don't write to experiment */
{
heap_mode = 0;
heap_key = COLLECTOR_TSD_INVALID_KEY;
Tprintf (0, "heaptrace: detach_experiment\n");
return 0;
}
static int in_init_heap_intf = 0; // Flag that we are in init_heap_intf()
static int
init_heap_intf ()
{
void *dlflag;
in_init_heap_intf = 1;
__real_malloc = (void*(*)(size_t))dlsym (RTLD_NEXT, "malloc");
if (__real_malloc == NULL)
{
/* We are probably dlopened after libthread/libc,
* try to search in the previously loaded objects
*/
__real_malloc = (void*(*)(size_t))dlsym (RTLD_DEFAULT, "malloc");
if (__real_malloc == NULL)
{
Tprintf (0, "heaptrace: ERROR: real malloc not found\n");
in_init_heap_intf = 0;
return 1;
}
Tprintf (DBG_LT1, "heaptrace: real malloc found with RTLD_DEFAULT\n");
dlflag = RTLD_DEFAULT;
}
else
{
Tprintf (DBG_LT1, "heaptrace: real malloc found with RTLD_NEXT\n");
dlflag = RTLD_NEXT;
}
__real_free = (void(*)(void *))dlsym (dlflag, "free");
__real_realloc = (void*(*)(void *, size_t))dlsym (dlflag, "realloc");
__real_memalign = (void*(*)(size_t, size_t))dlsym (dlflag, "memalign");
__real_calloc = (void*(*)(size_t, size_t))dlsym (dlflag, "calloc");
__real_valloc = (void*(*)(size_t))dlsym (dlflag, "valloc");
__real_strchr = (char*(*)(const char *, int))dlsym (dlflag, "strchr");
Tprintf (0, "heaptrace: init_heap_intf done\n");
in_init_heap_intf = 0;
return 0;
}
/*------------------------------------------------------------- malloc */
void *
malloc (size_t size)
{
void *ret;
int *guard;
Heap_packet hpacket;
/* Linux startup workaround */
if (!heap_mode)
{
void *ppp = (void *) __libc_malloc (size);
Tprintf (DBG_LT4, "heaptrace: LINUX malloc(%ld, %p)...\n", (long) size, ppp);
return ppp;
}
if (NULL_PTR (malloc))
init_heap_intf ();
if (CHCK_REENTRANCE (guard))
{
ret = (void *) CALL_REAL (malloc)(size);
Tprintf (DBG_LT4, "heaptrace: real malloc(%ld) = %p\n", (long) size, ret);
return ret;
}
PUSH_REENTRANCE (guard);
ret = (void *) CALL_REAL (malloc)(size);
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
hpacket.comm.tsize = sizeof ( Heap_packet);
hpacket.comm.tstamp = gethrtime ();
hpacket.mtype = MALLOC_TRACE;
hpacket.size = (Size_type) size;
hpacket.vaddr = (Vaddr_type) ret;
hpacket.ovaddr = (Vaddr_type) 0;
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
POP_REENTRANCE (guard);
return (void *) ret;
}
/*------------------------------------------------------------- free */
void
free (void *ptr)
{
int *guard;
Heap_packet hpacket;
/* Linux startup workaround */
if (!heap_mode)
{
// Tprintf(DBG_LT4,"heaptrace: LINUX free(%p)...\n",ptr);
__libc_free (ptr);
return;
}
if (NULL_PTR (malloc))
init_heap_intf ();
if (CHCK_REENTRANCE (guard))
{
CALL_REAL (free)(ptr);
return;
}
if (ptr == NULL)
return;
PUSH_REENTRANCE (guard);
/* Get a timestamp before 'free' to enforce consistency */
hrtime_t ts = gethrtime ();
CALL_REAL (free)(ptr);
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
hpacket.comm.tsize = sizeof ( Heap_packet);
hpacket.comm.tstamp = ts;
hpacket.mtype = FREE_TRACE;
hpacket.size = (Size_type) 0;
hpacket.vaddr = (Vaddr_type) ptr;
hpacket.ovaddr = (Vaddr_type) 0;
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
POP_REENTRANCE (guard);
return;
}
/*------------------------------------------------------------- realloc */
void *
realloc (void *ptr, size_t size)
{
void *ret;
int *guard;
Heap_packet hpacket;
/* Linux startup workaround */
if (!heap_mode)
{
void * ppp = (void *) __libc_realloc (ptr, size);
Tprintf (DBG_LT4, "heaptrace: LINUX realloc(%ld, %p->%p)...\n",
(long) size, ptr, ppp);
return ppp;
}
if (NULL_PTR (realloc))
init_heap_intf ();
if (CHCK_REENTRANCE (guard))
{
ret = (void *) CALL_REAL (realloc)(ptr, size);
return ret;
}
PUSH_REENTRANCE (guard);
hrtime_t ts = gethrtime ();
ret = (void *) CALL_REAL (realloc)(ptr, size);
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
hpacket.comm.tsize = sizeof ( Heap_packet);
hpacket.comm.tstamp = ts;
hpacket.mtype = REALLOC_TRACE;
hpacket.size = (Size_type) size;
hpacket.vaddr = (Vaddr_type) ret;
hpacket.ovaddr = (Vaddr_type) ptr;
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
POP_REENTRANCE (guard);
return (void *) ret;
}
/*------------------------------------------------------------- memalign */
void *
memalign (size_t align, size_t size)
{
void *ret;
int *guard;
Heap_packet hpacket;
if (NULL_PTR (memalign))
init_heap_intf ();
if (CHCK_REENTRANCE (guard))
{
ret = (void *) CALL_REAL (memalign)(align, size);
return ret;
}
PUSH_REENTRANCE (guard);
ret = (void *) CALL_REAL (memalign)(align, size);
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
hpacket.comm.tsize = sizeof ( Heap_packet);
hpacket.comm.tstamp = gethrtime ();
hpacket.mtype = MALLOC_TRACE;
hpacket.size = (Size_type) size;
hpacket.vaddr = (Vaddr_type) ret;
hpacket.ovaddr = (Vaddr_type) 0;
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
POP_REENTRANCE (guard);
return ret;
}
/*------------------------------------------------------------- valloc */
void *
valloc (size_t size)
{
void *ret;
int *guard;
Heap_packet hpacket;
if (NULL_PTR (memalign))
init_heap_intf ();
if (CHCK_REENTRANCE (guard))
{
ret = (void *) CALL_REAL (valloc)(size);
return ret;
}
PUSH_REENTRANCE (guard);
ret = (void *) CALL_REAL (valloc)(size);
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
hpacket.comm.tsize = sizeof ( Heap_packet);
hpacket.comm.tstamp = gethrtime ();
hpacket.mtype = MALLOC_TRACE;
hpacket.size = (Size_type) size;
hpacket.vaddr = (Vaddr_type) ret;
hpacket.ovaddr = (Vaddr_type) 0;
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
POP_REENTRANCE (guard);
return ret;
}
/*------------------------------------------------------------- calloc */
void *
calloc (size_t size, size_t esize)
{
void *ret;
int *guard;
Heap_packet hpacket;
if (NULL_PTR (calloc))
{
if (in_init_heap_intf != 0)
return NULL; // Terminate infinite loop
init_heap_intf ();
}
if (CHCK_REENTRANCE (guard))
{
ret = (void *) CALL_REAL (calloc)(size, esize);
return ret;
}
PUSH_REENTRANCE (guard);
ret = (void *) CALL_REAL (calloc)(size, esize);
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
hpacket.comm.tsize = sizeof ( Heap_packet);
hpacket.comm.tstamp = gethrtime ();
hpacket.mtype = MALLOC_TRACE;
hpacket.size = (Size_type) (size * esize);
hpacket.vaddr = (Vaddr_type) ret;
hpacket.ovaddr = (Vaddr_type) 0;
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
POP_REENTRANCE (guard);
return ret;
}
/* __collector_heap_record is used to record java allocations/deallocations.
* It uses the same facilities as regular heap tracing for now.
*/
void
__collector_heap_record (int mtype, size_t size, void *vaddr)
{
int *guard;
Heap_packet hpacket;
if (CHCK_REENTRANCE (guard))
return;
PUSH_REENTRANCE (guard);
collector_memset (&hpacket, 0, sizeof ( Heap_packet));
hpacket.comm.tsize = sizeof ( Heap_packet);
hpacket.comm.tstamp = gethrtime ();
hpacket.mtype = mtype;
hpacket.size = (Size_type) size;
hpacket.vaddr = (Vaddr_type) vaddr;
hpacket.ovaddr = (Vaddr_type) 0;
hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
POP_REENTRANCE (guard);
return;
}

View file

@ -0,0 +1,905 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/* Hardware counter profiling */
#include "config.h"
#include <alloca.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/syscall.h>
#include <signal.h>
#include <ucontext.h>
#include "gp-defs.h"
#define _STRING_H 1 /* XXX MEZ: temporary workaround */
#include "hwcdrv.h"
#include "collector_module.h"
#include "gp-experiment.h"
#include "libcol_util.h"
#include "hwprofile.h"
#include "ABS.h"
#include "tsd.h"
/* TprintfT(<level>,...) definitions. Adjust per module as needed */
#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
#define DBG_LT1 1 // for configuration details, warnings
#define DBG_LT2 2
#define DBG_LT3 3
#define DBG_LT4 4
#define DBG_LT5 5
#define SD_OFF 0 /* before start or after close she shut down process */
#define SD_PENDING 1 /* before running real_detach_experiment() */
#define SD_COMPLETE 2 /* after running real_detach_experiment() */
static int init_interface (CollectorInterface*);
static int open_experiment (const char *);
static int start_data_collection (void);
static int stop_data_collection (void);
static int close_experiment (void);
static int detach_experiment (void);
static int real_detach_experiment (void);
static ModuleInterface module_interface ={
SP_HWCNTR_FILE, /* description */
init_interface, /* initInterface */
open_experiment, /* openExperiment */
start_data_collection, /* startDataCollection */
stop_data_collection, /* stopDataCollection */
close_experiment, /* closeExperiment */
detach_experiment /* detachExperiment (fork child) */
};
static CollectorInterface *collector_interface = NULL;
/*---------------------------------------------------------------------------*/
/* compile options and workarounds */
/* Solaris: We set ITIMER_REALPROF to ensure that counters get started on
* LWPs that existed before the collector initialization.
*
* In addition, if the appropriate #define's are set, we check for:
* lost-hw-overflow -- the HW counters rollover, but the overflow
* interrupt is not generated (counters keep running)
* lost-sigemt -- the interrupt is received by the kernel,
* which stops the counters, but the kernel fails
* to deliver the signal.
*/
/*---------------------------------------------------------------------------*/
/* typedefs */
typedef enum {
HWCMODE_OFF, /* before start or after close */
HWCMODE_SUSPEND, /* stop_data_collection called */
HWCMODE_ACTIVE, /* counters are defined and after start_data_collection() */
HWCMODE_ABORT /* fatal error occured. Log a message, stop recording */
} hwc_mode_t;
/*---------------------------------------------------------------------------*/
/* prototypes */
static void init_ucontexts (void);
static int hwc_initialize_handlers (void);
static void collector_record_counter (ucontext_t*,
int timecvt,
ABST_type, hrtime_t,
unsigned, uint64_t);
static void collector_hwc_ABORT (int errnum, const char *msg);
static void hwclogwrite0 ();
static void hwclogwrite (Hwcentry *);
static void set_hwc_mode (hwc_mode_t);
static void collector_sigemt_handler (int sig, siginfo_t *si, void *puc);
/*---------------------------------------------------------------------------*/
/* static variables */
/* --- user counter selections and options */
static int hwcdef_has_memspace; /* true to indicate use of extened packets */
static unsigned hwcdef_cnt; /* number of *active* hardware counters */
static unsigned hwcdef_num_sampling_ctrdefs; /* ctrs that use sampling */
static unsigned hwcdef_num_overflow_ctrdefs; /* ctrs that use overflow */
static Hwcentry **hwcdef; /* HWC definitions */
static int cpcN_cpuver = CPUVER_UNDEFINED;
static int hwcdrv_inited; /* Don't call hwcdrv_init() in fork_child */
static hwcdrv_api_t *hwc_driver = NULL;
static unsigned hwprofile_tsd_key = COLLECTOR_TSD_INVALID_KEY;
static int hwprofile_tsd_sz = 0;
static volatile hwc_mode_t hwc_mode = HWCMODE_OFF;
static volatile unsigned int nthreads_in_sighandler = 0;
static volatile unsigned int sd_state = SD_OFF;
/* --- experiment logging state */
static CollectorModule expr_hndl = COLLECTOR_MODULE_ERR;
static ucontext_t expr_dummy_uc; // used for hacked "collector" frames
static ucontext_t expr_out_of_range_uc; // used for "out-of-range" frames
static ucontext_t expr_frozen_uc; // used for "frozen" frames
static ucontext_t expr_nopc_uc; // used for not-program-related frames
static ucontext_t expr_lostcounts_uc; // used for lost_counts frames
/* --- signal handler state */
static struct sigaction old_sigemt_handler; //overwritten in fork-child
/*---------------------------------------------------------------------------*/
/* macros */
#define COUNTERS_ENABLED() (hwcdef_cnt)
#define gethrtime collector_interface->getHiResTime
#ifdef DEBUG
#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
#else
#define Tprintf(...)
#define TprintfT(...)
#endif
/*---------------------------------------------------------------------------*/
/* Initialization routines */
static hwcdrv_api_t *
get_hwc_driver ()
{
if (hwc_driver == NULL)
hwc_driver = __collector_get_hwcdrv ();
return hwc_driver;
}
static void init_module () __attribute__ ((constructor));
static void
init_module ()
{
__collector_dlsym_guard = 1;
RegModuleFunc reg_module = (RegModuleFunc) dlsym (RTLD_DEFAULT, "__collector_register_module");
__collector_dlsym_guard = 0;
if (reg_module == NULL)
{
TprintfT (0, "hwprofile: init_module FAILED - reg_module = NULL\n");
return;
}
expr_hndl = reg_module (&module_interface);
if (expr_hndl == COLLECTOR_MODULE_ERR)
{
TprintfT (0, "hwprofile: ERROR: handle not created.\n");
if (collector_interface)
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n",
SP_JCMD_CERROR, COL_ERROR_HWCINIT);
}
}
static int
init_interface (CollectorInterface *_collector_interface)
{
collector_interface = _collector_interface;
return COL_ERROR_NONE;
}
static void *
hwprofile_get_tsd ()
{
return collector_interface->getKey (hwprofile_tsd_key);
}
static int
open_experiment (const char *exp)
{
if (collector_interface == NULL)
{
TprintfT (0, "hwprofile: ERROR: collector_interface is null.\n");
return COL_ERROR_HWCINIT;
}
const char *params = collector_interface->getParams ();
while (params)
{
if (__collector_strStartWith (params, "h:*") == 0)
{
/* HWC counters set by default */
collector_interface->writeLog ("<%s %s=\"1\"/>\n",
SP_TAG_SETTING, SP_JCMD_HWC_DEFAULT);
params += 3;
break;
}
else if (__collector_strStartWith (params, "h:") == 0)
{
params += 2;
break;
}
params = CALL_UTIL (strchr)(params, ';');
if (params)
params++;
}
if (params == NULL) /* HWC profiling not specified */
return COL_ERROR_HWCINIT;
char *s = CALL_UTIL (strchr)(params, (int) ';');
int sz = s ? s - params : CALL_UTIL (strlen)(params);
char *defstring = (char*) alloca (sz + 1);
CALL_UTIL (strlcpy)(defstring, params, sz + 1);
TprintfT (0, "hwprofile: open_experiment %s -- %s\n", exp, defstring);
int err = COL_ERROR_NONE;
/* init counter library */
if (!hwcdrv_inited)
{ /* do not call hwcdrv_init() from fork-child */
hwcdrv_inited = 1;
get_hwc_driver ();
if (hwc_driver->hwcdrv_init (collector_hwc_ABORT, &hwprofile_tsd_sz) == 0)
{
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring);
TprintfT (0, "hwprofile: ERROR: hwcfuncs_init() failed\n");
return COL_ERROR_HWCINIT;
}
if (hwc_driver->hwcdrv_enable_mt (hwprofile_get_tsd))
{
// It is OK to call hwcdrv_enable_mt() before tsd key is created
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring);
TprintfT (0, "hwprofile: ERROR: hwcdrv_enable_mt() failed\n");
return COL_ERROR_HWCINIT;
}
hwc_driver->hwcdrv_get_info (&cpcN_cpuver, NULL, NULL, NULL, NULL);
if (cpcN_cpuver < 0)
{
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring);
TprintfT (0, "hwprofile: ERROR: hwcdrv_get_info() failed\n");
return COL_ERROR_HWCINIT;
}
}
if (hwprofile_tsd_sz)
{
hwprofile_tsd_key = collector_interface->createKey (hwprofile_tsd_sz, NULL, NULL);
if (hwprofile_tsd_key == COLLECTOR_TSD_INVALID_KEY)
{
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring);
TprintfT (0, "hwprofile: ERROR: TSD createKey failed\n");
return COL_ERROR_HWCINIT;
}
}
hwcdef_cnt = 0;
hwcdef_has_memspace = 0;
/* create counters based on hwcdef[] */
err = __collector_hwcfuncs_bind_descriptor (defstring);
if (err)
{
err = err == HWCFUNCS_ERROR_HWCINIT ? COL_ERROR_HWCINIT : COL_ERROR_HWCARGS;
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
SP_JCMD_CERROR, err, defstring);
TprintfT (0, "hwprofile: ERROR: open_experiment() failed, RC=%d \n", err);
return err;
}
/* generate an array of counter structures for each requested counter */
hwcdef = __collector_hwcfuncs_get_ctrs (&hwcdef_cnt);
hwcdef_num_sampling_ctrdefs = hwcdef_num_overflow_ctrdefs = 0;
int idx;
for (idx = 0; idx < hwcdef_cnt; idx++)
{
if (HWCENTRY_USES_SAMPLING (hwcdef[idx]))
{
hwcdef_num_sampling_ctrdefs++;
}
else
{
hwcdef_num_overflow_ctrdefs++;
}
}
init_ucontexts ();
/* initialize the SIGEMT handler, and the periodic HWC checker */
err = hwc_initialize_handlers ();
if (err != COL_ERROR_NONE)
{
hwcdef_cnt = 0;
TprintfT (0, "hwprofile: ERROR: open_experiment() failed, RC=%d \n", err);
/* log written by hwc_initialize_handlers() */
return err;
}
for (idx = 0; idx < hwcdef_cnt; idx++)
if (ABST_BACKTRACK_ENABLED (hwcdef[idx]->memop))
hwcdef_has_memspace = 1;
/* record the hwc definitions in the log, based on the counter array */
hwclogwrite0 ();
for (idx = 0; idx < hwcdef_cnt; idx++)
hwclogwrite (hwcdef[idx]);
return COL_ERROR_NONE;
}
int
__collector_ext_hwc_lwp_init ()
{
return get_hwc_driver ()->hwcdrv_lwp_init ();
}
void
__collector_ext_hwc_lwp_fini ()
{
get_hwc_driver ()->hwcdrv_lwp_fini ();
}
int
__collector_ext_hwc_lwp_suspend ()
{
return get_hwc_driver ()->hwcdrv_lwp_suspend ();
}
int
__collector_ext_hwc_lwp_resume ()
{
return get_hwc_driver ()->hwcdrv_lwp_resume ();
}
/* Dummy routine, used to provide a context for non-program related profiles */
void
__collector_not_program_related () { }
/* Dummy routine, used to provide a context for lost counts (perf_events) */
void
__collector_hwc_samples_lost () { }
/* Dummy routine, used to provide a context */
void
__collector_hwcs_frozen () { }
/* Dummy routine, used to provide a context */
void
__collector_hwcs_out_of_range () { }
/* initialize some structures */
static void
init_ucontexts (void)
{
/* initialize dummy context for "collector" frames */
getcontext (&expr_dummy_uc);
SETFUNCTIONCONTEXT (&expr_dummy_uc, NULL);
/* initialize dummy context for "out-of-range" frames */
getcontext (&expr_out_of_range_uc);
SETFUNCTIONCONTEXT (&expr_out_of_range_uc, &__collector_hwcs_out_of_range);
/* initialize dummy context for "frozen" frames */
getcontext (&expr_frozen_uc);
SETFUNCTIONCONTEXT (&expr_frozen_uc, &__collector_hwcs_frozen);
/* initialize dummy context for non-program-related frames */
getcontext (&expr_nopc_uc);
SETFUNCTIONCONTEXT (&expr_nopc_uc, &__collector_not_program_related);
/* initialize dummy context for lost-counts-related frames */
getcontext (&expr_lostcounts_uc);
SETFUNCTIONCONTEXT (&expr_lostcounts_uc, &__collector_hwc_samples_lost);
}
/* initialize the signal handler */
static int
hwc_initialize_handlers (void)
{
/* install the signal handler for SIGEMT */
struct sigaction oact;
if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &oact) != 0)
{
TprintfT (0, "hwc_initialize_handlers(): ERROR: hwc_initialize_handlers(): __collector_sigaction() failed to get oact\n");
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">old handler could not be determined</event>\n", SP_JCMD_CERROR, COL_ERROR_HWCINIT);
return COL_ERROR_HWCINIT;
}
if (oact.sa_sigaction == collector_sigemt_handler)
{
/* signal handler is already in place; we are probably in a fork-child */
TprintfT (DBG_LT1, "hwc_initialize_handlers(): hwc_initialize_handlers() collector_sigemt_handler already installed\n");
}
else
{
/* set our signal handler */
struct sigaction c_act;
CALL_UTIL (memset)(&c_act, 0, sizeof c_act);
sigemptyset (&c_act.sa_mask);
sigaddset (&c_act.sa_mask, SIGPROF); /* block SIGPROF delivery in handler */
/* XXXX should probably also block sample_sig & pause_sig */
c_act.sa_sigaction = collector_sigemt_handler; /* note: used to set sa_handler instead */
c_act.sa_flags = SA_RESTART | SA_SIGINFO;
if (__collector_sigaction (HWCFUNCS_SIGNAL, &c_act, &old_sigemt_handler) != 0)
{
TprintfT (0, "hwc_initialize_handlers(): ERROR: hwc_initialize_handlers(): __collector_sigaction() failed to set cact\n");
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">event handler could not be installed</event>\n", SP_JCMD_CERROR, COL_ERROR_HWCINIT);
return COL_ERROR_HWCINIT;
}
}
return COL_ERROR_NONE;
}
static int
close_experiment (void)
{
/* note: stop_data_collection() should have already been called by
* collector_close_experiment()
*/
if (!COUNTERS_ENABLED ())
return COL_ERROR_NONE;
detach_experiment ();
/* cpc or libperfctr may still generate sigemts for a while */
/* verify that SIGEMT handler is still installed */
/* (still required with sigaction interposition and management,
since interposition is not done for attach experiments)
*/
struct sigaction curr;
if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &curr) == -1)
{
TprintfT (0, "hwprofile close_experiment: ERROR: hwc sigaction check failed: errno=%d\n", errno);
}
else if (curr.sa_sigaction != collector_sigemt_handler)
{
TprintfT (DBG_LT1, "hwprofile close_experiment: WARNING: collector sigemt handler replaced by 0x%p!\n", curr.sa_handler);
(void) collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">0x%p</event>\n",
SP_JCMD_CWARN, COL_WARN_SIGEMT, curr.sa_handler);
}
else
TprintfT (DBG_LT1, "hwprofile close_experiment: collector sigemt handler integrity verified!\n");
TprintfT (0, "hwprofile: close_experiment\n");
return 0;
}
static int
detach_experiment (void)
{
/* fork child. Clean up state but don't write to experiment */
/* note: stop_data_collection() has already been called by the fork_prologue */
// detach_experiment() can be called asynchronously
// from anywhere, even from within a sigemt handler
// via DBX detach.
// Important: stop_data_collection() _must_ be called
// before detach_experiment() is called.
if (!COUNTERS_ENABLED ())
return COL_ERROR_NONE;
TprintfT (0, "hwprofile: detach_experiment()\n");
if (SD_OFF != __collector_cas_32 (&sd_state, SD_OFF, SD_PENDING))
return 0;
// one and only one call should ever make it here here.
if (hwc_mode == HWCMODE_ACTIVE)
{
TprintfT (0, "hwprofile: ERROR: stop_data_collection() should have been called before detach_experiment()\n");
stop_data_collection ();
}
// Assumption: The only calls to sigemt_handler
// we should see at this point
// will be those that were already in-flight before
// stop_new_sigemts() was called.
if (nthreads_in_sighandler > 0)
{
// sigemt handlers should see
// SD_PENDING and should call real_detach_experiment()
// when the last handler is finished.
TprintfT (DBG_LT1, "hwprofile: detach in the middle of signal handler.\n");
return 0;
}
// If we get here, there should be no remaining
// sigemt handlers. However, we don't really know
// if there were ever any in flight, so call
// real_detach_experiment() here:
return real_detach_experiment (); // multiple calls to this OK
}
static int
real_detach_experiment (void)
{
/*multiple calls to this routine are OK.*/
if (SD_PENDING != __collector_cas_32 (&sd_state, SD_PENDING, SD_COMPLETE))
return 0;
// only the first caller to this routine should get here.
hwcdef_cnt = 0; /* since now deinstalled */
hwcdef = NULL;
set_hwc_mode (HWCMODE_OFF);
if (SD_COMPLETE != __collector_cas_32 (&sd_state, SD_COMPLETE, SD_OFF))
{
TprintfT (0, "hwprofile: ERROR: unexpected sd_state in real_detach_experiment()\n");
sd_state = SD_OFF;
}
hwprofile_tsd_key = COLLECTOR_TSD_INVALID_KEY;
TprintfT (DBG_LT0, "hwprofile: real_detach_experiment() detached from experiment.\n");
return 0;
}
/*---------------------------------------------------------------------------*/
/* Record counter values. */
/* <value> should already be adjusted to be "zero-based" (counting up from 0).*/
static void
collector_record_counter_internal (ucontext_t *ucp, int timecvt,
ABST_type ABS_memop, hrtime_t time,
unsigned tag, uint64_t value, uint64_t pc,
uint64_t va, uint64_t latency,
uint64_t data_source)
{
MHwcntr_packet pckt;
CALL_UTIL (memset)(&pckt, 0, sizeof ( MHwcntr_packet));
pckt.comm.tstamp = time;
pckt.tag = tag;
if (timecvt > 1)
{
if (HWCVAL_HAS_ERR (value))
{
value = HWCVAL_CLR_ERR (value);
value *= timecvt;
value = HWCVAL_SET_ERR (value);
}
else
value *= timecvt;
}
pckt.interval = value;
pckt.comm.type = HW_PCKT;
pckt.comm.tsize = sizeof (Hwcntr_packet);
TprintfT (DBG_LT4, "hwprofile: %llu sample %lld tag %u recorded\n",
(unsigned long long) time, (long long) value, tag);
if (ABS_memop == ABST_NOPC)
ucp = &expr_nopc_uc;
pckt.comm.frinfo = collector_interface->getFrameInfo (expr_hndl, pckt.comm.tstamp, FRINFO_FROM_UC, ucp);
collector_interface->writeDataRecord (expr_hndl, (Common_packet*) & pckt);
}
static void
collector_record_counter (ucontext_t *ucp, int timecvt, ABST_type ABS_memop,
hrtime_t time, unsigned tag, uint64_t value)
{
collector_record_counter_internal (ucp, timecvt, ABS_memop, time, tag, value,
HWCFUNCS_INVALID_U64, HWCFUNCS_INVALID_U64,
HWCFUNCS_INVALID_U64, HWCFUNCS_INVALID_U64);
}
/*---------------------------------------------------------------------------*/
/* Signal handlers */
/* SIGEMT -- relayed from libcpc, when the counter overflows */
/* Generates the appropriate event or events, and resets the counters */
static void
collector_sigemt_handler (int sig, siginfo_t *si, void *puc)
{
int rc;
hwc_event_t sample, lost_samples;
if (sig != HWCFUNCS_SIGNAL)
{
TprintfT (0, "hwprofile: ERROR: %s: unexpected signal %d\n", "collector_sigemt_handler", sig);
return;
}
if (!COUNTERS_ENABLED ())
{ /* apparently deinstalled */
TprintfT (0, "hwprofile: WARNING: SIGEMT detected after close_experiment()\n");
/* kills future sigemts since hwcdrv_sighlr_restart() not called */
return;
}
/* Typically, we expect HWC overflow signals to come from the kernel: si_code > 0.
* On Linux, however, dbx might be "forwarding" a signal using tkill()/tgkill().
* For more information on what si_code values can be expected on Linux, check:
* cmn_components/Collector_Interface/hwcdrv_pcl.c hwcdrv_overflow()
* cmn_components/Collector_Interface/hwcdrv_perfctr.c hdrv_perfctr_overflow()
*/
if (puc == NULL || si == NULL || (si->si_code <= 0 && si->si_code != SI_TKILL))
{
TprintfT (DBG_LT3, "hwprofile: collector_sigemt_handler SIG%02d\n", sig);
if (old_sigemt_handler.sa_handler == SIG_DFL)
__collector_SIGDFL_handler (HWCFUNCS_SIGNAL);
else if (old_sigemt_handler.sa_handler != SIG_IGN &&
old_sigemt_handler.sa_sigaction != &collector_sigemt_handler)
{
/* Redirect the signal to the previous signal handler */
(old_sigemt_handler.sa_sigaction)(sig, si, puc);
TprintfT (DBG_LT1, "hwprofile: collector_sigemt_handler SIG%02d redirected to original handler\n", sig);
}
return;
}
rc = get_hwc_driver ()->hwcdrv_overflow (si, &sample, &lost_samples);
if (rc)
{
/* hwcdrv_sighlr_restart() should not be called */
TprintfT (0, "hwprofile: ERROR: collector_sigemt_handler: hwcdrv_overflow() failed\n");
return;
}
if (hwc_mode == HWCMODE_ACTIVE)
{
/* record the event only if counters are active */
/* The following has been copied from dispatcher.c */
#if ARCH(SPARC)
/* 23340823 signal handler third argument should point to a ucontext_t */
/* Convert sigcontext to ucontext_t on sparc-Linux */
ucontext_t uctxmem;
struct sigcontext *sctx = (struct sigcontext*) puc;
ucontext_t *uctx = &uctxmem;
uctx->uc_link = NULL;
#if WSIZE(32)
uctx->uc_mcontext.gregs[REG_PC] = sctx->si_regs.pc;
__collector_memcpy (&uctx->uc_mcontext.gregs[3],
sctx->si_regs.u_regs,
sizeof (sctx->si_regs.u_regs));
#else
uctx->uc_mcontext.mc_gregs[MC_PC] = sctx->sigc_regs.tpc;
__collector_memcpy (&uctx->uc_mcontext.mc_gregs[3],
sctx->sigc_regs.u_regs,
sizeof (sctx->sigc_regs.u_regs));
#endif /* WSIZE() */
#else
ucontext_t *uctx = (ucontext_t*) puc;
#endif /* ARCH() */
for (int ii = 0; ii < hwcdef_cnt; ii++)
if (lost_samples.ce_pic[ii])
collector_record_counter (&expr_lostcounts_uc, hwcdef[ii]->timecvt,
hwcdef[ii]->memop, lost_samples.ce_hrt,
hwcdef[ii]->sort_order, lost_samples.ce_pic[ii]);
for (int ii = 0; ii < hwcdef_cnt; ii++)
if (sample.ce_pic[ii])
collector_record_counter (uctx, hwcdef[ii]->timecvt,
hwcdef[ii]->memop, sample.ce_hrt,
hwcdef[ii]->sort_order, sample.ce_pic[ii]);
}
rc = get_hwc_driver ()->hwcdrv_sighlr_restart (NULL);
}
/* SIGPROF -- not installed as handler, but
* __collector_ext_hwc_check: called by (SIGPROF) dispatcher.
* Periodical check of integrity of HWC count/signal mechanism,
* as required for various chip/system bugs/workarounds.
*/
void
__collector_ext_hwc_check (siginfo_t *info, ucontext_t *vcontext) { }
/*---------------------------------------------------------------------------*/
int
collector_sigemt_sigaction (const struct sigaction *nact,
struct sigaction *oact)
{
struct sigaction oact_check;
/* Error codes and messages that refer to HWC are tricky.
* E.g., HWC profiling might not even be on; we might
* encounter an error here simply because the user is
* trying to set a handler for a signal that happens to
* be HWCFUNCS_SIGNAL, which we aren't even using.
*/
if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &oact_check) != 0)
{
TprintfT (0, "hwprofile: ERROR: collector_sigemt_sigaction(): request to set handler for signal %d, but check on existing handler failed\n", HWCFUNCS_SIGNAL);
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">old handler for signal %d could not be determined</event>\n", SP_JCMD_CERROR, COL_ERROR_HWCINIT, HWCFUNCS_SIGNAL);
return COL_ERROR_HWCINIT;
}
if (oact_check.sa_sigaction == collector_sigemt_handler)
{
/* dispatcher is in place, so nact/oact apply to old_sigemt_handler */
if (oact != NULL)
{
oact->sa_handler = old_sigemt_handler.sa_handler;
oact->sa_mask = old_sigemt_handler.sa_mask;
oact->sa_flags = old_sigemt_handler.sa_flags;
}
if (nact != NULL)
{
old_sigemt_handler.sa_handler = nact->sa_handler;
old_sigemt_handler.sa_mask = nact->sa_mask;
old_sigemt_handler.sa_flags = nact->sa_flags;
}
return COL_ERROR_NONE;
}
else /* no dispatcher in place, so just act like normal sigaction() */
return __collector_sigaction (HWCFUNCS_SIGNAL, nact, oact);
}
static void
collector_hwc_ABORT (int errnum, const char *msg)
{
TprintfT (0, "hwprofile: collector_hwc_ABORT: [%d] %s\n", errnum, msg);
if (hwc_mode == HWCMODE_ABORT) /* HWC collection already aborted! */
return;
set_hwc_mode (HWCMODE_ABORT); /* set global flag to disable handlers and indicate abort */
/* Write the error message to the experiment */
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s: errno=%d</event>\n",
SP_JCMD_CERROR, COL_ERROR_HWCFAIL, msg, errnum);
#ifdef REAL_DEBUG
abort ();
#else
TprintfT (0, "hwprofile: Continuing without HWC collection...\n");
#endif
}
static int
start_data_collection (void)
{
hwc_mode_t old_mode = hwc_mode;
if (!COUNTERS_ENABLED ())
return COL_ERROR_NONE;
TprintfT (0, "hwprofile: start_data_collection (hwc_mode=%d)\n", old_mode);
switch (old_mode)
{
case HWCMODE_OFF:
if (get_hwc_driver ()->hwcdrv_start ())
{
TprintfT (0, "hwprofile: ERROR: start_data_collection() failed in hwcdrv_start()\n");
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s: errno=%d</event>\n",
SP_JCMD_CERROR, COL_ERROR_HWCFAIL,
"start_data_collection()", errno);
return COL_ERROR_HWCINIT;
}
set_hwc_mode (HWCMODE_ACTIVE); /* start handling events on signals */
break;
case HWCMODE_SUSPEND:
if (get_hwc_driver ()->hwcdrv_lwp_resume ())
{
TprintfT (0, "hwprofile: ERROR: start_data_collection() failed in hwcdrv_lwp_resume()\n");
/* ignore errors from lwp_resume() */
}
set_hwc_mode (HWCMODE_ACTIVE); /* start handling events on signals */
break;
default:
TprintfT (0, "hwprofile: ERROR: start_data_collection() invalid mode\n");
return COL_ERROR_HWCINIT;
}
return COL_ERROR_NONE;
}
static int
stop_data_collection (void)
{
hwc_mode_t old_mode = hwc_mode;
if (!COUNTERS_ENABLED ())
return COL_ERROR_NONE;
TprintfT (0, "hwprofile: stop_data_collection (hwc_mode=%d)\n", old_mode);
switch (old_mode)
{
case HWCMODE_SUSPEND:
return COL_ERROR_NONE;
case HWCMODE_ACTIVE:
set_hwc_mode (HWCMODE_SUSPEND); /* stop handling signals */
break;
default:
/* Don't change the mode, but attempt to suspend anyway... */
break;
}
if (get_hwc_driver ()->hwcdrv_lwp_suspend ())
/* ignore errors from lwp_suspend() */
TprintfT (0, "hwprofile: ERROR: stop_data_collection() failed in hwcdrv_lwp_suspend()\n");
/*
* hwcdrv_lwp_suspend() cannot guarantee that all SIGEMTs will stop
* but hwc_mode will prevent logging and counters will overflow once
* then stay frozen.
*/
/* There may still be pending SIGEMTs so don't reset the SIG_DFL handler.
*/
/* see comment in dispatcher.c */
/* ret = __collector_sigaction( SIGEMT, &old_sigemt_handler, NULL ); */
return COL_ERROR_NONE;
}
/*---------------------------------------------------------------------------*/
/* utilities */
static void
set_hwc_mode (hwc_mode_t md)
{
TprintfT (DBG_LT1, "hwprofile: set_hwc_mode(%d)\n", md);
hwc_mode = md;
}
int
__collector_ext_hwc_active ()
{
return (hwc_mode == HWCMODE_ACTIVE);
}
static void
hwclogwrite0 ()
{
collector_interface->writeLog ("<profdata fname=\"%s\"/>\n",
module_interface.description);
/* Record Hwcntr_packet description */
Hwcntr_packet *pp = NULL;
collector_interface->writeLog ("<profpckt kind=\"%d\" uname=\"" STXT ("Hardware counter profiling data") "\">\n", HW_PCKT);
collector_interface->writeLog (" <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n",
&pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n",
&pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n",
&pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n",
&pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
&pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"HWCTAG\" uname=\"" STXT ("Hardware counter index") "\" offset=\"%d\" type=\"%s\"/>\n",
&pp->tag, sizeof (pp->tag) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"HWCINT\" uname=\"" STXT ("Hardware counter interval") "\" offset=\"%d\" type=\"%s\"/>\n",
&pp->interval, sizeof (pp->interval) == 4 ? "INT32" : "INT64");
collector_interface->writeLog ("</profpckt>\n");
if (hwcdef_has_memspace)
{
/* Record MHwcntr_packet description */
MHwcntr_packet *xpp = NULL;
collector_interface->writeLog ("<profpckt kind=\"%d\" uname=\"" STXT ("Hardware counter profiling data") "\">\n", MHWC_PCKT);
collector_interface->writeLog (" <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->comm.lwp_id, sizeof (xpp->comm.lwp_id) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->comm.thr_id, sizeof (xpp->comm.thr_id) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->comm.cpu_id, sizeof (xpp->comm.cpu_id) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->comm.tstamp, sizeof (xpp->comm.tstamp) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->comm.frinfo, sizeof (xpp->comm.frinfo) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"HWCTAG\" uname=\"" STXT ("Hardware counter index") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->tag, sizeof (xpp->tag) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"HWCINT\" uname=\"" STXT ("Hardware counter interval") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->interval, sizeof (xpp->interval) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"VADDR\" uname=\"" STXT ("Virtual address (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->ea_vaddr, sizeof (xpp->ea_vaddr) == 4 ? "UINT32" : "UINT64");
collector_interface->writeLog (" <field name=\"PADDR\" uname=\"" STXT ("Physical address (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->ea_paddr, sizeof (xpp->ea_paddr) == 4 ? "UINT32" : "UINT64");
collector_interface->writeLog (" <field name=\"VIRTPC\" uname=\"" STXT ("Virtual address (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->pc_vaddr, sizeof (xpp->pc_vaddr) == 4 ? "UINT32" : "UINT64");
collector_interface->writeLog (" <field name=\"PHYSPC\" uname=\"" STXT ("Physical address (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->pc_paddr, sizeof (xpp->pc_paddr) == 4 ? "UINT32" : "UINT64");
collector_interface->writeLog (" <field name=\"EA_PAGESIZE\" uname=\"" STXT ("Page size (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->ea_pagesz, sizeof (xpp->ea_pagesz) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"PC_PAGESIZE\" uname=\"" STXT ("Page size (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->pc_pagesz, sizeof (xpp->pc_pagesz) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"EA_LGRP\" uname=\"" STXT ("Page locality group (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->ea_lgrp, sizeof (xpp->ea_lgrp) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"PC_LGRP\" uname=\"" STXT ("Page locality group (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->pc_lgrp, sizeof (xpp->pc_lgrp) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"LWP_LGRP_HOME\" uname=\"" STXT ("LWP home lgroup id") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->lgrp_lwp, sizeof (xpp->lgrp_lwp) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"PS_LGRP_HOME\" uname=\"" STXT ("Process home lgroup id") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->lgrp_ps, sizeof (xpp->lgrp_ps) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"MEM_LAT\" uname=\"" STXT ("Memory Latency Cycles") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->latency, sizeof (xpp->latency) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"MEM_SRC\" uname=\"" STXT ("Memory Data Source") "\" offset=\"%d\" type=\"%s\"/>\n",
&xpp->data_source, sizeof (xpp->data_source) == 4 ? "INT32" : "INT64");
collector_interface->writeLog ("</profpckt>\n");
}
}
static void
hwclogwrite (Hwcentry * ctr)
{
TprintfT (DBG_LT1, "hwprofile: writeLog(%s %u %s %d %u %d)\n",
SP_JCMD_HW_COUNTER, cpcN_cpuver, ctr->name ? ctr->name : "NULL",
ctr->val, ctr->sort_order, ctr->memop);
collector_interface->writeLog ("<profile name=\"%s\"", SP_JCMD_HW_COUNTER);
collector_interface->writeLog (" cpuver=\"%u\"", cpcN_cpuver);
collector_interface->writeLog (" hwcname=\"%s\"", ctr->name);
collector_interface->writeLog (" int_name=\"%s\"", ctr->int_name);
collector_interface->writeLog (" interval=\"%d\"", ctr->val);
collector_interface->writeLog (" tag=\"%u\"", ctr->sort_order);
collector_interface->writeLog (" memop=\"%d\"", ctr->memop);
collector_interface->writeLog ("/>\n");
}

View file

@ -0,0 +1,89 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _HWPROFILE_H
#define _HWPROFILE_H
#include <data_pckts.h>
typedef struct Hwcntr_packet
{ /* HW counter profiling packet */
Common_packet comm;
uint32_t tag; /* hw counter index, register */
uint64_t interval; /* overflow value */
} Hwcntr_packet;
typedef struct MHwcntr_packet
{ /* extended (superset) Hwcntr_packet */
Common_packet comm;
uint32_t tag; /* hw counter index, register */
uint64_t interval; /* overflow value */
Vaddr_type ea_vaddr; /* virtual addr causing HWC event */
Vaddr_type pc_vaddr; /* candidate eventPC */
uint64_t ea_paddr; /* physical address for ea_vaddr */
uint64_t pc_paddr; /* physical address for pc_vaddr */
uint64_t ea_pagesz; /* pagesz (bytes) for ea_paddr */
uint64_t pc_pagesz; /* pagesz (bytes) for pc_paddr */
uint32_t ea_lgrp; /* latency group of ea_paddr */
uint32_t pc_lgrp; /* latency group of pc_paddr */
uint32_t lgrp_lwp; /* locality group of lwp */
uint32_t lgrp_ps; /* locality group of process */
uint64_t latency; /* latency in cycles (sampling only) */
uint64_t data_source; /* data source (sampling only) */
} MHwcntr_packet;
#if ARCH(SPARC)
#define CONTEXT_PC MC_PC
#define CONTEXT_SP MC_O6
#define CONTEXT_FP MC_O7
#define SETFUNCTIONCONTEXT(ucp,funcp) \
(ucp)->uc_mcontext.gregs[CONTEXT_PC] = (greg_t)(funcp); \
(ucp)->uc_mcontext.gregs[CONTEXT_SP] = 0; \
(ucp)->uc_mcontext.gregs[CONTEXT_FP] = 0;
#elif ARCH(Intel)
#include <sys/reg.h>
#if WSIZE(64)
#define CONTEXT_PC REG_RIP
#define CONTEXT_FP REG_RBP
#define CONTEXT_SP REG_RSP
#elif WSIZE(32)
#define CONTEXT_PC REG_EIP
#define CONTEXT_FP REG_EBP
#define CONTEXT_SP REG_ESP
#endif /* WSIZE() */
#define SETFUNCTIONCONTEXT(ucp,funcp) \
(ucp)->uc_mcontext.gregs[CONTEXT_PC] = (greg_t)(funcp); \
(ucp)->uc_mcontext.gregs[CONTEXT_SP] = 0; \
(ucp)->uc_mcontext.gregs[CONTEXT_FP] = 0;
#elif ARCH(Aarch64)
#define CONTEXT_PC 15
#define CONTEXT_FP 14
#define CONTEXT_SP 13
#define SETFUNCTIONCONTEXT(ucp,funcp) \
(ucp)->uc_mcontext.regs[CONTEXT_PC] = (greg_t)(funcp); \
(ucp)->uc_mcontext.regs[CONTEXT_SP] = 0; \
(ucp)->uc_mcontext.regs[CONTEXT_FP] = 0;
#endif /* ARCH() */
#endif

1156
gprofng/libcollector/iolib.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,28 @@
/* Copyright (C) 2022 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#if defined(__i386__) || defined(__x86_64)
#include "opcodes/i386-dis.c"
#undef _
#undef M
#include "libiberty/safe-ctype.c"
#endif

View file

@ -0,0 +1,25 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include "collector.h" /* Tprintf*() */
#define LIBCOLLECTOR_SRC
#include "hwcdrv.c"

View file

@ -0,0 +1,27 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include "collector.h" /* Tprintf*() */
#define LIBCOLLECTOR_SRC
#include "hwcfuncs.c"

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,321 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _LIBCOL_UTIL_H
#define _LIBCOL_UTIL_H
#include <stdarg.h>
#include <pthread.h>
#include <signal.h>
// LIBCOLLECTOR NOT I18N
#define NTXT(x) x
#define STXT(x) x
extern int __collector_tracelevel;
/* Initialization function */
extern int __collector_util_init();
extern void __collector_libkstat_funcs_init();
extern void __collector_libscf_funcs_init();
/* ------- functions from libcol_util.c ----------------- */
extern void * __collector_memcpy (void *s1, const void *s2, size_t n);
extern int (*__collector_sscanfp)(const char *restrict s, const char *restrict fmt, ...);
extern char * __collector_strcat (char *s1, const char *s2);
extern char * __collector_strchr (const char *s1, int chr);
extern size_t __collector_strlcpy (char *dst, const char *src, size_t dstsize);
extern char* __collector_strrchr (const char *str, int chr);
extern size_t __collector_strlen (const char *s);
extern size_t __collector_strlcat (char *dst, const char *src, size_t dstsize);
extern char* __collector_strchr (const char *str, int chr);
extern int __collector_strcmp (const char *s1, const char *s2);
extern int __collector_strncmp (const char *s1, const char *s2, size_t n);
extern char * __collector_strstr (const char *s1, const char *s2);
extern size_t __collector_strncpy (char *dst, const char *src, size_t dstsize);
extern size_t __collector_strncat (char *dst, const char *src, size_t dstsize);
extern void * __collector_malloc (size_t size);
extern void * __collector_calloc (size_t nelem, size_t elsize);
extern char * __collector_strdup (const char * str);
extern int __collector_strStartWith (const char *s1, const char *s2);
extern int __collector_xml_snprintf (char *s, size_t n, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
extern int __collector_xml_vsnprintf (char *s, size_t n, const char *format, va_list args);
/* ------- collector_thread ----------------- */
pid_t __collector_gettid ();
extern void __collector_ext_gettid_tsd_create_key ();
#define collector_thread_t pthread_t // not using pid_t, since tid is defined as pthread_t in package structures, and other codes assume this type
#define statvfs_t struct statvfs
#define __collector_lwp_self() (collector_thread_t)__collector_gettid() // not using pthread_self()
#define __collector_thr_self() (collector_thread_t)__collector_gettid() // not using pthread_self()
/* ------- collector_mutex ----------------- */
/*
* mutex_init is defined in libthread. If we don't want to interact
* with libthread we should use memset to initialize mutexes
*/
typedef volatile int collector_mutex_t;
#define COLLECTOR_MUTEX_INITIALIZER 0
extern int __collector_mutex_lock (collector_mutex_t *mp);
extern int __collector_mutex_unlock (collector_mutex_t *mp);
extern int __collector_mutex_trylock (collector_mutex_t *mp);
#define __collector_mutex_init(xx) \
do { collector_mutex_t tmp=COLLECTOR_MUTEX_INITIALIZER; *(xx)=tmp; } while(0)
void __collector_sample (char *name);
void __collector_terminate_expt ();
void __collector_pause ();
void __collector_pause_m ();
void __collector_resume ();
struct DT_lineno;
typedef enum
{
DFUNC_API = 1, /* dynamic function declared with API */
DFUNC_JAVA, /* dynamically compiled java method */
DFUNC_KERNEL /* dynamic code mapped by the kernel (Linux) */
} dfunc_mode_t;
extern void __collector_int_func_load (dfunc_mode_t mode, char *name,
char *sourcename, void *vaddr,
int size, int lntsize,
struct DT_lineno *lntable);
extern void __collector_int_func_unload (dfunc_mode_t mode, void *vaddr);
extern int __collector_sigaction (int sig, const struct sigaction *nact,
struct sigaction *oact);
extern void __collector_SIGDFL_handler (int sig);
extern int __collector_ext_itimer_set (int period);
#if ARCH(Intel)
/* Atomic functions on x86/x64 */
/**
* This function enables the inrementing (by one) of the value stored in target
* to occur in an atomic manner.
*/
static __attribute__ ((always_inline)) inline void
__collector_inc_32 (uint32_t *ptr)
{
__asm__ __volatile__("lock; incl %0"
: // "=m" (*ptr) // output
: "m" (*ptr)); // input
}
/**
* This function enables the decrementing (by one) of the value stored in target
* to occur in an atomic manner.
*/
static __attribute__ ((always_inline)) inline void
__collector_dec_32 (volatile uint32_t *ptr)
{
__asm__ __volatile__("lock; decl %0"
: // "=m" (*ptr) // output
: "m" (*ptr)); // input
}
/**
* This function subtrackts the value "off" of the value stored in target
* to occur in an atomic manner, and returns new value stored in target.
*/
static __attribute__ ((always_inline)) inline uint32_t
__collector_subget_32 (uint32_t *ptr, uint32_t off)
{
uint32_t r;
uint32_t offset = off;
__asm__ __volatile__("movl %2, %0; negl %0; lock; xaddl %0, %1"
: "=r" (r), "=m" (*ptr) /* output */
: "a" (off), "r" (*ptr) /* input */
);
return (r - offset);
}
/**
* This function returns the value of the stack pointer register
*/
static __attribute__ ((always_inline)) inline void *
__collector_getsp ()
{
void *r;
#if WSIZE(64)
__asm__ __volatile__("movq %%rsp, %0"
#else
__asm__ __volatile__("movl %%esp, %0"
#endif
: "=r" (r)); // output
return r;
}
/**
* This function returns the value of the frame pointer register
*/
static __attribute__ ((always_inline)) inline void *
__collector_getfp ()
{
void *r;
#if WSIZE(64)
__asm__ __volatile__("movq %%rbp, %0"
#else
__asm__ __volatile__("movl %%ebp, %0"
#endif
: "=r" (r)); // output
return r;
}
/**
* This function returns the value of the processor counter register
*/
static __attribute__ ((always_inline)) inline void *
__collector_getpc ()
{
void *r;
__asm__ __volatile__(
#if WSIZE(32)
" call 1f \n"
"1: popl %0 \n"
#else
" call 1f \n"
"1: popq %0 \n"
#endif
: "=r" (r)); // output
return r;
}
/**
* This function enables a compare and swap operation to occur atomically.
* The 32-bit value stored in target is compared with "old". If these values
* are equal, the value stored in target is replaced with "new". The old
* 32-bit value stored in target is returned by the function whether or not
* the replacement occurred.
*/
static __attribute__ ((always_inline)) inline uint32_t
__collector_cas_32 (volatile uint32_t *pdata, uint32_t old, uint32_t new)
{
uint32_t r;
__asm__ __volatile__("lock; cmpxchgl %2, %1"
: "=a" (r), "=m" (*pdata) : "r" (new),
"a" (old), "m" (*pdata));
return r;
}
/**
* This function enables a compare and swap operation to occur atomically.
* The 64-bit value stored in target is compared with "old". If these values
* are equal, the value stored in target is replaced with "new". The old
* 64-bit value stored in target is returned by the function whether or not
* the replacement occurred.
*/
static __attribute__ ((always_inline)) inline uint64_t
__collector_cas_64p (volatile uint64_t *mem, uint64_t *old, uint64_t * new)
{
uint64_t r;
#if WSIZE(32)
uint32_t old1 = (uint32_t) (*old & 0xFFFFFFFFL);
uint32_t old2 = (uint32_t) ((*old >> 32) & 0xFFFFFFFFL);
uint32_t new1 = (uint32_t) (*new & 0xFFFFFFFFL);
uint32_t new2 = (uint32_t) ((*new >> 32) & 0xFFFFFFFFL);
uint32_t res1 = 0;
uint32_t res2 = 0;
__asm__ __volatile__(
"movl %3, %%esi; lock; cmpxchg8b (%%esi); movl %%edx, %2; movl %%eax, %1"
: "=m" (r), "=m" (res1), "=m" (res2) /* output */
: "m" (mem), "a" (old1), "d" (old2), "b" (new1), "c" (new2) /* input */
: "memory", "cc", "esi" //, "edx", "ecx", "ebx", "eax" /* clobbered register */
);
r = (((uint64_t) res2) << 32) | ((uint64_t) res1);
#else
__asm__ __volatile__( "lock; cmpxchgq %2, %1"
: "=a" (r), "=m" (*mem) /* output */
: "r" (*new), "a" (*old), "m" (*mem) /* input */
: "%rcx", "rdx" /* clobbered register */
);
#endif
return r;
}
/**
* This function enables a compare and swap operation to occur atomically.
* The 32-/64-bit value stored in target is compared with "cmp". If these values
* are equal, the value stored in target is replaced with "new".
* The old value stored in target is returned by the function whether or not
* the replacement occurred.
*/
static __attribute__ ((always_inline)) inline void *
__collector_cas_ptr (void *mem, void *cmp, void *new)
{
void *r;
#if WSIZE(32)
r = (void *) __collector_cas_32 ((volatile uint32_t *)mem, (uint32_t) cmp, (uint32_t)new);
#else
__asm__ __volatile__("lock; cmpxchgq %2, (%1)"
: "=a" (r), "=b" (mem) /* output */
: "r" (new), "a" (cmp), "b" (mem) /* input */
);
#endif
return r;
}
#elif ARCH(Aarch64)
static __attribute__ ((always_inline)) inline uint32_t
__collector_inc_32 (volatile uint32_t *ptr)
{
return __sync_add_and_fetch (ptr, 1);
}
static __attribute__ ((always_inline)) inline uint32_t
__collector_dec_32 (volatile uint32_t *ptr)
{
return __sync_sub_and_fetch (ptr, 1);
}
static __attribute__ ((always_inline)) inline uint32_t
__collector_subget_32 (volatile uint32_t *ptr, uint32_t off)
{
return __sync_sub_and_fetch (ptr, off);
}
static __attribute__ ((always_inline)) inline uint32_t
__collector_cas_32 (volatile uint32_t *ptr, uint32_t old, uint32_t new)
{
return __sync_val_compare_and_swap (ptr, old, new);
}
static __attribute__ ((always_inline)) inline uint64_t
__collector_cas_64p (volatile uint64_t *ptr, uint64_t *old, uint64_t * new)
{
return __sync_val_compare_and_swap (ptr, *old, *new);
}
static __attribute__ ((always_inline)) inline void *
__collector_cas_ptr (void *ptr, void *old, void *new)
{
return (void *) __sync_val_compare_and_swap ((unsigned long *) ptr, (unsigned long) old, (unsigned long) new);
}
#else
extern void __collector_flushw (); /* defined for SPARC only */
extern void* __collector_getpc ();
extern void* __collector_getsp ();
extern void* __collector_getfp ();
extern void __collector_inc_32 (volatile uint32_t *);
extern void __collector_dec_32 (volatile uint32_t *);
extern void* __collector_cas_ptr (volatile void *, void *, void *);
extern uint32_t __collector_cas_32 (volatile uint32_t *, uint32_t, uint32_t);
extern uint32_t __collector_subget_32 (volatile uint32_t *, uint32_t);
extern uint64_t __collector_cas_64p (volatile uint64_t *, uint64_t *, uint64_t *);
#endif /* ARCH() */
#endif /* _LIBCOL_UTIL_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
GLIBC_2.17 {
global:
posix_spawn;
posix_spawnp;
pthread_mutex_lock;
pthread_mutex_unlock;
pthread_join;
sem_wait;
pthread_create;
dlopen;
popen;
timer_create;
pthread_cond_wait;
pthread_cond_timedwait;
fopen;
fclose;
fdopen;
fgetpos;
fsetpos;
};

View file

@ -0,0 +1,79 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
GLIBC_2.2.5 {
global:
posix_spawn;
posix_spawnp;
pthread_mutex_lock;
pthread_mutex_unlock;
pthread_join;
sem_wait;
pthread_create;
dlopen;
popen;
timer_create;
pthread_cond_wait;
pthread_cond_timedwait;
fopen;
fclose;
fdopen;
fgetpos;
fsetpos;
};
GLIBC_2.3.2 {
global:
pthread_cond_wait;
pthread_cond_timedwait;
};
GLIBC_2.3.3 {
global:
timer_create;
};
GLIBC_2.15 {
global:
posix_spawn;
posix_spawnp;
};
GLIBC_2.17 {
global:
posix_spawn;
posix_spawnp;
pthread_mutex_lock;
pthread_mutex_unlock;
pthread_join;
sem_wait;
pthread_create;
dlopen;
popen;
timer_create;
pthread_cond_wait;
pthread_cond_timedwait;
fopen;
fclose;
fdopen;
fgetpos;
fsetpos;
};

View file

@ -0,0 +1,81 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
GLIBC_2.0 {
global:
pthread_mutex_lock;
pthread_mutex_unlock;
pthread_join;
pthread_create;
dlopen;
popen;
sem_wait;
pthread_cond_wait;
pthread_cond_timedwait;
fopen;
fclose;
fdopen;
fgetpos;
fsetpos;
};
GLIBC_2.1 {
global:
sem_wait;
pthread_create;
dlopen;
open64;
pread;
pwrite;
pwrite64;
popen;
fopen;
fclose;
fdopen;
fgetpos64;
fsetpos64;
};
GLIBC_2.2 {
global:
open64;
posix_spawn;
posix_spawnp;
pread;
pwrite;
pwrite64;
timer_create;
fgetpos;
fsetpos;
fgetpos64;
fsetpos64;
};
GLIBC_2.3.2 {
global:
pthread_cond_wait;
pthread_cond_timedwait;
};
GLIBC_2.15 {
global:
posix_spawn;
posix_spawnp;
};

View file

@ -0,0 +1,40 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
GLIBC_2.0 {
global:
pthread_mutex_lock;
pthread_mutex_unlock;
pthread_join;
};
GLIBC_2.1 {
global:
sem_wait;
pthread_create;
dlopen;
popen;
};
GLIBC_2.3.2 {
global:
pthread_cond_wait;
pthread_cond_timedwait;
};

View file

@ -0,0 +1,58 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
GLIBC_2.0 {
global:
dlopen;
};
GLIBC_2.1 {
global:
dlopen;
};
GLIBC_2.2 {
global:
pthread_create;
popen;
pthread_mutex_lock;
pthread_mutex_unlock;
pthread_join;
sem_wait;
pthread_cond_wait;
pthread_cond_timedwait;
timer_create;
fopen;
fclose;
fdopen;
fgetpos;
fsetpos;
};
GLIBC_2.3.2 {
global:
pthread_cond_wait;
pthread_cond_timedwait;
};
GLIBC_2.3.3 {
global:
timer_create;
};

View file

@ -0,0 +1,396 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "collector.h"
#include "libcol_util.h"
#include "gp-experiment.h"
#include "memmgr.h"
/* TprintfT(<level>,...) definitions. Adjust per module as needed */
#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
#define DBG_LT1 1 // for configuration details, warnings
#define DBG_LT2 2
#define DBG_LT3 3
#define DBG_LT4 4
/*
* Memory allocation.
*
* Heap:
* chain[0] - linked list of chunks;
* chain[1] - linked list of free 16-byte objects;
* chain[2] - linked list of free 32-byte objects;
* ...
*
* Chunk:
*
* base lo hi
* V V V
* +------------------+---------+-------------------+--+--+-----+
* | Var size object | -> <-| Const size objects| | |Chunk|
* +------------------+---------+-------------------+--+--+-----+
*
* Limitations:
* - one var size object per chunk
* - can't allocate const size objects larger than 2^MAXCHAIN
*/
#define MAXCHAIN 32
#define ALIGNMENT 4 /* 2^ALIGNMENT == minimal size and alignment */
#define ALIGN(x) ((((x) - 1)/(1 << ALIGNMENT) + 1) * (1 << ALIGNMENT))
struct Heap
{
collector_mutex_t lock; /* master lock */
void *chain[MAXCHAIN]; /* chain[0] - chunks */
/* chain[i] - structs of size 2^i */
};
typedef struct Chunk
{
size_t size;
char *base;
char *lo;
char *hi;
struct Chunk *next;
} Chunk;
static void
not_implemented ()
{
__collector_log_write ("<event kind=\"%s\" id=\"%d\">error memmgr not_implemented()</event>\n",
SP_JCMD_CERROR, COL_ERROR_NOZMEM);
return;
}
/*
* void __collector_mmgr_init_mutex_locks( Heap *heap )
* Iinitialize mmgr mutex locks.
*/
void
__collector_mmgr_init_mutex_locks (Heap *heap)
{
if (heap == NULL)
return;
if (__collector_mutex_trylock (&heap->lock))
{
/*
* We are in a child process immediately after the fork().
* Parent process was in the middle of critical section when the fork() happened.
* This is a placeholder for the cleanup.
* See CR 6997020 for details.
*/
__collector_mutex_init (&heap->lock);
}
__collector_mutex_init (&heap->lock);
}
/*
* alloc_chunk( unsigned sz ) allocates a chunk of at least sz bytes.
* If sz == 0, allocates a chunk of the default size.
*/
static Chunk *
alloc_chunk (unsigned sz, int log)
{
static long pgsz = 0;
char *ptr;
Chunk *chnk;
size_t chunksz;
if (pgsz == 0)
{
pgsz = CALL_UTIL (sysconf)(_SC_PAGESIZE);
Tprintf (DBG_LT2, "memmgr: pgsz = %ld (0x%lx)\n", pgsz, pgsz);
}
/* Allocate 2^n >= sz bytes */
unsigned nsz = ALIGN (sizeof (Chunk)) + sz;
for (chunksz = pgsz; chunksz < nsz; chunksz *= 2);
if (log == 1)
Tprintf (DBG_LT2, "alloc_chunk mapping %u, rounded up from %u\n", (unsigned int) chunksz, sz);
/* mmap64 is only in 32-bits; this call goes to mmap in 64-bits */
ptr = (char*) CALL_UTIL (mmap64)(0, chunksz, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, (int) -1, (off64_t) 0);
if (ptr == MAP_FAILED)
{
Tprintf (0, "alloc_chunk mapping failed COL_ERROR_NOZMEMMAP: %s\n", CALL_UTIL (strerror)(errno));
__collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
SP_JCMD_CERROR, COL_ERROR_NOZMEMMAP, errno, "0");
return NULL;
}
/* Put the chunk descriptor at the end of the chunk */
chnk = (Chunk*) (ptr + chunksz - ALIGN (sizeof (Chunk)));
chnk->size = chunksz;
chnk->base = ptr;
chnk->lo = chnk->base;
chnk->hi = (char*) chnk;
chnk->next = (Chunk*) NULL;
if (log == 1)
Tprintf (DBG_LT2, "memmgr: returning new chunk @%p, chunksx=%ld sz=%ld\n",
ptr, (long) chunksz, (long) sz);
return chnk;
}
Heap *
__collector_newHeap ()
{
Heap *heap;
Chunk *chnk;
Tprintf (DBG_LT2, "__collector_newHeap calling alloc_chunk(0)\n");
chnk = alloc_chunk (0, 1);
if (chnk == NULL)
return NULL;
/* A bit of hackery: allocate heap from its own chunk */
chnk->hi -= ALIGN (sizeof (Heap));
heap = (Heap*) chnk->hi;
heap->chain[0] = (void*) chnk;
__collector_mutex_init (&heap->lock);
return heap;
}
void
__collector_deleteHeap (Heap *heap)
{
if (heap == NULL)
return;
/* Note: heap itself is in the last chunk */
for (Chunk *chnk = heap->chain[0]; chnk;)
{
Chunk *next = chnk->next;
CALL_UTIL (munmap)((void*) chnk->base, chnk->size);
chnk = next;
}
}
void *
__collector_allocCSize (Heap *heap, unsigned sz, int log)
{
void *res;
Chunk *chnk;
if (heap == NULL)
return NULL;
/* block all signals and acquire lock */
sigset_t old_mask, new_mask;
CALL_UTIL (sigfillset)(&new_mask);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask);
__collector_mutex_lock (&heap->lock);
/* Allocate nsz = 2^idx >= sz bytes */
unsigned idx = ALIGNMENT;
unsigned nsz = 1 << idx;
while (nsz < sz)
nsz = 1 << ++idx;
/* Look in the corresponding chain first */
if (idx < MAXCHAIN)
{
if (heap->chain[idx] != NULL)
{
res = heap->chain[idx];
heap->chain[idx] = *(void**) res;
__collector_mutex_unlock (&heap->lock);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
if (log == 1)
Tprintf (DBG_LT2, "memmgr: allocCSize %p sz %d (0x%x) req = 0x%x, from chain idx = %d\n", res, nsz, nsz, sz, idx);
return res;
}
}
else
{
not_implemented ();
__collector_mutex_unlock (&heap->lock);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
return NULL;
}
/* Chain is empty, allocate from chunks */
for (chnk = (Chunk*) heap->chain[0]; chnk; chnk = chnk->next)
if (chnk->lo + nsz < chnk->hi)
break;
if (chnk == NULL)
{
/* Get a new chunk */
if (log == 1)
Tprintf (DBG_LT2, "__collector_allocCSize (%u) calling alloc_chunk(%u)\n", sz, nsz);
chnk = alloc_chunk (nsz, 1);
if (chnk == NULL)
{
__collector_mutex_unlock (&heap->lock);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
return NULL;
}
chnk->next = (Chunk*) heap->chain[0];
heap->chain[0] = chnk;
}
/* Allocate from the chunk */
chnk->hi -= nsz;
res = (void*) chnk->hi;
__collector_mutex_unlock (&heap->lock);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
if (log == 1)
Tprintf (DBG_LT2, "memmgr: allocCSize %p sz %d (0x%x) req = 0x%x, new chunk\n", res, nsz, nsz, sz);
return res;
}
void
__collector_freeCSize (Heap *heap, void *ptr, unsigned sz)
{
if (heap == NULL || ptr == NULL)
return;
/* block all signals and acquire lock */
sigset_t old_mask, new_mask;
CALL_UTIL (sigfillset)(&new_mask);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask);
__collector_mutex_lock (&heap->lock);
/* Free 2^idx >= sz bytes */
unsigned idx = ALIGNMENT;
unsigned nsz = 1 << idx;
while (nsz < sz)
nsz = 1 << ++idx;
if (idx < MAXCHAIN)
{
*(void**) ptr = heap->chain[idx];
heap->chain[idx] = ptr;
}
else
not_implemented ();
__collector_mutex_unlock (&heap->lock);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
Tprintf (DBG_LT4, "memmgr: freeC %p sz %ld\n", ptr, (long) sz);
}
static void *
allocVSize_nolock (Heap *heap, unsigned sz)
{
void *res;
Chunk *chnk;
if (sz == 0)
return NULL;
/* Find a good chunk */
for (chnk = (Chunk*) heap->chain[0]; chnk; chnk = chnk->next)
if (chnk->lo == chnk->base && chnk->lo + sz < chnk->hi)
break;
if (chnk == NULL)
{
/* Get a new chunk */
Tprintf (DBG_LT2, "allocVsize_nolock calling alloc_chunk(%u)\n", sz);
chnk = alloc_chunk (sz, 0);
if (chnk == NULL)
return NULL;
chnk->next = (Chunk*) heap->chain[0];
heap->chain[0] = chnk;
}
chnk->lo = chnk->base + sz;
res = (void*) (chnk->base);
Tprintf (DBG_LT4, "memmgr: allocV %p for %ld\n", res, (long) sz);
return res;
}
void *
__collector_allocVSize (Heap *heap, unsigned sz)
{
void *res;
if (heap == NULL)
return NULL;
/* block all signals and acquire lock */
sigset_t old_mask, new_mask;
CALL_UTIL (sigfillset)(&new_mask);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask);
__collector_mutex_lock (&heap->lock);
res = allocVSize_nolock (heap, sz);
__collector_mutex_unlock (&heap->lock);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
return res;
}
/*
* reallocVSize( Heap *heap, void *ptr, unsigned newsz )
* Changes the size of memory pointed by ptr to newsz.
* If ptr == NULL, allocates new memory of size newsz.
* If newsz == 0, frees ptr and returns NULL.
*/
void *
__collector_reallocVSize (Heap *heap, void *ptr, unsigned newsz)
{
Chunk *chnk;
void *res;
if (heap == NULL)
return NULL;
if (ptr == NULL)
return __collector_allocVSize (heap, newsz);
/* block all signals and acquire lock */
sigset_t old_mask, new_mask;
CALL_UTIL (sigfillset)(&new_mask);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask);
__collector_mutex_lock (&heap->lock);
/* Find its chunk */
for (chnk = (Chunk*) heap->chain[0]; chnk; chnk = chnk->next)
if (ptr == chnk->base)
break;
if (chnk == NULL)
{
/* memory corrpution */
not_implemented ();
__collector_mutex_unlock (&heap->lock);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
return NULL;
}
if (chnk->base + newsz < chnk->hi)
{
/* easy case */
chnk->lo = chnk->base + newsz;
res = newsz ? chnk->base : NULL;
__collector_mutex_unlock (&heap->lock);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
Tprintf (DBG_LT4, "memmgr: reallocV %p for %ld\n", ptr, (long) newsz);
return res;
}
res = allocVSize_nolock (heap, newsz);
/* Copy to new location */
if (res)
{
int size = chnk->lo - chnk->base;
if (newsz < size)
size = newsz;
char *s1 = (char*) res;
char *s2 = chnk->base;
while (size--)
*s1++ = *s2++;
}
/* Free old memory*/
chnk->lo = chnk->base;
__collector_mutex_unlock (&heap->lock);
CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
return res;
}

View file

@ -0,0 +1,59 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _MEMMGR_H
#define _MEMMGR_H
struct Heap;
typedef struct Heap Heap;
Heap *__collector_newHeap ();
void __collector_deleteHeap (Heap *heap);
/*
* Initialize memmgr mutex locks.
*/
void __collector_mmgr_init_mutex_locks (Heap *heap);
/*
* Allocate non-resizable memory.
*/
void *__collector_allocCSize (Heap *heap, unsigned sz, int log);
/*
* Free non-resizable memory.
*/
void __collector_freeCSize (Heap *heap, void *ptr, unsigned sz);
/*
* Allocate resizable memory
*/
void *__collector_allocVSize (Heap *heap, unsigned sz);
/*
* Change size of resizable memory.
* ptr - if not NULL, it must have been previously allocated from
* the same heap, otherwise returns allocVSize(heap, newsz);
* newsz - new size; if 0, memory is freed and no new allocation
* occurs;
*/
void *__collector_reallocVSize (Heap *heap, void *ptr, unsigned newsz);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,287 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/*
* Profile handling
*
* Note: SIGPROF signal-handling and interval timer (once exclusive to
* profile handling) are now common services provided by the dispatcher.
*/
#include "config.h"
#include <dlfcn.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
#include <unistd.h>
#include "gp-defs.h"
#include "collector_module.h"
#include "gp-experiment.h"
#include "data_pckts.h"
#include "libcol_util.h"
#include "hwprofile.h"
#include "tsd.h"
/* TprintfT(<level>,...) definitions. Adjust per module as needed */
#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
#define DBG_LT1 1 // for configuration details, warnings
#define DBG_LT2 2
#define DBG_LT3 3
static int init_interface (CollectorInterface*);
static int open_experiment (const char *);
static int start_data_collection (void);
static int stop_data_collection (void);
static int close_experiment (void);
static int detach_experiment (void);
static ModuleInterface module_interface ={
SP_PROFILE_FILE, /* description */
init_interface, /* initInterface */
open_experiment, /* openExperiment */
start_data_collection, /* startDataCollection */
stop_data_collection, /* stopDataCollection */
close_experiment, /* closeExperiment */
detach_experiment /* detachExperiment (fork child) */
};
static CollectorInterface *collector_interface = NULL;
static int prof_mode = 0;
static CollectorModule prof_hndl = COLLECTOR_MODULE_ERR;
static unsigned prof_key = COLLECTOR_TSD_INVALID_KEY;
typedef struct ClockPacket
{ /* clock profiling packet */
CM_Packet comm;
pthread_t lwp_id;
pthread_t thr_id;
uint32_t cpu_id;
hrtime_t tstamp __attribute__ ((packed));
uint64_t frinfo __attribute__ ((packed));
int mstate; /* kernel microstate */
int nticks; /* number of ticks in that state */
} ClockPacket;
/* XXX should be able to use local types */
#define CLOCK_TYPE OPROF_PCKT
#define CHCK_REENTRANCE(x) ( !prof_mode || ((x) = collector_interface->getKey( prof_key )) == NULL || (*(x) != 0) )
#define PUSH_REENTRANCE(x) ((*(x))++)
#define POP_REENTRANCE(x) ((*(x))--)
#ifdef DEBUG
#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
#else
#define Tprintf(...)
#define TprintfT(...)
#endif
static void init_module () __attribute__ ((constructor));
static void
init_module ()
{
__collector_dlsym_guard = 1;
RegModuleFunc reg_module = (RegModuleFunc) dlsym (RTLD_DEFAULT, "__collector_register_module");
__collector_dlsym_guard = 0;
if (reg_module == NULL)
{
TprintfT (0, "clockprof: init_module FAILED -- reg_module = NULL\n");
return;
}
prof_hndl = reg_module (&module_interface);
if (prof_hndl == COLLECTOR_MODULE_ERR && collector_interface != NULL)
{
Tprintf (0, "clockprof: ERROR: handle not created.\n");
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n", SP_JCMD_CERROR, COL_ERROR_PROFINIT);
}
TprintfT (0, "clockprof: init_module, prof_hndl = %d\n", prof_hndl);
return;
}
static int
init_interface (CollectorInterface *_collector_interface)
{
collector_interface = _collector_interface;
return COL_ERROR_NONE;
}
static int
open_experiment (const char *exp)
{
if (collector_interface == NULL)
{
Tprintf (0, "clockprof: ERROR: collector_interface is null.\n");
return COL_ERROR_PROFINIT;
}
const char *params = collector_interface->getParams ();
while (params)
{
if (__collector_strStartWith (params, "p:") == 0)
{
params += 2;
break;
}
while (*params != 0 && *params != ';')
params++;
if (*params == 0)
params = NULL;
else
params++;
}
if (params == NULL) /* Clock profiling not specified */
return COL_ERROR_PROFINIT;
TprintfT (0, "clockprof: open_experiment %s -- %s\n", exp, params);
int prof_interval = CALL_UTIL (strtol)(params, NULL, 0);
prof_key = collector_interface->createKey (sizeof ( int), NULL, NULL);
if (prof_key == (unsigned) - 1)
{
Tprintf (0, "clockprof: ERROR: TSD key create failed.\n");
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n", SP_JCMD_CERROR, COL_ERROR_PROFINIT);
return COL_ERROR_PROFINIT;
}
/* set dispatcher interval timer period used for all timed activities */
int prof_interval_actual = __collector_ext_itimer_set (prof_interval);
TprintfT (0, "clockprof: open_experiment(): __collector_ext_itimer_set (actual period=%d, req_period=%d)\n",
prof_interval_actual, prof_interval);
if (prof_interval_actual <= 0)
{
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">itimer could not be set</event>\n", SP_JCMD_CERROR, COL_ERROR_PROFINIT);
return COL_ERROR_PROFINIT;
}
if ((prof_interval_actual >= (prof_interval + prof_interval / 10)) ||
(prof_interval_actual <= (prof_interval - prof_interval / 10)))
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n", SP_JCMD_CWARN, COL_WARN_PROFRND, prof_interval, prof_interval_actual);
else if (prof_interval_actual != prof_interval)
collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n", SP_JCMD_COMMENT, COL_WARN_PROFRND, prof_interval, prof_interval_actual);
prof_interval = prof_interval_actual;
collector_interface->writeLog ("<profile name=\"%s\" ptimer=\"%d\" numstates=\"%d\">\n",
SP_JCMD_PROFILE, prof_interval, LMS_MAGIC_ID_LINUX);
collector_interface->writeLog (" <profdata fname=\"%s\"/>\n",
module_interface.description);
/* Record Profile packet description */
ClockPacket *cp = NULL;
collector_interface->writeLog (" <profpckt kind=\"%d\" uname=\"" STXT ("Clock profiling data") "\">\n", CLOCK_TYPE);
collector_interface->writeLog (" <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n",
&cp->lwp_id, sizeof (cp->lwp_id) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n",
&cp->thr_id, sizeof (cp->thr_id) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n",
&cp->cpu_id, sizeof (cp->cpu_id) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n",
&cp->tstamp, sizeof (cp->tstamp) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
&cp->frinfo, sizeof (cp->frinfo) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"MSTATE\" uname=\"" STXT ("Thread state") "\" offset=\"%d\" type=\"%s\"/>\n",
&cp->mstate, sizeof (cp->mstate) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" <field name=\"NTICK\" uname=\"" STXT ("Duration") "\" offset=\"%d\" type=\"%s\"/>\n",
&cp->nticks, sizeof (cp->nticks) == 4 ? "INT32" : "INT64");
collector_interface->writeLog (" </profpckt>\n");
collector_interface->writeLog ("</profile>\n");
return COL_ERROR_NONE;
}
static int
start_data_collection (void)
{
TprintfT (0, "clockprof: start_data_collection\n");
prof_mode = 1;
return 0;
}
static int
stop_data_collection (void)
{
prof_mode = 0;
TprintfT (0, "clockprof: stop_data_collection\n");
return 0;
}
static int
close_experiment (void)
{
prof_mode = 0;
prof_key = COLLECTOR_TSD_INVALID_KEY;
TprintfT (0, "clockprof: close_experiment\n");
return 0;
}
/* fork child. Clean up state but don't write to experiment */
static int
detach_experiment (void)
{
prof_mode = 0;
prof_key = COLLECTOR_TSD_INVALID_KEY;
TprintfT (0, "clockprof: detach_experiment\n");
return 0;
}
/*
* void collector_lost_profile_context
* Placeholder/marker function used when profiling given NULL context.
*/
void
__collector_lost_profile_context (void) { }
/*
* void __collector_ext_profile_handler( siginfo_t *info, ucontext_t *context )
* Handle real profile events to collect profile data.
*/
void
__collector_ext_profile_handler (siginfo_t *info, ucontext_t *context)
{
int *guard;
if (!prof_mode) /* sigprof timer running only because hwprofile.c needs it */
return;
if (CHCK_REENTRANCE (guard))
{
TprintfT (0, "__collector_ext_profile_handler: ERROR: prof_mode=%d guard=%d!\n",
prof_mode, guard ? *guard : -2);
return;
}
PUSH_REENTRANCE (guard);
TprintfT (DBG_LT3, "__collector_ext_profile_handler\n");
ucontext_t uctxmem;
if (context == NULL)
{
/* assume this case is rare, and accept overhead of creating dummy_uc */
TprintfT (0, "collector_profile_handler: ERROR: got NULL context!\n");
context = &uctxmem;
getcontext (context); /* initialize dummy context */
SETFUNCTIONCONTEXT (context, &__collector_lost_profile_context);
}
ClockPacket pckt;
CALL_UTIL (memset)(&pckt, 0, sizeof ( pckt));
pckt.comm.tsize = sizeof ( pckt);
pckt.comm.type = CLOCK_TYPE;
pckt.lwp_id = __collector_lwp_self ();
pckt.thr_id = __collector_thr_self ();
pckt.cpu_id = CALL_UTIL (getcpuid)();
pckt.tstamp = collector_interface->getHiResTime ();
pckt.frinfo = collector_interface->getFrameInfo (COLLECTOR_MODULE_ERR, pckt.tstamp, FRINFO_FROM_UC, context);
pckt.mstate = LMS_LINUX_CPU;
pckt.nticks = 1;
collector_interface->writeDataPacket (prof_hndl, (CM_Packet*) & pckt);
POP_REENTRANCE (guard);
}

File diff suppressed because it is too large Load diff

149
gprofng/libcollector/tsd.c Normal file
View file

@ -0,0 +1,149 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <pthread.h>
#include "collector.h"
#include "libcol_util.h"
#include "tsd.h"
#include "memmgr.h"
/* TprintfT(<level>,...) definitions. Adjust per module as needed */
#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
#define DBG_LT1 1 // for configuration details, warnings
#define DBG_LT2 2
#define DBG_LT3 3
/*
* Build our thread-specific-data support on pthread interfaces.
*/
#define MAXNKEYS 64 /* hard-wired? really? well, it depends only on us and we have a sense for how many keys we will use */
static pthread_key_t tsd_pkeys[MAXNKEYS];
static size_t tsd_sizes[MAXNKEYS];
static unsigned tsd_nkeys = 0;
int
__collector_tsd_init ()
{
return 0;
}
void
__collector_tsd_fini ()
{
Tprintf (DBG_LT1, "tsd_fini()\n");
while (tsd_nkeys)
{
tsd_nkeys--;
pthread_key_delete (tsd_pkeys[tsd_nkeys]);
tsd_sizes[tsd_nkeys] = 0; // should be unneeded
}
}
int
__collector_tsd_allocate ()
{
return 0;
}
void
__collector_tsd_release () { }
static void
tsd_destructor (void *p)
{
if (p)
__collector_freeCSize (__collector_heap, p, *((size_t *) p));
}
unsigned
__collector_tsd_create_key (size_t sz, void (*init)(void*), void (*fini)(void*))
{
/*
* We no longer support init and fini arguments (and weren't using them anyhow).
* Our hard-wired MAXNKEYS presumably is considerably higher than the number of keys we use.
*/
if (init || fini || (tsd_nkeys >= MAXNKEYS))
return COLLECTOR_TSD_INVALID_KEY;
/*
* A pthread key has a value that is (void *).
* We don't know where it is stored, and can access its value only through {get|set}specific.
* But libcollector expects a pointer to memory that it can modify.
* So we have to allocate that memory and store the pointer.
*
* For now, we just have to register a destructor that will free the memory
* when the thread finishes.
*/
if (pthread_key_create (&tsd_pkeys[tsd_nkeys], &tsd_destructor))
return COLLECTOR_TSD_INVALID_KEY;
tsd_sizes[tsd_nkeys] = sz;
tsd_nkeys++;
return (tsd_nkeys - 1);
}
void *
__collector_tsd_get_by_key (unsigned key_index)
{
if (key_index == COLLECTOR_TSD_INVALID_KEY)
return NULL;
if (key_index < 0 || key_index >= tsd_nkeys)
return NULL;
pthread_key_t key = tsd_pkeys[key_index];
size_t sz = tsd_sizes[key_index];
/*
* When we use __collector_freeCSize(), we need to know the
* size that had been allocated. So, stick a header to the
* front of the allocation to hold the size. The header could
* just be sizeof(size_t), but pad it to preserve alignment for
* the usable area.
*/
size_t header = 8;
void *value = pthread_getspecific (key);
// check whether we have allocated the memory
if (value == NULL)
{
// add room to record the size
value = __collector_allocCSize (__collector_heap, sz + header, 0);
if (value == NULL)
{
// do we need to guard against trying to alloc each time?
return NULL;
}
// write the size of the allocation
*((size_t *) value) = sz + header;
CALL_UTIL (memset)(((char *) value) + header, 0, sz);
// record the allocation for future retrieval
if (pthread_setspecific (key, value))
return NULL;
}
// return the pointer, skipping the header
return ((char *) value) +header;
}
void
__collector_tsd_fork_child_cleanup ()
{
__collector_tsd_fini ();
}

View file

@ -0,0 +1,80 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/* Thread-specific data */
#ifndef _TSD_H
#define _TSD_H
#include <sys/types.h>
int __collector_tsd_init ();
/* Function: Init tsd module. Call once before using other functions.
MT-Level: Unsafe
Return: 0 if successful
*/
void __collector_tsd_fini ();
/* Function: Shutdown tsd module.
MT-Level: Unsafe
Return: None
*/
void __collector_tsd_fork_child_cleanup ();
/* Function: Reset tsd module. Call immediately after fork() in child process.
MT-Level: Unsafe
Return: None
*/
int __collector_tsd_allocate ();
/* Function: Allocate thread info.
Call from threads before using tsd_get_by_key().
Call from main thread should be made before calls from other threads.
MT-Level: First call is unsafe. Safe afterwards.
Return: 0 if successful
*/
void __collector_tsd_release ();
/* Function: Free thread info.
Call from threads just before thread termination.
MT-Level: Safe
Return: None
*/
#define COLLECTOR_TSD_INVALID_KEY ((unsigned)-1)
unsigned __collector_tsd_create_key (size_t memsize, void (*init)(void*), void (*fini)(void*));
/* Function: Reserve TDS memory.
MT-Level: Unsafe
Inputs: <memsize>: number of bytes to reserve
<init>: key memory initialization. Must be callable even if
the associated thread has not yet been created.
<fini>: key memory finalization. Must be callable even if
the associated thread has been terminated.
Return: key or COLLECTOR_TSD_INVALID_KEY if not successful.
*/
void *__collector_tsd_get_by_key (unsigned key);
/* Function: Get TSD memory.
Call from threads after calling tsd_allocate().
MT-Level: Safe
Inputs: <key>: return value from tsd_create_key()
Return: memory if successful, NULL otherwise
*/
#endif /* _TSD_H */

File diff suppressed because it is too large Load diff

62
gprofng/src/ABS.h Normal file
View file

@ -0,0 +1,62 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _ABS_H
#define _ABS_H
/*
* Apropos Backtracking Scheme definitions.
* Class: com_sun_forte_st_mpmt_timeline_HWCEvent
*/
/* ABS failure codes */
typedef enum
{
ABS_NULL = 0x00, /* undefined/disabled/inactive */
ABS_UNSUPPORTED = 0x01, /* inappropriate HWC event type */
ABS_BLOCKED = 0x02, /* runtime backtrack blocker reached */
ABS_INCOMPLETE = 0x03, /* runtime backtrack limit reached */
ABS_REG_LOSS = 0x04, /* address register contaminated */
ABS_INVALID_EA = 0x05, /* invalid effective address value */
ABS_NO_CTI_INFO = 0x10, /* no AnalyzerInfo for validation */
ABS_INFO_FAILED = 0x20, /* info failed to validate backtrack */
ABS_CTI_TARGET = 0x30, /* CTI target invalidated backtrack */
ABS_CODE_RANGE = 0xFF /* reserved ABS code range in Vaddr */
} ABS_code;
enum {
NUM_ABS_RT_CODES = 7,
NUM_ABS_PP_CODES = 5
};
extern const char *ABS_RT_CODES[NUM_ABS_RT_CODES];
extern char *ABS_PP_CODES[NUM_ABS_PP_CODES];
/* libcollector will mark HWC overflow values that appear to be invalid */
/* dbe should check HWC values for errors */
#define HWCVAL_ERR_FLAG (1ULL<<63)
#define HWCVAL_SET_ERR(ctr) ((ctr) | HWCVAL_ERR_FLAG)
#define HWCVAL_HAS_ERR(ctr) ((ctr) & HWCVAL_ERR_FLAG ? 1 : 0)
#define HWCVAL_CLR_ERR(ctr) ((ctr) & ~HWCVAL_ERR_FLAG)
#define ABS_GET_RT_CODE(EA) ((EA) & 0x0FLL)
#define ABS_GET_PP_CODE(EA) (((EA) & 0xF0LL) / 0xF)
#endif /* _ABS_H */

259
gprofng/src/Application.cc Normal file
View file

@ -0,0 +1,259 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <stdlib.h>
#include <strings.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include "Application.h"
#include "Settings.h"
#include "i18n.h"
#include "util.h"
Application::ProgressFunc Application::progress_func = NULL;
Application *theApplication;
Application::Application (int argc, char *argv[], char *fdhome)
{
theApplication = this;
cur_dir = NULL;
prog_version = dbe_strdup (VERSION);
set_name (strchr (argv[0], '/') ? argv[0] : NULL);
whoami = get_basename (get_name ());
// set up a queue for comments
commentq = new Emsgqueue (NTXT ("app_commentq"));
// Locate where the binaries are installed
set_run_dir (fdhome);
// Initialize I18N
init_locale (run_dir);
// Initialize licensing data
lic_found = 0;
lic_err = NULL;
// Initialize worker threads
number_of_worker_threads = 1;
#if DEBUG
char *use_worker_threads = getenv (NTXT ("SP_USE_WORKER_THREADS"));
if ((NULL != use_worker_threads) && (0 == strcasecmp (use_worker_threads, NTXT ("no"))))
{
number_of_worker_threads = 0;
}
#endif /* DEBUG */
settings = new Settings (this);
}
Application::~Application ()
{
delete commentq;
delete settings;
free (prog_version);
free (cur_dir);
free (prog_name);
free (run_dir);
}
// Set the name of the application (for messages)
void
Application::set_name (const char *_name)
{
prog_name = get_realpath (_name);
}
char *
Application::get_realpath (const char *_name)
{
if (_name == NULL)
_name = "/proc/self/exe";
char *exe_name = realpath (_name, NULL);
if (exe_name)
return exe_name;
if (strchr (_name, '/') == NULL)
{
char *path = getenv ("PATH");
if (path)
for (char *s = path;; s++)
if (*s == ':' || *s == 0)
{
if (path != s)
{
char *nm = dbe_sprintf (NTXT ("%.*s/%s"), (int) (path - s - 1), path, _name);
exe_name = realpath (nm, NULL);
free (nm);
if (exe_name)
return exe_name;
}
if (*s == 0)
break;
path = s + 1;
}
}
return strdup (_name);
}
// Set the directory where all binaries are found
void
Application::set_run_dir (char *fdhome)
{
run_dir_with_spaces = NULL;
if (fdhome)
{
char *path = dbe_sprintf ("%s/bin", fdhome);
struct stat sbuf;
if (stat (path, &sbuf) != -1)
run_dir = path;
else
{
free (path);
run_dir = dbe_strdup (fdhome);
}
}
else
{
run_dir = realpath (prog_name, NULL);
if (run_dir == NULL)
{
fprintf (stderr, // I18N won't work here -- not catopen yet.
GTXT ("Can't find location of %s\n"), prog_name);
run_dir = dbe_strdup (get_cur_dir ());
}
else
{
char *d = strrchr (run_dir, '/');
if (d)
*d = 0;
// Check if the installation path contains spaces
if (strchr (run_dir, ' ') != NULL)
{
// Create a symbolic link without spaces
const char *dir = NTXT ("/tmp/.gprofngLinks");
char *symbolic_link = dbe_create_symlink_to_path (run_dir, dir);
if (NULL != symbolic_link)
{
// Save old path to avoid memory leak
run_dir_with_spaces = run_dir;
// Use the path through symbolic link
run_dir = symbolic_link;
}
}
}
}
}
char *
Application::get_cur_dir ()
{
if (cur_dir == NULL)
{
char cwd[MAXPATHLEN];
if (getcwd (cwd, sizeof (cwd)) == NULL)
{
perror (prog_name);
exit (1);
}
cur_dir = dbe_strdup (canonical_path (cwd));
}
return cur_dir;
}
/**
* Get number of worker threads
* This is used to decide if it is ok to use worker threads for stat()
* and other actions that can hang for a long time
* @return number_of_worker_threads
*/
int
Application::get_number_of_worker_threads ()
{
return number_of_worker_threads;
}
int
Application::check_args (int argc, char *argv[])
{
int opt;
// Parsing the command line
opterr = 0;
while ((opt = getopt (argc, argv, "V")) != EOF)
switch (opt)
{
case 'V':
// Ruud
Application::print_version_info ();
/*
printf (NTXT ("GNU %s version %s\n"), get_basename (prog_name), VERSION);
*/
exit (0);
default:
usage ();
}
return optind;
}
Emsg *
Application::fetch_comments ()
{
if (commentq == NULL)
return NULL;
return commentq->fetch ();
}
void
Application::queue_comment (Emsg *m)
{
commentq->append (m);
}
void
Application::delete_comments ()
{
if (commentq != NULL)
{
delete commentq;
commentq = new Emsgqueue (NTXT ("app_commentq"));
}
}
int
Application::set_progress (int percentage, const char *proc_str)
{
if (progress_func != NULL)
return progress_func (percentage, proc_str);
return 0;
}
// Ruud
void
Application::print_version_info ()
{
printf ( GTXT (
"GNU %s binutils version %s\n"
"Copyright (C) 2021 Free Software Foundation, Inc.\n"
"License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.\n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n"),
get_basename (prog_name), VERSION);
}

108
gprofng/src/Application.h Normal file
View file

@ -0,0 +1,108 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/*
* The Application class is the base class for all C++ executables
* in the Performance Tools Suite
*
* It determines the directory from which the running binary came,
* sets up the I18N catalog, the program name, and initializes
* an instance of the Settings class to manage all user preferences
* and settings. It also manages usage tracking.
*
* Applications which read experiments are derived from a subclass
* named DbeApplication (q.v.)
*/
#ifndef _APPLICATION_H
#define _APPLICATION_H
#include "dbe_types.h"
class Settings;
class Emsg;
class Emsgqueue;
// Application object
class Application
{
public:
Application (int argc, char *argv[], char *_run_dir = NULL);
virtual ~Application ();
void set_name (const char *_name);
char *get_cur_dir ();
// Control the settings of a progress bar, used for GUI applications
// this function also detects cancel requests and returns 1
// if yes, 0 otherwise
static int set_progress (int percentage, const char *proc_str);
static char *get_realpath (const char *_name);
// queue for messages (from reading er.rc files, ...)
void queue_comment (Emsg *m); // queue for messages
Emsg *fetch_comments (void); // fetch the queue of comment messages
void delete_comments (void); // delete the queue of comment messages
// worker threads (currently used in dbe_stat() for stat() calls)
int get_number_of_worker_threads ();
char *get_version () { return prog_version; }
char *get_name () { return prog_name; }
char *get_run_dir () { return run_dir; }
Emsgqueue *get_comments_queue () { return commentq; };
protected: // methods
void set_run_dir (char *fdhome = NULL);
typedef int (*ProgressFunc)(int, const char *);
// Write a usage message; to be defined in derived class
virtual void usage () = 0;
// Ruud
// Write a version message; to be defined in derived class
void print_version_info ();
// Can be overridden in derived class
virtual int check_args (int argc, char *argv[]);
void read_rc ();
static void set_progress_func (ProgressFunc func) { progress_func = func; }
protected:
Emsgqueue *commentq;
Settings *settings;
char *prog_version;
char *prog_name;
char *whoami;
char *run_dir;
char *run_dir_with_spaces; // used in case there are spaces
char *cur_dir;
int lic_found;
char *lic_err;
private:
void set_ut_email (int argc, char *argv[]);
int number_of_worker_threads;
static ProgressFunc progress_func;
};
extern Application *theApplication;
#endif /* _APPLICATION_H */

149
gprofng/src/ArchiveExp.cc Normal file
View file

@ -0,0 +1,149 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <stdio.h>
#include <unistd.h>
#include "util.h"
#include "DbeSession.h"
#include "LoadObject.h"
#include "ArchiveExp.h"
#include "DbeFile.h"
#include "CallStack.h"
#include "gp-archive.h"
#include "Function.h"
#include "Module.h"
ArchiveExp::ArchiveExp (char *path) : Experiment ()
{
force_flag = false;
copyso_flag = false;
use_fndr_archives = true;
status = find_expdir (path);
if (status == SUCCESS)
read_log_file ();
}
ArchiveExp::~ArchiveExp () { }
void
ArchiveExp::read_data (int s_option)
{
read_archives ();
read_map_file ();
if (read_java_classes_file () == SUCCESS)
{
for (int i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
{
LoadObject *lo = loadObjs->get (i);
Dprintf (DEBUG_ARCHIVE, NTXT ("%s:%d loadObjs[%d]=%-25s %s\n"),
get_basename (__FILE__), (int) __LINE__, i,
STR (lo->get_name ()), STR (lo->get_pathname ()));
if ((lo->dbeFile->filetype & DbeFile::F_JAVACLASS) == 0)
continue;
lo->isUsed = true;
if ((s_option & ARCH_EXE_ONLY) != 0)
continue;
lo->sync_read_stabs ();
}
}
if ((s_option & (ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY)) != 0)
{
read_frameinfo_file ();
resolveFrameInfo = true;
Vector<DataDescriptor*> *ddscr = getDataDescriptors ();
delete ddscr; // getDataDescriptors() forces reading of experiment data
CallStack *callStack = callTree ();
if (callStack)
{
if (DEBUG_ARCHIVE)
{
Dprintf (DEBUG_ARCHIVE, NTXT ("stacks=%p\n"), callStack);
callStack->print (NULL);
}
for (int n = 0;; n++)
{
CallStackNode *node = callStack->get_node (n);
if (node == NULL)
break;
do
{
Histable *h = node->get_instr ();
Histable::Type t = h->get_type ();
if (t == Histable::INSTR)
{
DbeInstr *dbeInstr = (DbeInstr *) h;
if (!dbeInstr->isUsed)
{
Function *func = (Function *) dbeInstr->convertto (Histable::FUNCTION);
if (!func->isUsed)
{
func->isUsed = true;
func->module->isUsed = true;
func->module->loadobject->isUsed = true;
}
DbeLine *dbeLine = (DbeLine *) dbeInstr->convertto (Histable::LINE);
if (dbeLine)
dbeLine->sourceFile->isUsed = true;
}
}
else if (t == Histable::LINE)
{
DbeLine * dbeLine = (DbeLine *) h;
dbeLine->sourceFile->isUsed = true;
}
node = node->ancestor;
}
while (node);
}
}
}
}
char *
ArchiveExp::createLinkToFndrArchive (LoadObject *lo, int /* hide_msg */)
{
// For example, archives of libc.so will be:
// <exp>/archives/<libc.so_check_sum>
// <exp>/M_r0.er/archives/libc.so_<hash> -> ../../archives/<libc.so_check_sum>
if (!create_dir (get_fndr_arch_name ()))
{
fprintf (stderr, GTXT ("Unable to create directory `%s'\n"), get_fndr_arch_name ());
return NULL;
}
uint32_t checksum = lo->get_checksum ();
char *linkName = dbe_sprintf (NTXT ("../../%s/%u"), SP_ARCHIVES_DIR, checksum);
char *nm = lo->get_pathname ();
char *symLinkName = getNameInArchive (nm, false);
if (symlink (linkName, symLinkName) != 0)
{
fprintf (stderr, GTXT ("Unable to create link `%s' -> `%s'\n"),
symLinkName, linkName);
free (linkName);
free (symLinkName);
return NULL;
}
free (linkName);
free (symLinkName);
// Return a full path inside founder archive:
return dbe_sprintf (NTXT ("%s/%u"), get_fndr_arch_name (), checksum);
}

41
gprofng/src/ArchiveExp.h Normal file
View file

@ -0,0 +1,41 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _ARCHIVE_EXP_H
#define _ARCHIVE_EXP_H
#include "Experiment.h"
class LoadObject;
class ArchiveExp : public Experiment
{
public:
ArchiveExp (char *path);
~ArchiveExp ();
char *createLinkToFndrArchive (LoadObject *lo, int hide_msg);
void read_data (int s_option);
private:
bool force_flag;
bool copyso_flag;
bool use_fndr_archives;
};
#endif /* _ARCHIVE_EXP_H */

975
gprofng/src/BaseMetric.cc Normal file
View file

@ -0,0 +1,975 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <strings.h>
#include <stdlib.h>
#include "util.h"
#include "BaseMetric.h"
#include "DbeSession.h"
#include "Expression.h"
int BaseMetric::last_id = 0;
void
BaseMetric::init (Type t)
{
id = last_id++;
type = t;
aux = NULL;
cmd = NULL;
username = NULL;
hw_ctr = NULL;
cond = NULL;
val = NULL;
expr = NULL;
cond_spec = NULL;
val_spec = NULL;
expr_spec = NULL;
legend = NULL;
definition = NULL;
dependent_bm = NULL;
zeroThreshold = 0;
clock_unit = (Presentation_clock_unit) 0;
for (int ii = 0; ii < NSUBTYPES; ii++)
default_visbits[ii] = VAL_NA;
valtype = VT_DOUBLE;
precision = METRIC_HR_PRECISION;
flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
value_styles = VAL_TIMEVAL | VAL_PERCENT;
}
BaseMetric::BaseMetric (Type t)
{
init (t);
switch (t)
{
case CP_LMS_USER:
case CP_LMS_SYSTEM:
case CP_LMS_WAIT_CPU:
case CP_LMS_USER_LOCK:
case CP_LMS_TFAULT:
case CP_LMS_DFAULT:
case OMP_MASTER_THREAD:
case CP_TOTAL:
case CP_TOTAL_CPU:
case CP_LMS_TRAP:
case CP_LMS_KFAULT:
case CP_LMS_SLEEP:
case CP_LMS_STOPPED:
case OMP_NONE:
case OMP_OVHD:
case OMP_WORK:
case OMP_IBAR:
case OMP_EBAR:
case OMP_WAIT:
case OMP_SERL:
case OMP_RDUC:
case OMP_LKWT:
case OMP_CTWT:
case OMP_ODWT:
case OMP_MSTR:
case OMP_SNGL:
case OMP_ORDD:
case CP_KERNEL_CPU:
// all of these are floating point, precision = clock profile tick
valtype = VT_DOUBLE;
precision = METRIC_SIG_PRECISION;
flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
value_styles = VAL_TIMEVAL | VAL_PERCENT;
break;
case SYNC_WAIT_TIME:
case IO_READ_TIME:
case IO_WRITE_TIME:
case IO_OTHER_TIME:
case IO_ERROR_TIME:
// all of these are floating point, precision = hrtime tick
valtype = VT_DOUBLE;
precision = METRIC_HR_PRECISION;
flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
value_styles = VAL_TIMEVAL | VAL_PERCENT;
break;
case SYNC_WAIT_COUNT:
case HEAP_ALLOC_CNT:
case HEAP_LEAK_CNT:
case IO_READ_CNT:
case IO_WRITE_CNT:
case IO_OTHER_CNT:
case IO_ERROR_CNT:
valtype = VT_LLONG;
precision = 1;
flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
value_styles = VAL_VALUE | VAL_PERCENT;
break;
case RACCESS:
case DEADLOCKS:
// all of these are integer
valtype = VT_LLONG;
precision = 1;
flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
value_styles = VAL_VALUE | VAL_PERCENT;
zeroThreshold = 1;
break;
case HEAP_ALLOC_BYTES:
case HEAP_LEAK_BYTES:
case IO_READ_BYTES:
case IO_WRITE_BYTES:
// all of these are longlong
valtype = VT_ULLONG;
precision = 1;
flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
value_styles = VAL_VALUE | VAL_PERCENT;
break;
case SIZES:
valtype = VT_LLONG;
precision = 1;
flavors = STATIC;
value_styles = VAL_VALUE;
break;
case ADDRESS:
valtype = VT_ADDRESS;
precision = 1;
flavors = STATIC;
value_styles = VAL_VALUE;
break;
case ONAME:
valtype = VT_LABEL;
precision = 0;
flavors = STATIC;
value_styles = VAL_VALUE;
break;
case HWCNTR: // We should call the other constructor for hwc metric
default:
abort ();
}
specify ();
}
// Constructor for linked HW counters (base counter)
BaseMetric::BaseMetric (Hwcentry *ctr, const char* _aux, const char* _username,
int v_styles, BaseMetric* _dependent_bm)
{
hwc_init (ctr, _aux, _aux, _username, v_styles);
dependent_bm = _dependent_bm;
}
// Constructor for linked HW counters (derived counter)
BaseMetric::BaseMetric (Hwcentry *ctr, const char *_aux, const char *_cmdname,
const char *_username, int v_styles)
{
hwc_init (ctr, _aux, _cmdname, _username, v_styles);
}
void
BaseMetric::hwc_init (Hwcentry *ctr, const char* _aux, const char* _cmdname,
const char* _username, int v_styles)
{
init (HWCNTR);
aux = dbe_strdup (_aux); // HWC identifier
cmd = dbe_strdup (_cmdname); // may differ from _aux for cycles->time hwcs
username = dbe_strdup (_username);
flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
value_styles = v_styles | VAL_PERCENT;
if ((value_styles & (VAL_TIMEVAL | VAL_VALUE)) == VAL_TIMEVAL)
valtype = VT_DOUBLE;
else
valtype = VT_ULLONG;
if (ABST_MEMSPACE_ENABLED (ctr->memop))
flavors |= DATASPACE; // only for ctrs with memop definitions
hw_ctr = ctr;
specify ();
}
// Constructor for derived metrics
BaseMetric::BaseMetric (const char *_cmd, const char *_username,
Definition *def)
{
init (DERIVED);
cmd = dbe_strdup (_cmd);
username = dbe_strdup (_username);
aux = dbe_strdup (_cmd);
definition = def;
flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
clock_unit = CUNIT_NULL; // should it be CUNIT_TIME or 0 or something?
/* we're not going to process packets for derived metrics */
packet_type = (ProfData_type) (-1);
value_styles = VAL_VALUE;
valtype = VT_DOUBLE;
precision = 1000;
}
// Copy constructor
BaseMetric::BaseMetric (const BaseMetric& m)
{
id = m.id;
type = m.type;
aux = dbe_strdup (m.aux);
cmd = dbe_strdup (m.cmd);
username = dbe_strdup (m.username);
flavors = m.flavors;
value_styles = m.value_styles;
valtype = m.valtype;
precision = m.precision;
hw_ctr = m.hw_ctr;
packet_type = m.packet_type;
zeroThreshold = m.zeroThreshold;
clock_unit = m.clock_unit;
for (int ii = 0; ii < NSUBTYPES; ii++)
default_visbits[ii] = m.default_visbits[ii];
if (m.cond_spec)
{
cond_spec = strdup (m.cond_spec);
cond = m.cond->copy ();
}
else
{
cond = NULL;
cond_spec = NULL;
}
if (m.val_spec)
{
val_spec = strdup (m.val_spec);
val = m.val->copy ();
}
else
{
val = NULL;
val_spec = NULL;
}
if (m.expr_spec)
{
expr_spec = strdup (m.expr_spec);
expr = m.expr->copy ();
}
else
{
expr = NULL;
expr_spec = NULL;
}
legend = dbe_strdup (m.legend);
definition = NULL;
if (m.definition)
definition = Definition::add_definition (m.definition->def);
dependent_bm = m.dependent_bm;
}
BaseMetric::~BaseMetric ()
{
free (aux);
free (cmd);
free (cond_spec);
free (val_spec);
free (expr_spec);
free (legend);
free (username);
delete cond;
delete val;
delete expr;
delete definition;
}
bool
BaseMetric::is_internal ()
{
return (get_value_styles () & VAL_INTERNAL) != 0;
}
int
BaseMetric::get_default_visbits (SubType subtype)
{
int rc = VAL_NA;
switch (subtype)
{
case STATIC:
case EXCLUSIVE:
rc = default_visbits[0];
break;
case INCLUSIVE:
rc = default_visbits[1];
break;
default:
break;
}
return rc;
}
void
BaseMetric::set_default_visbits (SubType subtype, int _visbits)
{
switch (subtype)
{
case STATIC:
case EXCLUSIVE:
default_visbits[0] = _visbits;
break;
case INCLUSIVE:
default_visbits[1] = _visbits;
break;
default:
break;
}
}
void
BaseMetric::set_cond_spec (char *_cond_spec)
{
if (cond_spec)
{
free (cond_spec);
delete cond;
cond_spec = NULL;
cond = NULL;
}
if (_cond_spec)
{
cond = dbeSession->ql_parse (_cond_spec);
if (cond == NULL)
{
fprintf (stderr, GTXT ("Invalid expression in metric specification `%s'\n"), _cond_spec);
abort ();
}
cond_spec = dbe_strdup (_cond_spec);
}
}
void
BaseMetric::set_val_spec (char *_val_spec)
{
if (val_spec)
{
free (val_spec);
delete val;
val_spec = NULL;
val = NULL;
}
if (_val_spec)
{
val = dbeSession->ql_parse (_val_spec);
if (val == NULL)
{
fprintf (stderr, GTXT ("Invalid expression in metric specification `%s'\n"), _val_spec);
abort ();
}
val_spec = dbe_strdup (_val_spec);
}
}
void
BaseMetric::set_expr_spec (char *_expr_spec)
{
id = last_id++;
if (expr_spec)
{
free (expr_spec);
delete expr;
expr_spec = NULL;
expr = NULL;
}
if (_expr_spec)
{
expr = dbeSession->ql_parse (_expr_spec);
if (expr == NULL)
{
fprintf (stderr, GTXT ("Invalid expression in metric specification `%s'\n"), _expr_spec);
return;
}
expr_spec = dbe_strdup (_expr_spec);
}
}
void
BaseMetric::specify_mstate_metric (int st)
{
char buf[128];
snprintf (buf, sizeof (buf), NTXT ("MSTATE==%d"), st);
specify_prof_metric (buf);
}
void
BaseMetric::specify_ompstate_metric (int st)
{
char buf[128];
snprintf (buf, sizeof (buf), NTXT ("OMPSTATE==%d"), st);
specify_prof_metric (buf);
}
void
BaseMetric::specify_prof_metric (char *_cond_spec)
{
packet_type = DATA_CLOCK;
specify_metric (_cond_spec, NTXT ("NTICK_USEC")); // microseconds
}
void
BaseMetric::specify_metric (char *_cond_spec, char *_val_spec)
{
set_cond_spec (_cond_spec);
set_val_spec (_val_spec);
}
void
BaseMetric::specify ()
{
enum
{
IDLE_STATE_BITS =
(1 << OMP_IDLE_STATE) | (1 << OMP_IBAR_STATE) | (1 << OMP_EBAR_STATE) |
(1 << OMP_LKWT_STATE) | (1 << OMP_CTWT_STATE) | (1 << OMP_ODWT_STATE) |
(1 << OMP_ATWT_STATE) | (1 << OMP_TSKWT_STATE),
LMS_USER_BITS =
(1 << OMP_NO_STATE) | (1 << OMP_WORK_STATE) | (1 << OMP_SERL_STATE) |
(1 << OMP_RDUC_STATE)
};
char buf[256];
char buf2[256];
packet_type = (ProfData_type) - 1; // illegal value
clock_unit = CUNIT_TIME;
switch (type)
{
case SIZES:
username = dbe_strdup (GTXT ("Size"));
clock_unit = CUNIT_BYTES;
cmd = dbe_strdup (NTXT ("size"));
break;
case ADDRESS:
username = dbe_strdup (GTXT ("PC Address"));
cmd = dbe_strdup (NTXT ("address"));
break;
case ONAME:
username = dbe_strdup (GTXT ("Name"));
cmd = dbe_strdup (NTXT ("name"));
break;
case CP_LMS_SYSTEM:
username = dbe_strdup (GTXT ("System CPU Time"));
specify_mstate_metric (LMS_SYSTEM);
cmd = dbe_strdup (NTXT ("system"));
break;
case CP_TOTAL_CPU:
username = dbe_strdup (GTXT ("Total CPU Time"));
snprintf (buf, sizeof (buf),
"(MSTATE==%d)||(MSTATE==%d)||(MSTATE==%d)||(MSTATE==%d)",
LMS_USER, LMS_SYSTEM, LMS_TRAP, LMS_LINUX_CPU);
specify_prof_metric (buf);
cmd = dbe_strdup (NTXT ("totalcpu"));
break;
case CP_TOTAL:
username = dbe_strdup (GTXT ("Total Thread Time"));
snprintf (buf, sizeof (buf), NTXT ("(MSTATE!=%d)&&(MSTATE!=%d)"),
LMS_KERNEL_CPU, LMS_LINUX_CPU);
specify_prof_metric (buf);
cmd = dbe_strdup (NTXT ("total"));
break;
case CP_KERNEL_CPU:
username = dbe_strdup (GTXT ("Kernel CPU Time"));
specify_mstate_metric (LMS_KERNEL_CPU);
cmd = dbe_strdup (NTXT ("kcpu"));
break;
case OMP_MASTER_THREAD:
username = dbe_strdup (GTXT ("Master Thread Time"));
specify_prof_metric (NTXT ("LWPID==1"));
cmd = dbe_strdup (NTXT ("masterthread"));
break;
case CP_LMS_USER:
username = dbe_strdup (GTXT ("User CPU Time"));
specify_mstate_metric (LMS_USER);
cmd = dbe_strdup (NTXT ("user"));
break;
case CP_LMS_WAIT_CPU:
username = dbe_strdup (GTXT ("Wait CPU Time"));
specify_mstate_metric (LMS_WAIT_CPU);
cmd = dbe_strdup (NTXT ("wait"));
break;
case CP_LMS_USER_LOCK:
username = dbe_strdup (GTXT ("User Lock Time"));
specify_mstate_metric (LMS_USER_LOCK);
cmd = dbe_strdup (NTXT ("lock"));
break;
case CP_LMS_TFAULT:
username = dbe_strdup (GTXT ("Text Page Fault Time"));
specify_mstate_metric (LMS_TFAULT);
cmd = dbe_strdup (NTXT ("textpfault"));
break;
case CP_LMS_DFAULT:
username = dbe_strdup (GTXT ("Data Page Fault Time"));
specify_mstate_metric (LMS_DFAULT);
cmd = dbe_strdup (NTXT ("datapfault"));
break;
case CP_LMS_TRAP:
username = dbe_strdup (GTXT ("Trap CPU Time"));
specify_mstate_metric (LMS_TRAP);
cmd = dbe_strdup (NTXT ("trap"));
break;
case CP_LMS_KFAULT:
username = dbe_strdup (GTXT ("Kernel Page Fault Time"));
specify_mstate_metric (LMS_KFAULT);
cmd = dbe_strdup (NTXT ("kernelpfault"));
break;
case CP_LMS_SLEEP:
username = dbe_strdup (GTXT ("Sleep Time"));
specify_mstate_metric (LMS_SLEEP);
cmd = dbe_strdup (NTXT ("sleep"));
break;
case CP_LMS_STOPPED:
username = dbe_strdup (GTXT ("Stopped Time"));
specify_mstate_metric (LMS_STOPPED);
cmd = dbe_strdup (NTXT ("stop"));
break;
case OMP_OVHD:
username = dbe_strdup (GTXT ("OpenMP Overhead Time"));
specify_ompstate_metric (OMP_OVHD_STATE);
cmd = dbe_strdup (NTXT ("ompovhd"));
break;
case OMP_WORK:
username = dbe_strdup (GTXT ("OpenMP Work Time"));
snprintf (buf, sizeof (buf),
NTXT ("(OMPSTATE>=0) && (MSTATE==%d) && ((1<<OMPSTATE) & %d)"),
LMS_USER, LMS_USER_BITS);
specify_prof_metric (buf);
cmd = dbe_strdup (NTXT ("ompwork"));
break;
case OMP_WAIT:
username = dbe_strdup (GTXT ("OpenMP Wait Time"));
snprintf (buf, sizeof (buf),
"OMPSTATE>=0 && ((1<<OMPSTATE) & ((MSTATE!=%d) ? %d : %d))",
LMS_USER, (LMS_USER_BITS | IDLE_STATE_BITS), IDLE_STATE_BITS);
specify_prof_metric (buf);
cmd = dbe_strdup (NTXT ("ompwait"));
break;
case OMP_IBAR:
username = dbe_strdup (GTXT ("OpenMP Implicit Barrier Time"));
specify_ompstate_metric (OMP_IBAR_STATE);
cmd = dbe_strdup (NTXT ("ompibar"));
break;
case OMP_EBAR:
username = dbe_strdup (GTXT ("OpenMP Explicit Barrier Time"));
specify_ompstate_metric (OMP_EBAR_STATE);
cmd = dbe_strdup (NTXT ("ompebar"));
break;
case OMP_SERL:
username = dbe_strdup (GTXT ("OpenMP Serial Time"));
specify_ompstate_metric (OMP_SERL_STATE);
cmd = dbe_strdup (NTXT ("ompserl"));
break;
case OMP_RDUC:
username = dbe_strdup (GTXT ("OpenMP Reduction Time"));
specify_ompstate_metric (OMP_RDUC_STATE);
cmd = dbe_strdup (NTXT ("omprduc"));
break;
case OMP_LKWT:
username = dbe_strdup (GTXT ("OpenMP Lock Wait Time"));
specify_ompstate_metric (OMP_LKWT_STATE);
cmd = dbe_strdup (NTXT ("omplkwt"));
break;
case OMP_CTWT:
username = dbe_strdup (GTXT ("OpenMP Critical Section Wait Time"));
specify_ompstate_metric (OMP_CTWT_STATE);
cmd = dbe_strdup (NTXT ("ompctwt"));
break;
case OMP_ODWT:
username = dbe_strdup (GTXT ("OpenMP Ordered Section Wait Time"));
specify_ompstate_metric (OMP_ODWT_STATE);
cmd = dbe_strdup (NTXT ("ompodwt"));
break;
case SYNC_WAIT_TIME:
packet_type = DATA_SYNCH;
username = dbe_strdup (GTXT ("Sync Wait Time"));
snprintf (buf, sizeof (buf), NTXT ("(EVT_TIME)/%lld"),
(long long) (NANOSEC / METRIC_HR_PRECISION));
specify_metric (NULL, buf);
cmd = dbe_strdup (NTXT ("sync"));
break;
case SYNC_WAIT_COUNT:
packet_type = DATA_SYNCH;
username = dbe_strdup (GTXT ("Sync Wait Count"));
specify_metric (NULL, NTXT ("1"));
cmd = dbe_strdup (NTXT ("syncn"));
break;
case HEAP_ALLOC_CNT:
packet_type = DATA_HEAP;
username = dbe_strdup (GTXT ("Allocations"));
snprintf (buf, sizeof (buf), NTXT ("(HTYPE!=%d)&&(HTYPE!=%d)&&HVADDR"),
FREE_TRACE, MUNMAP_TRACE);
specify_metric (buf, NTXT ("1"));
cmd = dbe_strdup (NTXT ("heapalloccnt"));
break;
case HEAP_ALLOC_BYTES:
packet_type = DATA_HEAP;
username = dbe_strdup (GTXT ("Bytes Allocated"));
snprintf (buf, sizeof (buf), NTXT ("(HTYPE!=%d)&&(HTYPE!=%d)&&HVADDR"),
FREE_TRACE, MUNMAP_TRACE);
specify_metric (buf, NTXT ("HSIZE"));
cmd = dbe_strdup (NTXT ("heapallocbytes"));
break;
case HEAP_LEAK_CNT:
packet_type = DATA_HEAP;
username = dbe_strdup (GTXT ("Leaks"));
snprintf (buf, sizeof (buf), "(HTYPE!=%d)&&(HTYPE!=%d)&&HVADDR&&HLEAKED",
FREE_TRACE, MUNMAP_TRACE);
specify_metric (buf, NTXT ("1"));
cmd = dbe_strdup (NTXT ("heapleakcnt"));
break;
case HEAP_LEAK_BYTES:
packet_type = DATA_HEAP;
username = dbe_strdup (GTXT ("Bytes Leaked"));
snprintf (buf, sizeof (buf), NTXT ("(HTYPE!=%d)&&(HTYPE!=%d)&&HVADDR"),
FREE_TRACE, MUNMAP_TRACE);
specify_metric (buf, NTXT ("HLEAKED"));
cmd = dbe_strdup (NTXT ("heapleakbytes"));
break;
case IO_READ_CNT:
packet_type = DATA_IOTRACE;
username = dbe_strdup (GTXT ("Read Count"));
snprintf (buf, sizeof (buf), "(IOTYPE==%d)", READ_TRACE);
specify_metric (buf, NTXT ("1"));
cmd = dbe_strdup (NTXT ("ioreadcnt"));
break;
case IO_WRITE_CNT:
packet_type = DATA_IOTRACE;
username = dbe_strdup (GTXT ("Write Count"));
snprintf (buf, sizeof (buf), "(IOTYPE==%d)", WRITE_TRACE);
specify_metric (buf, NTXT ("1"));
cmd = dbe_strdup (NTXT ("iowritecnt"));
break;
case IO_OTHER_CNT:
packet_type = DATA_IOTRACE;
username = dbe_strdup (GTXT ("Other I/O Count"));
snprintf (buf, sizeof (buf), "(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)",
OPEN_TRACE, CLOSE_TRACE, OTHERIO_TRACE);
specify_metric (buf, NTXT ("1"));
cmd = dbe_strdup (NTXT ("ioothercnt"));
break;
case IO_ERROR_CNT:
packet_type = DATA_IOTRACE;
username = dbe_strdup (GTXT ("I/O Error Count"));
snprintf (buf, sizeof (buf),
"(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)",
READ_TRACE_ERROR, WRITE_TRACE_ERROR, OPEN_TRACE_ERROR,
CLOSE_TRACE_ERROR, OTHERIO_TRACE_ERROR);
specify_metric (buf, NTXT ("1"));
cmd = dbe_strdup (NTXT ("ioerrorcnt"));
break;
case IO_READ_BYTES:
packet_type = DATA_IOTRACE;
username = dbe_strdup (GTXT ("Read Bytes"));
snprintf (buf, sizeof (buf), NTXT ("(IOTYPE==%d)&&IONBYTE"),
READ_TRACE);
specify_metric (buf, NTXT ("IONBYTE"));
cmd = dbe_strdup (NTXT ("ioreadbytes"));
break;
case IO_WRITE_BYTES:
packet_type = DATA_IOTRACE;
username = dbe_strdup (GTXT ("Write Bytes"));
snprintf (buf, sizeof (buf), "(IOTYPE==%d)&&IONBYTE", WRITE_TRACE);
specify_metric (buf, NTXT ("IONBYTE"));
cmd = dbe_strdup (NTXT ("iowritebytes"));
break;
case IO_READ_TIME:
packet_type = DATA_IOTRACE;
username = dbe_strdup (GTXT ("Read Time"));
snprintf (buf, sizeof (buf), "(IOTYPE==%d)&&EVT_TIME", READ_TRACE);
snprintf (buf2, sizeof (buf2), NTXT ("(EVT_TIME)/%lld"),
(long long) (NANOSEC / METRIC_HR_PRECISION));
specify_metric (buf, buf2);
cmd = dbe_strdup (NTXT ("ioreadtime"));
break;
case IO_WRITE_TIME:
packet_type = DATA_IOTRACE;
username = dbe_strdup (GTXT ("Write Time"));
snprintf (buf, sizeof (buf), NTXT ("(IOTYPE==%d)&&EVT_TIME"),
WRITE_TRACE);
snprintf (buf2, sizeof (buf2), NTXT ("(EVT_TIME)/%lld"),
(long long) (NANOSEC / METRIC_HR_PRECISION));
specify_metric (buf, buf2);
cmd = dbe_strdup (NTXT ("iowritetime"));
break;
case IO_OTHER_TIME:
packet_type = DATA_IOTRACE;
username = dbe_strdup (GTXT ("Other I/O Time"));
snprintf (buf, sizeof (buf),
"(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)&&EVT_TIME",
OPEN_TRACE, CLOSE_TRACE, OTHERIO_TRACE);
snprintf (buf2, sizeof (buf2), NTXT ("(EVT_TIME)/%lld"),
(long long) (NANOSEC / METRIC_HR_PRECISION));
specify_metric (buf, buf2);
cmd = dbe_strdup (NTXT ("ioothertime"));
break;
case IO_ERROR_TIME:
packet_type = DATA_IOTRACE;
username = dbe_strdup (GTXT ("I/O Error Time"));
snprintf (buf, sizeof (buf),
"(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)&&EVT_TIME",
READ_TRACE_ERROR, WRITE_TRACE_ERROR, OPEN_TRACE_ERROR,
CLOSE_TRACE_ERROR, OTHERIO_TRACE_ERROR);
snprintf (buf2, sizeof (buf2), NTXT ("(EVT_TIME)/%lld"),
(long long) (NANOSEC / METRIC_HR_PRECISION));
specify_metric (buf, buf2);
cmd = dbe_strdup (NTXT ("ioerrortime"));
break;
case RACCESS:
packet_type = DATA_RACE;
username = dbe_strdup (GTXT ("Race Accesses"));
specify_metric (NULL, NTXT ("RCNT"));
cmd = dbe_strdup (NTXT ("raccess"));
break;
case DEADLOCKS:
packet_type = DATA_DLCK;
username = dbe_strdup (GTXT ("Deadlocks"));
specify_metric (NULL, NTXT ("1"));
cmd = dbe_strdup (NTXT ("deadlocks"));
break;
case HWCNTR:
packet_type = DATA_HWC;
// username, cmd, and aux set by hwc constructor
if (valtype == VT_DOUBLE)
{
if (hw_ctr->timecvt > 0) // CPU cycles
specify_metric (NULL, NTXT ("((HWCINT*1000000)/FREQ_MHZ)"));
else if (hw_ctr->timecvt < 0)
{ // reference clock (frequency is -timecvt MHz)
snprintf (buf, sizeof (buf), NTXT ("((HWCINT*1000000)/%d)"), -hw_ctr->timecvt);
specify_metric (NULL, buf);
}
else // shouldn't happen
specify_metric (NULL, NTXT ("0"));
// resulting unit: seconds * 1e12
precision = 1000000LL * 1000000LL; // Seconds * 1e12
}
else
{
specify_metric (NULL, NTXT ("HWCINT"));
precision = 1;
}
break;
case OMP_MSTR:
case OMP_SNGL:
case OMP_ORDD:
case OMP_NONE:
default:
username = dbe_strdup (GTXT ("****"));
fprintf (stderr, "BaseMetric::init Undefined basemetric %s\n",
get_basetype_name ());
}
}
#define CASE_S(x) case x: s = (char *) #x; break
char *
BaseMetric::get_basetype_name ()
{
static char buf[128];
char *s;
switch (type)
{
CASE_S (CP_LMS_SYSTEM);
CASE_S (CP_TOTAL_CPU);
CASE_S (CP_TOTAL);
CASE_S (OMP_MASTER_THREAD);
CASE_S (CP_LMS_USER);
CASE_S (CP_LMS_WAIT_CPU);
CASE_S (CP_LMS_USER_LOCK);
CASE_S (CP_LMS_TFAULT);
CASE_S (CP_LMS_DFAULT);
CASE_S (CP_LMS_TRAP);
CASE_S (CP_LMS_KFAULT);
CASE_S (CP_LMS_SLEEP);
CASE_S (CP_LMS_STOPPED);
CASE_S (OMP_NONE);
CASE_S (OMP_OVHD);
CASE_S (OMP_WORK);
CASE_S (OMP_IBAR);
CASE_S (OMP_EBAR);
CASE_S (OMP_WAIT);
CASE_S (OMP_SERL);
CASE_S (OMP_RDUC);
CASE_S (OMP_LKWT);
CASE_S (OMP_CTWT);
CASE_S (OMP_ODWT);
CASE_S (OMP_MSTR);
CASE_S (OMP_SNGL);
CASE_S (OMP_ORDD);
CASE_S (CP_KERNEL_CPU);
CASE_S (SYNC_WAIT_TIME);
CASE_S (IO_READ_TIME);
CASE_S (IO_WRITE_TIME);
CASE_S (IO_OTHER_TIME);
CASE_S (IO_ERROR_TIME);
CASE_S (HWCNTR);
CASE_S (SYNC_WAIT_COUNT);
CASE_S (HEAP_ALLOC_CNT);
CASE_S (HEAP_LEAK_CNT);
CASE_S (IO_READ_CNT);
CASE_S (IO_WRITE_CNT);
CASE_S (IO_OTHER_CNT);
CASE_S (IO_ERROR_CNT);
CASE_S (RACCESS);
CASE_S (DEADLOCKS);
CASE_S (HEAP_ALLOC_BYTES);
CASE_S (HEAP_LEAK_BYTES);
CASE_S (IO_READ_BYTES);
CASE_S (IO_WRITE_BYTES);
CASE_S (SIZES);
CASE_S (ADDRESS);
CASE_S (ONAME);
CASE_S (DERIVED);
default:
s = NTXT ("???");
break;
}
snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, type);
buf[sizeof (buf) - 1] = 0;
return buf;
}
char *
BaseMetric::dump ()
{
int len = 4;
char *msg = dbe_sprintf (NTXT ("id=%d %s aux='%s' cmd='%s' user_name='%s' expr_spec='%s'\n"
"%*c cond_spec='%s' val_spec='%s'"),
id, get_basetype_name (), STR (aux), STR (cmd),
STR (username), STR (expr_spec),
len, ' ', STR (cond_spec), STR (val_spec));
return msg;
}
Histable *
BaseMetric::get_comparable_obj (Histable *obj)
{
if (obj == NULL || expr == NULL)
return obj;
if (strncmp (expr_spec, NTXT ("EXPGRID=="), 9) == 0)
{
int n = atoi (expr_spec + 9);
Vector<Histable *> *cmpObjs = obj->get_comparable_objs ();
if (cmpObjs && cmpObjs->size () >= n)
return cmpObjs->get (n - 1);
return NULL;
}
return obj;
}
Definition::Definition (opType _op)
{
op = _op;
bm = NULL;
arg1 = NULL;
arg2 = NULL;
def = NULL;
dependencies = NULL;
map = NULL;
index = 0;
}
Definition::~Definition ()
{
delete arg1;
delete arg2;
delete dependencies;
delete[] map;
}
Vector<BaseMetric *> *
Definition::get_dependencies ()
{
if (dependencies == NULL)
{
if (arg1 && arg1->bm && arg2 && arg2->bm)
{
dependencies = new Vector<BaseMetric *>(2);
arg1->index = dependencies->size ();
dependencies->append (arg1->bm);
arg2->index = dependencies->size ();
dependencies->append (arg2->bm);
map = new long[2];
}
}
return dependencies;
}
long *
Definition::get_map ()
{
get_dependencies ();
return map;
}
Definition *
Definition::add_definition (char *_def)
{
// parse the definition
char *op_ptr = strchr (_def, '/');
if (op_ptr == NULL)
{
// it's a primitive metric
BaseMetric *bm = dbeSession->find_base_reg_metric (_def);
if (bm)
{
Definition *p = new Definition (opPrimitive);
p->bm = bm;
return p;
}
return NULL; // BaseMetric is not yet specified
}
Definition *p2 = add_definition (op_ptr + 1);
if (p2 == NULL)
return NULL;
_def = dbe_strdup (_def);
op_ptr = strchr (_def, '/');
*op_ptr = 0;
Definition *p1 = add_definition (_def);
if (p1)
{
*op_ptr = '/';
Definition *p = new Definition (opDivide);
p->arg1 = p1;
p->arg2 = p2;
p->def = _def;
return p;
}
free (_def);
delete p1;
delete p2;
return NULL;
}
double
Definition::eval (long *indexes, TValue *values)
{
switch (op)
{
case opPrimitive:
return values[indexes[index]].to_double ();
case opDivide:
{
double x2 = arg2->eval (indexes, values);
if (x2 == 0)
return 0.;
double x1 = arg1->eval (indexes, values);
return x1 / x2;
}
default:
fprintf (stderr, GTXT ("unknown expression\n"));
return 0.;
}
}

246
gprofng/src/BaseMetric.h Normal file
View file

@ -0,0 +1,246 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _BASEMETRIC_H
#define _BASEMETRIC_H
#include "dbe_structs.h"
#include "hwcentry.h"
#include "Table.h"
// METRIC_*_PRECISION determine the least threshold value
// for time measured metrics. Any event that counts for less
// than 1sec/METRIC_PRECISION is discarded.
#define METRIC_SIG_PRECISION MICROSEC
#define METRIC_HR_PRECISION MICROSEC
class Expression;
class Definition;
class Histable;
template <class ITEM> class Vector;
class BaseMetric
{
public:
// sync enum changes with AnMetric.java
enum Type
{ // Subtype==STATIC metrics:
ONAME = 1, //ONAME must be 1
SIZES,
ADDRESS,
// Clock Profiling, Derived Metrics:
CP_TOTAL,
CP_TOTAL_CPU,
// Clock profiling, Solaris Microstates (LMS_* defines)
CP_LMS_USER,
CP_LMS_SYSTEM,
CP_LMS_TRAP,
CP_LMS_TFAULT,
CP_LMS_DFAULT,
CP_LMS_KFAULT,
CP_LMS_USER_LOCK,
CP_LMS_SLEEP,
CP_LMS_WAIT_CPU,
CP_LMS_STOPPED,
// Kernel clock profiling
CP_KERNEL_CPU,
// Sync Tracing
SYNC_WAIT_TIME,
SYNC_WAIT_COUNT,
// HWC
HWCNTR,
// Heap Tracing:
HEAP_ALLOC_CNT,
HEAP_ALLOC_BYTES,
HEAP_LEAK_CNT,
HEAP_LEAK_BYTES,
// I/O Tracing:
IO_READ_BYTES,
IO_READ_CNT,
IO_READ_TIME,
IO_WRITE_BYTES,
IO_WRITE_CNT,
IO_WRITE_TIME,
IO_OTHER_CNT,
IO_OTHER_TIME,
IO_ERROR_CNT,
IO_ERROR_TIME,
// MPI Tracing:
MPI_TIME,
MPI_SEND,
MPI_BYTES_SENT,
MPI_RCV,
MPI_BYTES_RCVD,
MPI_OTHER,
// OMP states:
OMP_NONE,
OMP_OVHD,
OMP_WORK,
OMP_IBAR,
OMP_EBAR,
OMP_WAIT,
OMP_SERL,
OMP_RDUC,
OMP_LKWT,
OMP_CTWT,
OMP_ODWT,
OMP_MSTR,
OMP_SNGL,
OMP_ORDD,
OMP_MASTER_THREAD,
// MPI states:
MPI_WORK,
MPI_WAIT,
// Races and Deadlocks
RACCESS,
DEADLOCKS,
// Derived Metrics
DERIVED
};
// sync enum changes with AnMetric.java
enum SubType
{
STATIC = 1, // Type==SIZES, ADDRESS, ONAME
EXCLUSIVE = 2,
INCLUSIVE = 4,
ATTRIBUTED = 8,
DATASPACE = 16 // Can be accessed in dataspace views
};
BaseMetric (Type t);
BaseMetric (Hwcentry *ctr, const char* _aux, const char* _cmdname,
const char* _username, int v_styles); // depended bm
BaseMetric (Hwcentry *ctr, const char* _aux, const char* _username,
int v_styles, BaseMetric* _depended_bm = NULL); // master bm
BaseMetric (const char *_cmd, const char *_username, Definition *def); // derived metrics
BaseMetric (const BaseMetric& m);
virtual ~BaseMetric ();
int get_id () { return id; }
Type get_type () { return type; }
Hwcentry *get_hw_ctr () { return hw_ctr; }
char *get_aux () { return aux; }
char *get_username () { return username; }
char *get_cmd () { return cmd; }
int get_flavors () { return flavors; }
int get_clock_unit () { return clock_unit; }
long long get_precision () { return precision; }
ValueTag get_vtype () { return valtype; }
int get_value_styles () { return value_styles; }
bool is_zeroThreshold () { return zeroThreshold; }
ProfData_type get_packet_type () { return packet_type; }
Expression *get_cond () { return cond; }
Expression *get_val () { return val; }
Expression *get_expr () { return expr; }
char *get_expr_spec () { return expr_spec; }
Definition *get_definition () { return definition; };
BaseMetric *get_dependent_bm () { return dependent_bm; };
bool
comparable ()
{
return val_spec != NULL || type == DERIVED || type == SIZES || type == ADDRESS;
}
// setters..
void set_default_visbits (SubType subtype, int _visbits);
void set_id (int _id) { id = _id; } //TBR, if possible
// For comparison, set which packets to eval:
void set_expr_spec (char *_expr_spec);
void set_cond_spec (char *_cond_spec);
int get_default_visbits (SubType subtype);
char *dump ();
Histable *get_comparable_obj (Histable *obj);
bool is_internal (); // Invisible for users
char *legend; // for comparison: add'l column text
private:
BaseMetric *dependent_bm; // for HWCs only: a link to the timecvt metric
Expression *cond; // determines which packets to evaluate
char *cond_spec; // used to generate "cond"
Expression *val; // determines the numeric value for packet
char *val_spec; // used to generate "val"
Expression *expr; // for comparison: an additional expression to determine
// which packets to eval. Should be NULL otherwise.
char *expr_spec; // used to generate "expr"
int id; // unique id (assigned to last_id @ "new")
Type type; // e.g. HWCNTR
char *aux; // for HWCs only: Hwcentry ctr->name
char *cmd; // the .rc metric command, e.g. "total"
char *username; // e.g. "GTXT("Total Wait Time")"
int flavors; // bitmask of SubType capabilities
int value_styles; // bitmask of ValueType capabilities
static const int NSUBTYPES = 2; // STATIC/EXCLUSIVE, INCLUSIVE
int default_visbits[NSUBTYPES]; // ValueType, e.g. VAL_VALUE|VAL_TIMEVAL
ValueTag valtype; // e.g. VT_LLONG
long long precision; // e.g. METRIC_SIG_PRECISION, 1, etc.
Hwcentry *hw_ctr; // HWC definition
ProfData_type packet_type; // e.g. DATA_HWC, or -1 for N/A
bool zeroThreshold; // deadlock stuff
Presentation_clock_unit clock_unit;
static int last_id; // incremented by 1 w/ every "new". Not MT-safe
Definition *definition;
void hwc_init (Hwcentry *ctr, const char* _aux, const char* _cmdname, const char* _username, int v_styles);
void init (Type t);
char *get_basetype_name ();
void specify ();
void specify_metric (char *_cond_spec, char *_val_spec);
void set_val_spec (char *_val_spec);
void specify_mstate_metric (int st);
void specify_ompstate_metric (int st);
void specify_prof_metric (char *_cond_spec);
};
class Definition
{
public:
enum opType
{
opNULL,
opPrimitive,
opDivide
};
Definition (opType _op);
~Definition ();
static Definition *add_definition (char *_def);
Vector<BaseMetric *> *get_dependencies ();
long *get_map ();
double eval (long *indexes, TValue *values);
opType op;
Definition *arg1;
Definition *arg2;
char *def;
private:
BaseMetric *bm;
long *map;
Vector<BaseMetric *> *dependencies;
long index;
};
#endif /* _BASEMETRIC_H */

View file

@ -0,0 +1,329 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <stdio.h>
#include <strings.h>
#include <limits.h>
#include <sys/param.h>
#include "hwcentry.h"
#include "DbeSession.h"
#include "Experiment.h"
#include "Expression.h"
#include "Metric.h"
#include "Table.h"
#include "i18n.h"
#include "debug.h"
BaseMetricTreeNode::BaseMetricTreeNode ()
{
init_vars ();
build_basic_tree ();
}
BaseMetricTreeNode::BaseMetricTreeNode (BaseMetric *item)
{
init_vars ();
bm = item;
name = dbe_strdup (bm->get_cmd ());
uname = dbe_strdup (bm->get_username ());
unit = NULL; //YXXX populate from base_metric (requires updating base_metric)
unit_uname = NULL;
}
BaseMetricTreeNode::BaseMetricTreeNode (const char *_name, const char *_uname,
const char *_unit, const char *_unit_uname)
{
init_vars ();
name = dbe_strdup (_name);
uname = dbe_strdup (_uname);
unit = dbe_strdup (_unit);
unit_uname = dbe_strdup (_unit_uname);
}
void
BaseMetricTreeNode::init_vars ()
{
name = NULL;
uname = NULL;
unit = NULL;
unit_uname = NULL;
root = this;
parent = NULL;
children = new Vector<BaseMetricTreeNode*>;
isCompositeMetric = false;
bm = NULL;
registered = false;
num_registered_descendents = 0;
}
BaseMetricTreeNode::~BaseMetricTreeNode ()
{
children->destroy ();
delete children;
free (name);
free (uname);
free (unit);
free (unit_uname);
}
BaseMetricTreeNode *
BaseMetricTreeNode::register_metric (BaseMetric *item)
{
BaseMetricTreeNode *found = root->find (item->get_cmd ());
if (!found)
{
switch (item->get_type ())
{
case BaseMetric::CP_TOTAL:
found = root->find (L_CP_TOTAL);
break;
case BaseMetric::CP_TOTAL_CPU:
found = root->find (L_CP_TOTAL_CPU);
break;
}
if (found && found->bm == NULL)
found->bm = item;
}
if (!found)
{
switch (item->get_type ())
{
case BaseMetric::HEAP_ALLOC_BYTES:
case BaseMetric::HEAP_ALLOC_CNT:
case BaseMetric::HEAP_LEAK_BYTES:
case BaseMetric::HEAP_LEAK_CNT:
found = root->find (get_prof_data_type_name (DATA_HEAP));
break;
case BaseMetric::CP_KERNEL_CPU:
case BaseMetric::CP_TOTAL:
found = root->find (get_prof_data_type_name (DATA_CLOCK));
break;
case BaseMetric::CP_LMS_DFAULT:
case BaseMetric::CP_LMS_TFAULT:
case BaseMetric::CP_LMS_KFAULT:
case BaseMetric::CP_LMS_STOPPED:
case BaseMetric::CP_LMS_WAIT_CPU:
case BaseMetric::CP_LMS_SLEEP:
case BaseMetric::CP_LMS_USER_LOCK:
case BaseMetric::CP_TOTAL_CPU:
found = root->find (L_CP_TOTAL);
break;
case BaseMetric::CP_LMS_USER:
case BaseMetric::CP_LMS_SYSTEM:
case BaseMetric::CP_LMS_TRAP:
found = root->find (L_CP_TOTAL_CPU);
break;
case BaseMetric::HWCNTR:
found = root->find ((item->get_flavors () & BaseMetric::DATASPACE) != 0 ?
L2_HWC_DSPACE : L2_HWC_GENERAL);
break;
case BaseMetric::SYNC_WAIT_TIME:
case BaseMetric::SYNC_WAIT_COUNT:
found = root->find (get_prof_data_type_name (DATA_SYNCH));
break;
case BaseMetric::OMP_WORK:
case BaseMetric::OMP_WAIT:
case BaseMetric::OMP_OVHD:
found = root->find (get_prof_data_type_name (DATA_OMP));
break;
case BaseMetric::IO_READ_TIME:
case BaseMetric::IO_READ_BYTES:
case BaseMetric::IO_READ_CNT:
case BaseMetric::IO_WRITE_TIME:
case BaseMetric::IO_WRITE_BYTES:
case BaseMetric::IO_WRITE_CNT:
case BaseMetric::IO_OTHER_TIME:
case BaseMetric::IO_OTHER_CNT:
case BaseMetric::IO_ERROR_TIME:
case BaseMetric::IO_ERROR_CNT:
found = root->find (get_prof_data_type_name (DATA_IOTRACE));
break;
case BaseMetric::ONAME:
case BaseMetric::SIZES:
case BaseMetric::ADDRESS:
found = root->find (L1_STATIC);
break;
default:
found = root->find (L1_OTHER);
break;
}
assert (found != NULL);
switch (item->get_type ())
{
case BaseMetric::CP_TOTAL:
case BaseMetric::CP_TOTAL_CPU:
found->isCompositeMetric = true;
break;
}
found = found->add_child (item);
}
register_node (found);
return found;
}
void
BaseMetricTreeNode::register_node (BaseMetricTreeNode *node)
{
if (!node->registered)
{
node->registered = true;
BaseMetricTreeNode *tmp = node->parent;
while (tmp)
{
tmp->num_registered_descendents++;
tmp = tmp->parent;
}
}
}
BaseMetricTreeNode *
BaseMetricTreeNode::find (const char *_name)
{
BaseMetricTreeNode *found = NULL;
if (dbe_strcmp (get_name (), _name) == 0)
return this;
if (bm && dbe_strcmp (bm->get_cmd (), _name) == 0)
return this;
BaseMetricTreeNode *child;
int index;
Vec_loop (BaseMetricTreeNode*, children, index, child)
{
found = child->find (_name);
if (found)
return found;
}
return NULL;
}
static void
int_get_registered_descendents (BaseMetricTreeNode* curr,
Vector<BaseMetricTreeNode*> *dest, bool nearest_only)
{
if (!curr)
return;
if (curr->is_registered ())
{
dest->append (curr);
if (nearest_only)
return; // soon as we hit a live node, stop following branch
}
int index;
BaseMetricTreeNode *child;
Vec_loop (BaseMetricTreeNode*, curr->get_children (), index, child)
{
int_get_registered_descendents (child, dest, nearest_only);
}
}
void
BaseMetricTreeNode::get_nearest_registered_descendents (Vector<BaseMetricTreeNode*> *dest)
{
if (!dest || dest->size () != 0)
abort ();
bool nearest_only = true;
int_get_registered_descendents (this, dest, nearest_only);
}
void
BaseMetricTreeNode::get_all_registered_descendents (Vector<BaseMetricTreeNode*> *dest)
{
if (!dest || dest->size () != 0)
abort ();
bool nearest_only = false;
int_get_registered_descendents (this, dest, nearest_only);
}
char *
BaseMetricTreeNode::get_description ()
{
if (bm)
{
Hwcentry* hw_ctr = bm->get_hw_ctr ();
if (hw_ctr)
return hw_ctr->short_desc;
}
return NULL;
}
void
BaseMetricTreeNode::build_basic_tree ()
{
#define TREE_INSERT_DATA_TYPE(t) add_child(get_prof_data_type_name (t), get_prof_data_type_uname (t))
BaseMetricTreeNode *level1, *level2;
// register L1_DURATION here because it has a value but is not a true metric
register_node (add_child (L1_DURATION, L1_DURATION_UNAME, UNIT_SECONDS,
UNIT_SECONDS_UNAME));
register_node (add_child (L1_GCDURATION, L1_GCDURATION_UNAME, UNIT_SECONDS,
UNIT_SECONDS_UNAME));
TREE_INSERT_DATA_TYPE (DATA_HEAP);
level1 = TREE_INSERT_DATA_TYPE (DATA_CLOCK);
level1 = level1->add_child (L_CP_TOTAL, GTXT ("XXX Total Thread Time"));
level1->isCompositeMetric = true;
level2 = level1->add_child (L_CP_TOTAL_CPU, GTXT ("XXX Total CPU Time"));
level2->isCompositeMetric = true;
add_child (L1_OTHER, L1_OTHER_UNAME);
level1 = TREE_INSERT_DATA_TYPE (DATA_HWC);
level1->add_child (L2_HWC_DSPACE, L2_HWC_DSPACE_UNAME);
level1->add_child (L2_HWC_GENERAL, L2_HWC_GENERAL_UNAME);
TREE_INSERT_DATA_TYPE (DATA_SYNCH);
TREE_INSERT_DATA_TYPE (DATA_OMP);
TREE_INSERT_DATA_TYPE (DATA_IOTRACE);
add_child (L1_STATIC, L1_STATIC_UNAME);
}
BaseMetricTreeNode *
BaseMetricTreeNode::add_child (BaseMetric *item)
{
return add_child (new BaseMetricTreeNode (item));
}
BaseMetricTreeNode *
BaseMetricTreeNode::add_child (const char * _name, const char *_uname,
const char * _unit, const char * _unit_uname)
{
return add_child (new BaseMetricTreeNode (_name, _uname, _unit, _unit_uname));
}
BaseMetricTreeNode *
BaseMetricTreeNode::add_child (BaseMetricTreeNode *new_node)
{
new_node->parent = this;
new_node->root = root;
children->append (new_node);
return new_node;
}
char *
BaseMetricTreeNode::dump ()
{
int len = 4;
char *s = bm ? bm->dump () : dbe_strdup ("<no base metric>");
char *msg = dbe_sprintf ("%s\n%*c %*c unit='%s' unit_uname='%s' uname='%s' name='%s'\n",
STR (s), len, ' ', len, ' ',
STR (get_unit_uname ()), STR (get_unit ()),
STR (get_user_name ()), STR (get_name ()));
free (s);
return msg;
}

View file

@ -0,0 +1,100 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _BASEMETRICTREENODE_H
#define _BASEMETRICTREENODE_H
#include "BaseMetric.h"
// Unit values
#define UNIT_SECONDS "SECONDS"
#define UNIT_SECONDS_UNAME GTXT("secs.")
#define UNIT_BYTES "BYTES"
#define UNIT_BYTES_UNAME GTXT("bytes")
// Name values for intermediate parent nodes that aren't defined elsewhere
#define L1_DURATION "PROFDATA_TYPE_DURATION"
#define L1_DURATION_UNAME GTXT("Experiment Duration")
#define L1_GCDURATION "PROFDATA_TYPE_GCDURATION"
#define L1_GCDURATION_UNAME GTXT("Java Garbage Collection Duration")
#define L2_HWC_DSPACE "PROFDATA_TYPE_HWC_DSPACE"
#define L2_HWC_DSPACE_UNAME GTXT("Memoryspace Hardware Counters")
#define L2_HWC_GENERAL "PROFDATA_TYPE_HWC_GENERAL"
#define L2_HWC_GENERAL_UNAME GTXT("General Hardware Counters")
#define L1_MPI_STATES "PROFDATA_TYPE_MPI_STATES"
#define L1_MPI_STATES_UNAME GTXT("MPI States")
#define L1_OTHER "PROFDATA_TYPE_OTHER"
#define L1_OTHER_UNAME GTXT("Derived and Other Metrics")
#define L1_STATIC "PROFDATA_TYPE_STATIC"
#define L1_STATIC_UNAME GTXT("Static")
#define L_CP_TOTAL "L_CP_TOTAL"
#define L_CP_TOTAL_CPU "L_CP_TOTAL_CPU"
class BaseMetricTreeNode
{
public:
BaseMetricTreeNode (); // builds basic metric tree (not including HWCs)
virtual ~BaseMetricTreeNode ();
BaseMetricTreeNode *register_metric (BaseMetric *item);
BaseMetricTreeNode *find (const char *name);
void get_nearest_registered_descendents (Vector<BaseMetricTreeNode*> *new_vec);
void get_all_registered_descendents (Vector<BaseMetricTreeNode*> *new_vec);
char *get_description();
char *dump();
BaseMetricTreeNode *get_root () { return root; }
BaseMetricTreeNode *get_parent () { return parent; }
Vector<BaseMetricTreeNode*> *get_children () { return children; }
bool is_registered () { return registered; }
int get_num_registered_descendents () { return num_registered_descendents; }
bool is_composite_metric () { return isCompositeMetric; }
BaseMetric *get_BaseMetric () { return bm; }
char *get_name () { return name; }
char *get_user_name () { return uname; }
char *get_unit () { return unit; }
char *get_unit_uname () { return unit_uname; }
private:
BaseMetricTreeNode (BaseMetric *item);
BaseMetricTreeNode (const char *name, const char *uname,
const char *_unit, const char *_unit_uname);
void init_vars ();
void build_basic_tree ();
BaseMetricTreeNode *add_child (BaseMetric *item);
BaseMetricTreeNode *add_child (const char *name, const char *uname,
const char *unit = NULL, const char *unit_uname = NULL);
BaseMetricTreeNode *add_child (BaseMetricTreeNode *new_node);
void register_node (BaseMetricTreeNode *);
BaseMetricTreeNode *root; // root of tree
BaseMetricTreeNode *parent; // my parent
bool aggregation; // value is based on children's values
char *name; // bm->get_cmd() for metrics, unique string otherwise
char *uname; // user-visible text
char *unit; // see UNIT_* defines
char *unit_uname; // see UNIT_*_UNAME defines
Vector<BaseMetricTreeNode*> *children; // my children
bool isCompositeMetric; // value is sum of children
BaseMetric *bm; // metric for this node, or null
bool registered; // metric has been officially registered
int num_registered_descendents; // does not include self
};
#endif /* _BASEMETRICTREENODE_H */

186
gprofng/src/CacheMap.h Normal file
View file

@ -0,0 +1,186 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/*
* Cache Map implementation.
*
* Cache Map makes the following assumptions:
* - Cache Map is used for very fast but not guaranteed mapping;
* - only REL_EQ Relation can be used;
* - all objects used as keys or values has to be managed
* outside CacheMap (f.e. deletion);
* - (Key_t)0 is invalid key;
* - (Value_t)0 is invalid value;
* - <TBC>
*/
#ifndef _DBE_CACHEMAP_H
#define _DBE_CACHEMAP_H
#include <assert.h>
#include <vec.h>
#include <Map.h>
template <typename Key_t, typename Value_t>
class CacheMap : public Map<Key_t, Value_t>
{
public:
CacheMap ();
~CacheMap ();
void put (Key_t key, Value_t val);
Value_t get (Key_t key);
Value_t get (Key_t key, typename Map<Key_t, Value_t>::Relation rel);
Value_t
remove (Key_t key);
private:
struct Entry
{
Key_t key;
Value_t val;
Entry ()
{
key = (Key_t) 0;
}
};
static const int INIT_SIZE;
static const int MAX_SIZE;
static unsigned hash (Key_t key);
Entry *getEntry (Key_t key);
int cursize;
int nputs;
int nchunks;
Entry **chunks;
};
template <typename Key_t, typename Value_t>
const int CacheMap<Key_t, Value_t>::INIT_SIZE = 1 << 14;
template <typename Key_t, typename Value_t>
const int CacheMap<Key_t, Value_t>::MAX_SIZE = 1 << 20;
template <typename Key_t, typename Value_t>CacheMap<Key_t, Value_t>
::CacheMap ()
{
cursize = INIT_SIZE;
chunks = new Entry*[32];
nchunks = 0;
chunks[nchunks++] = new Entry[cursize];
nputs = 0;
}
template <typename Key_t, typename Value_t>
CacheMap<Key_t, Value_t>::~CacheMap ()
{
for (int i = 0; i < nchunks; i++)
delete[] chunks[i];
delete[] chunks;
}
template <typename Key_t, typename Value_t>
unsigned
CacheMap<Key_t, Value_t>::hash (Key_t key)
{
unsigned h = (unsigned) key ^ (unsigned) (key >> 32);
h ^= (h >> 20) ^ (h >> 12);
return h ^ (h >> 7) ^ (h >> 4);
}
template <typename Key_t, typename Value_t>
void
CacheMap<Key_t, Value_t>::put (Key_t key, Value_t val)
{
if (nputs >= cursize && cursize < MAX_SIZE)
{
// Allocate new chunk for entries.
chunks[nchunks++] = new Entry[cursize];
cursize *= 2;
// Copy all old entries to the newly allocated chunk
Entry *newchunk = chunks[nchunks - 1];
int prevsz = 0;
int nextsz = INIT_SIZE;
for (int i = 0; i < nchunks - 1; i++)
{
Entry *oldchunk = chunks[i];
for (int j = prevsz; j < nextsz; j++)
newchunk[j] = oldchunk[j - prevsz];
prevsz = nextsz;
nextsz *= 2;
}
}
Entry *entry = getEntry (key);
entry->key = key;
entry->val = val;
nputs++;
}
template <typename Key_t, typename Value_t>
typename CacheMap<Key_t, Value_t>::Entry *
CacheMap<Key_t, Value_t>::getEntry (Key_t key)
{
unsigned idx = hash (key);
int i = nchunks - 1;
int j = cursize / 2;
for (; i > 0; i -= 1, j /= 2)
if (idx & j)
break;
if (i == 0)
j *= 2;
return &chunks[i][idx & (j - 1)];
}
template <typename Key_t, typename Value_t>
Value_t
CacheMap<Key_t, Value_t>::get (Key_t key)
{
Entry *entry = getEntry (key);
return entry->key == key ? entry->val : (Value_t) 0;
}
template <typename Key_t, typename Value_t>
Value_t
CacheMap<Key_t, Value_t>::get (Key_t key, typename Map<Key_t, Value_t>::Relation rel)
{
if (rel != Map<Key_t, Value_t>::REL_EQ)
return (Value_t) 0;
return get (key);
}
template <typename Key_t, typename Value_t>
Value_t
CacheMap<Key_t, Value_t>::remove (Key_t key)
{
Entry *entry = getEntry (key);
Value_t res = (Value_t) 0;
if (entry->key == key)
{
res = entry->val;
entry->val = (Value_t) 0;
}
return res;
}
#endif

1250
gprofng/src/CallStack.cc Normal file

File diff suppressed because it is too large Load diff

114
gprofng/src/CallStack.h Normal file
View file

@ -0,0 +1,114 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _CALLSTACK_H
#define _CALLSTACK_H
#include <stdio.h>
#include "dbe_structs.h"
#include "Experiment.h"
#include "DbeLock.h"
class DataDescriptor;
class FramePacket;
class DbeInstr;
class Histable;
template <class ITEM> class Vector;
class CallStackNode;
class Descendants /* : public DbeLock */
{
public:
Descendants ();
~Descendants ();
CallStackNode *find (Histable *hi, int *index);
void append (CallStackNode *item);
void insert (int ind, CallStackNode *item);
int volatile count;
private:
enum
{
DELTA = 8
};
int limit;
CallStackNode **data;
CallStackNode *first_data[4];
};
class CallStackNode : public Descendants
{
public:
CallStackNode (CallStackNode *_ancestor, Histable *_instr);
~CallStackNode ();
bool compare (long start, long end, Vector<Histable*> *objs, CallStackNode *mRoot);
void dump ();
CallStackNode *
get_ancestor ()
{
return ancestor;
}
Histable *
get_instr ()
{
return instr;
}
CallStackNode *alt_node;
Histable *instr;
CallStackNode *ancestor;
};
class CallStack
{
public:
static CallStack *getInstance (Experiment *exp);
virtual ~CallStack () { };
virtual void add_stack (DataDescriptor *dDscr, long idx, FramePacket *frp,
cstk_ctx_chunk* cstCtxChunk) = 0;
// Creates a call stack representation for objs and
// returns an opaque pointer to it
virtual void *add_stack (Vector<Histable*> *objs) = 0;
// Debugging methods
virtual void print (FILE *) = 0;
// Call stack inquiries
static int stackSize (void *stack);
static Histable *getStackPC (void *stack, int n);
static Vector<Histable*> *getStackPCs (void *stack, bool get_hide_stack = false);
static void setHideStack (void *stack, void *hideStack);
static int compare (void *stack1, void *stack2);
virtual CallStackNode *
get_node (int)
{
return NULL;
};
};
#endif /* _CALLSTACK_H */

View file

@ -0,0 +1,59 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <new> // std::bad_alloc
#include <stdio.h> // fprintf
#include <stdlib.h> // exit
#include "DbeApplication.h"
static char *name = NULL;
/**
* Out Of Memory exception handler
*/
void
out_of_mem ()
{
fprintf (stderr, "%s: %s: %s\n", "Error", name ? name : "", "Out of memory\n");
exit (2); // Out of memory
// throw bad_alloc();
}
/**
* Calls real_main inside try{...}catch(std::bad_alloc *)
*/
int
catch_out_of_memory (int (*real_main)(int, char*[]), int argc, char *argv[])
{
int i = 0;
name = argv[0];
std::set_new_handler (out_of_mem);
try
{
i = real_main (argc, argv);
}
catch (std::bad_alloc */*ba*/)
{
exit (2); // Out of memory
}
delete theDbeApplication;
return i;
}

1639
gprofng/src/ClassFile.cc Normal file

File diff suppressed because it is too large Load diff

63
gprofng/src/ClassFile.h Normal file
View file

@ -0,0 +1,63 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _CLASSFILE_H
#define _CLASSFILE_H
#include "Module.h"
class DataInputStream;
class BinaryConstantPool;
class JMethod;
class StringBuilder;
class ByteCodeInfo;
class ClassFile : public Module
{
public:
ClassFile ();
virtual ~ClassFile ();
virtual int readFile ();
virtual char *get_disasm (uint64_t inst_address, uint64_t end_address,
uint64_t start_address, uint64_t f_offset,
int64_t &inst_size);
static char *get_java_file_name (char *clname, bool classSuffix);
private:
void openFile (const char *fname);
char *get_opc_name (int op);
void readAttributes (int count);
void printConstant (StringBuilder *sb, int index);
long long printCodeSequence (StringBuilder *sb, uint64_t addr, DataInputStream *in);
unsigned char *cf_buf;
int64_t cf_bufsz;
int blanksCnt;
DataInputStream *input;
BinaryConstantPool *bcpool;
JMethod *cur_jmthd;
char *class_name;
char *class_filename;
char *source_name;
Vector<ByteCodeInfo *> *byteCodeInfo;
};
#endif

562
gprofng/src/Command.cc Normal file
View file

@ -0,0 +1,562 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include <sys/param.h>
#include "gp-defs.h"
#include "Command.h"
#include "DbeSession.h"
#include "MemorySpace.h"
#include "i18n.h"
#include "StringBuilder.h"
const char *Command::DEFAULT_CMD = "default"; // token for default
const char *Command::ALL_CMD = "all"; // token for all
const char *Command::ANY_CMD = "any"; // token for any
const char *Command::NONE_CMD = "none"; // token for none
const char *Command::HWC_CMD = "hwc"; // token for all HWC
const char *Command::BIT_CMD = "bit"; // token for any bit-generated metric
const char *Command::DEFAULT_METRICS = "ei.user:name"; // if no .rc files read
const char *Command::DEFAULT_SORT = "e.user:name"; // if no .rc files read
static char *fhdr, *cchdr, *lahdr, *iohdr, *sdhdr, *lsthdr, *lohdr;
static char *methdr, *othdr, *mischdr, *deflthdr;
static char *selhdr, *filthdr, *outhdr, *exphdr, *obj_allhdr;
static char *unsuphdr, *indxobjhdr;
static char *helphdr, *rahdr, *ddhdr, *typehdr, *typehdr2;
// This is the list of commands, which governs the parser scan, as
// well as the help command.
// A line with the tag NO_CMD is skipped in parsing, but is used
// to provide subheadings for the help
// The HELP line must be the last one in the list of commands
// to be shown by "-help"; The HHELP line must be the
// last one to be shown by "-xhelp"
// The LAST_CMD line must be the last one recognized by the parser
//
// The ordering of this list should match the ordering in the man
// page, and the subheader lines should match the subheadings in
// the man page.
static char *desc[LAST_CMD];
static Cmdtable cmd_lst[] = { // list of commands
// User Commands
{ NO_CMD, "", NULL, NULL, 0, &fhdr},
{ FUNCS, "functions", NULL, NULL, 0, &desc[FUNCS]},
{ METRICS, "metrics", NULL, "metric_spec", 1, &desc[METRICS]},
{ SORT, "sort", NULL, "metric_spec", 1, &desc[SORT]},
{ FDETAIL, "fsummary", NULL, NULL, 0, &desc[FDETAIL]},
{ FSINGLE, "fsingle", NULL, "function_name #", 2, &desc[FSINGLE]},
{ NO_CMD, "", NULL, NULL, 0, &cchdr},
{ GPROF, "callers-callees", "gprof", NULL, 0, &desc[GPROF]},
{ CSINGLE, "csingle", NULL, "function_name #", 2, &desc[CSINGLE]},
{ CPREPEND, "cprepend", NULL, "function_name #", 2, &desc[CPREPEND]},
{ CAPPEND, "cappend", NULL, "function_name #", 2, &desc[CAPPEND]},
{ CRMFIRST, "crmfirst", NULL, NULL, 0, &desc[CRMFIRST]},
{ CRMLAST, "crmlast", NULL, NULL, 0, &desc[CRMLAST]},
{ CALLTREE, "calltree", "ctree", NULL, 0, &desc[CALLTREE]},
{ NO_CMD, "", NULL, NULL, 0, &lahdr},
{ LEAKS, "leaks", NULL, NULL, 0, &desc[LEAKS]},
{ ALLOCS, "allocs", NULL, NULL, 0, &desc[ALLOCS]},
{ HEAP, "heap", NULL, NULL, 0, &desc[HEAP]},
{ HEAPSTAT, "heapstat", NULL, NULL, 0, &desc[HEAPSTAT]},
{ NO_CMD, "", NULL, NULL, 0, &iohdr},
{ IOACTIVITY, "ioactivity", NULL, NULL, 0, &desc[IOACTIVITY]},
{ IOVFD, "iodetail", NULL, NULL, 0, &desc[IOVFD]},
{ IOCALLSTACK, "iocallstack", NULL, NULL, 0, &desc[IOCALLSTACK]},
{ IOSTAT, "iostat", NULL, NULL, 0, &desc[IOSTAT]},
// PC, line, source and dissassembly commands
{ NO_CMD, "", NULL, NULL, 0, &sdhdr},
{ HOTPCS, "pcs", NULL, NULL, 0, &desc[HOTPCS]},
{ PDETAIL, "psummary", NULL, NULL, 0, &desc[PDETAIL]},
{ HOTLINES, "lines", NULL, NULL, 0, &desc[HOTLINES]},
{ LDETAIL, "lsummary", NULL, NULL, 0, &desc[LDETAIL]},
{ SOURCE, "source", NULL, "func/file #", 2, &desc[SOURCE]},
{ DISASM, "disasm", NULL, "func/file #", 2, &desc[DISASM]},
{ SCOMPCOM, "scc", NULL, "com_spec", 1, &desc[SCOMPCOM]},
{ STHRESH, "sthresh", NULL, "value", 1, &desc[STHRESH]},
{ DCOMPCOM, "dcc", NULL, "com_spec", 1, &desc[DCOMPCOM]},
{ COMPCOM, "cc", NULL, "com_spec", 1, &desc[COMPCOM]},
{ DTHRESH, "dthresh", NULL, "value", 1, &desc[DTHRESH]},
{ SETPATH, "setpath", NULL, "path_list", 1, &desc[SETPATH]},
{ ADDPATH, "addpath", NULL, "path_list", 1, &desc[ADDPATH]},
{ PATHMAP, "pathmap", NULL, "old_prefix new_prefix", 2, &desc[PATHMAP]},
{ LIBDIRS, "preload_libdirs", NULL, NULL, 1, &desc[PATHMAP]},
// Index Object commands
{ NO_CMD, "", NULL, NULL, 0, &indxobjhdr},
{ INDXOBJ, "indxobj", NULL, "type", 1, &desc[INDXOBJ]},
{ INDXOBJLIST, "indxobj_list", NULL, NULL, 0, &desc[INDXOBJLIST]},
{ INDXOBJDEF, "indxobj_define", NULL, "type \"index-expr\"", 2, &desc[INDXOBJDEF]},
// Deadlock detection commands
{ NO_CMD, "", NULL, NULL, 0, &ddhdr},
{ DEADLOCK_EVNTS, "deadlocks", NULL, NULL, 0, &desc[DEADLOCK_EVNTS]},
{ DEADLOCK_SUM, "dsummary", NULL, "{deadlock_id|all}", 1, &desc[DEADLOCK_SUM]},
{ NO_CMD, "", NULL, NULL, 0, &lsthdr},
{ EXP_LIST, "experiment_list", "exp_list", NULL, 0, &desc[EXP_LIST]},
{ SAMPLE_LIST, "sample_list", NULL, NULL, 0, &desc[SAMPLE_LIST]},
{ LWP_LIST, "lwp_list", NULL, NULL, 0, &desc[LWP_LIST]},
{ THREAD_LIST, "thread_list", NULL, NULL, 0, &desc[THREAD_LIST]},
{ CPU_LIST, "cpu_list", NULL, NULL, 0, &desc[CPU_LIST]},
{ NO_CMD, "", NULL, NULL, 0, &filthdr},
{ FILTERS, "filters", NULL, "filter-specification", 1, &desc[FILTERS]},
{ DESCRIBE, "describe", NULL, NULL, 0, &desc[DESCRIBE]},
{ NO_CMD, "", NULL, NULL, 0, &selhdr},
{ SAMPLE_SELECT, "sample_select", NULL, "sample_spec", 1, &desc[SAMPLE_SELECT]},
{ LWP_SELECT, "lwp_select", NULL, "lwp_spec", 1, &desc[LWP_SELECT]},
{ THREAD_SELECT, "thread_select", NULL, "thread_spec", 1, &desc[THREAD_SELECT]},
{ CPU_SELECT, "cpu_select", NULL, "cpu_spec", 1, &desc[CPU_SELECT]},
{ NO_CMD, "", NULL, NULL, 0, &lohdr},
{ OBJECT_LIST, "object_list", NULL, NULL, 0, &desc[OBJECT_LIST]},
{ OBJECT_SHOW, "object_show", NULL, "obj1,...", 1, &desc[OBJECT_SHOW]},
{ OBJECT_HIDE, "object_hide", NULL, "obj1,...", 1, &desc[OBJECT_HIDE]},
{ OBJECT_API, "object_api", NULL, "obj1,...", 1, &desc[OBJECT_API]},
{ DUMMY_CMD, " ", NULL, NULL, 0, &obj_allhdr},
{ OBJECTS_DEFAULT, "objects_default", NULL, NULL, 1, &desc[OBJECTS_DEFAULT]},
{ OBJECT_SELECT, "object_select", NULL, "obj1,...", 1, &desc[OBJECT_SELECT]},
{ NO_CMD, "", NULL, NULL, 0, &methdr},
{ METRIC_LIST, "metric_list", NULL, NULL, 0, &desc[METRIC_LIST]},
{ GMETRIC_LIST, "cmetric_list", "gmetric_list", NULL, 0, &desc[GMETRIC_LIST]},
{ INDX_METRIC_LIST, "indx_metric_list", NULL, NULL, 1, &desc[INDX_METRIC_LIST]},
{ NO_CMD, "", NULL, NULL, 0, &outhdr},
{ OUTFILE, "outfile", NULL, "filename", 1, &desc[OUTFILE]},
{ APPENDFILE, "appendfile", NULL, "filename", 1, &desc[APPENDFILE]},
{ LIMIT, "limit", NULL, "n", 1, &desc[LIMIT]},
{ NAMEFMT, "name", NULL, "{long|short|mangled}[:{soname|nosoname}]", 1, &desc[NAMEFMT]},
{ VIEWMODE, "viewmode", NULL, "{user|expert|machine}", 1, &desc[VIEWMODE]},
{ COMPARE, "compare", NULL, "{on|off|delta|ratio}", 1, &desc[COMPARE]},
{ PRINTMODE, "printmode", NULL, "string", 1, &desc[PRINTMODE]},
{ NO_CMD, "", NULL, NULL, 0, &othdr},
{ HEADER, "header", NULL, "exp_id", 1, &desc[HEADER]},
{ OBJECTS, "objects", NULL, NULL, 0, &desc[OBJECTS]},
{ OVERVIEW_NEW, "overview", NULL, NULL, 0, &desc[OVERVIEW_NEW]},
{ SAMPLE_DETAIL, "sample_detail", NULL, "exp_id", 1, &desc[SAMPLE_DETAIL]},
{ STATISTICS, "statistics", NULL, "exp_id", 1, &desc[STATISTICS]},
{ NO_CMD, "", NULL, NULL, 0, &exphdr},
{ OPEN_EXP, "open_exp", NULL, "experiment", 1, &desc[OPEN_EXP]},
{ ADD_EXP, "add_exp", NULL, "experiment", 1, &desc[ADD_EXP]},
{ DROP_EXP, "drop_exp", NULL, "experiment", 1, &desc[DROP_EXP]},
{ NO_CMD, "", NULL, NULL, 0, &deflthdr},
{ DMETRICS, "dmetrics", NULL, "metric_spec", 1, &desc[DMETRICS]},
{ DSORT, "dsort", NULL, "metric_spec", 1, &desc[DSORT]},
{ EN_DESC, "en_desc", NULL, "{on|off|=<regex>}", 1, &desc[EN_DESC]},
{ NO_CMD, "", NULL, NULL, 0, &mischdr},
{ DUMMY_CMD, "<type>", NULL, NULL, 0, &typehdr},
{ DUMMY_CMD, " ", NULL, NULL, 0, &typehdr2},
{ IFREQ, "ifreq", NULL, NULL, 0, &desc[IFREQ]},
{ PROCSTATS, "procstats", NULL, NULL, 0, &desc[PROCSTATS]},
{ SCRIPT, "script", NULL, "file", 1, &desc[SCRIPT]},
{ VERSION_cmd, "version", NULL, NULL, 0, &desc[VERSION_cmd]},
{ QUIT, "quit", "exit", NULL, 0, &desc[QUIT]},
{ NO_CMD, "", NULL, NULL, 0, &helphdr},
{ HELP, "help", NULL, NULL, 0, &desc[HELP]},
{ NO_CMD, "", NULL, NULL, 0, &unsuphdr},
{ HELP, "-help", NULL, NULL, 0, &desc[HELP]},
{ DUMPFUNC, "dfuncs", NULL, "string", 1, &desc[DUMPFUNC]},
{ DUMPDOBJS, "ddobjs", NULL, "string", 1, &desc[DUMPDOBJS]},
{ DUMPNODES, "dnodes", NULL, NULL, 0, &desc[DUMPNODES]},
{ DUMPSTACKS, "dstacks", NULL, NULL, 0, &desc[DUMPSTACKS]},
{ DUMPUNK, "dunkpc", NULL, NULL, 0, &desc[DUMPUNK]},
{ DUMPMAP, "dmap", NULL, NULL, 0, &desc[DUMPMAP]},
{ DUMPENTITIES, "dentities", NULL, NULL, 0, &desc[DUMPENTITIES]},
{ IGNORE_NO_XHWCPROF, "ignore_no_xhwcprof", NULL, NULL, 0, &desc[IGNORE_NO_XHWCPROF]},
{ IGNORE_FS_WARN, "ignore_fs_warn", NULL, NULL, 0, &desc[IGNORE_FS_WARN]},
{ DUMP_PROFILE, "dprofile", NULL, NULL, 0, &desc[DUMP_PROFILE]},
{ DUMP_SYNC, "dsync", NULL, NULL, 0, &desc[DUMP_SYNC]},
{ DUMP_IOTRACE, "diotrace", NULL, NULL, 0, &desc[DUMP_IOTRACE]},
{ DUMP_HWC, "dhwc", NULL, NULL, 0, &desc[DUMP_HWC]},
{ DUMP_HEAP, "dheap", NULL, NULL, 0, &desc[DUMP_HEAP]},
{ RACE_ACCS, "r_accs", NULL, NULL, 0, &desc[RACE_ACCS]},
{ DMPI_FUNCS, "dmpi_funcs", NULL, NULL, 0, &desc[DMPI_FUNCS]},
{ DMPI_MSGS, "dmpi_msgs", NULL, NULL, 0, &desc[DMPI_MSGS]},
{ DMPI_EVENTS, "dmpi_events", NULL, NULL, 0, &desc[DMPI_EVENTS]},
{ DMEM, "dmem", NULL, NULL, 1, &desc[DMEM]},
{ DUMP_GC, "dumpgc", NULL, NULL, 0, &desc[DUMP_GC]},
{ DKILL, "dkill", NULL, NULL, 2, &desc[DKILL]},
{ QQUIT, "xquit", NULL, NULL, 0, &desc[QQUIT]},
// use xquit for memory leak detection in dbe; it's
// like quit, but deletes all data loaded
{ HHELP, "xhelp", NULL, NULL, 0, &desc[HHELP]},
{ WHOAMI, "-whoami", NULL, NULL, 0, &desc[WHOAMI]},
// these are not recognized at this point
{ LOADOBJECT, "segments", "pmap", NULL, 0, &desc[LOADOBJECT]},
{ LOADOBJECT_LIST, "segment_list", NULL, NULL, 0, &desc[LOADOBJECT_LIST]},
{ LOADOBJECT_SELECT, "segment_select", NULL, "seg1,...", 1, &desc[LOADOBJECT_SELECT]},
{ LAST_CMD, "xxxx", NULL, NULL, 0, NULL}
};
CmdType
Command::get_command (char *cmd, int &arg_count, int &cparam)
{
int i;
int len = (int) strlen (cmd);
bool got = false;
CmdType token = UNKNOWN_CMD;
arg_count = 0;
cparam = -1;
if (*cmd == '\0') // - command
return STDIN;
if (*cmd == '#') // comment
return COMMENT;
if (strcmp (cmd, "V") == 0 || strcmp (cmd, "-version") == 0)
return VERSION_cmd;
if (strcmp (cmd, "-help") == 0)
return HELP;
if (strncmp (cmd, NTXT ("-whoami="), 8) == 0)
{
cparam = 8;
return WHOAMI;
}
if (*cmd == '-')
cmd++;
for (i = 0;; i++)
{
if (cmd_lst[i].token == LAST_CMD)
break;
if (!strncasecmp (cmd, cmd_lst[i].str, len) ||
(cmd_lst[i].alt && !strncasecmp (cmd, cmd_lst[i].alt, len)))
{
// Is it unambiguous?
if (!strcasecmp (cmd, cmd_lst[i].str)
|| (cmd_lst[i].alt && !strcasecmp (cmd, cmd_lst[i].alt)))
{
// exact, full-length match
token = cmd_lst[i].token;
arg_count = cmd_lst[i].arg_count;
return token;
}
if (got)
return AMBIGUOUS_CMD;
got = true;
token = cmd_lst[i].token;
arg_count = cmd_lst[i].arg_count;
}
}
// Did we find it?
if (token != UNKNOWN_CMD)
return token;
// See if it's the name of a index object
if (dbeSession)
{
int indxtype = dbeSession->findIndexSpaceByName (cmd);
if (indxtype >= 0)
{
// found it
cparam = indxtype;
return INDXOBJ;
}
}
return token;
}
const char *
Command::get_cmd_str (CmdType type)
{
for (int i = 0;; i++)
{
if (cmd_lst[i].token == LAST_CMD)
break;
if (type == cmd_lst[i].token)
return cmd_lst[i].str;
}
return "xxxx";
}
char *
Command::get_err_string (Cmd_status err)
{
switch (err)
{
case CMD_OK:
return NULL;
case CMD_BAD:
return GTXT ("command bad");
case CMD_AMBIGUOUS:
return GTXT ("command ambiguous");
case CMD_BAD_ARG:
return GTXT ("Invalid argument to command");
case CMD_OUTRANGE:
return GTXT ("argument to command is out-of-range");
case CMD_INVALID:
return GTXT ("invalid command");
}
return NULL;
}
void
Command::print_help (char *prog_name, bool cmd_line, bool usermode, FILE *outf)
{
char *fmt, *msg;
int i;
StringBuilder sb;
enum CmdType nc;
init_desc ();
if (usermode) // show the hidden ones, too
nc = HELP;
else
nc = HHELP;
if (cmd_line)
fprintf (outf, GTXT ("Usage: %s [ -script script | -command | - ] exper_1 ... exper_n\n"),
prog_name);
fprintf (outf, GTXT ("An alternate spelling for a command is shown in [], where applicable.\n\n"
"Those commands followed by a * may appear in .rc files.\n\n"
"Those commands followed by a $ can only appear in .rc files.\n\n"));
fmt = fmt_help (nc, ' ');
for (i = 0;; i++)
{
// check for end of list
if (cmd_lst[i].token == LAST_CMD)
break;
if (cmd_lst[i].token == NO_CMD) // this is a header line
fprintf (outf, NTXT (" %s\n"), *cmd_lst[i].desc);
else
{
if (strlen (cmd_lst[i].str) == 0)
continue;
// this is a real command line
sb.setLength (0);
sb.append (cmd_lst[i].str);
if (cmd_lst[i].alt)
{
sb.append ('[');
sb.append (cmd_lst[i].alt);
sb.append (']');
}
if (cmd_lst[i].arg)
{
sb.append (' ');
sb.append (cmd_lst[i].arg);
}
msg = sb.toString ();
fprintf (outf, fmt, msg, *cmd_lst[i].desc);
free (msg);
}
// check for end of list
if (cmd_lst[i].token == nc)
break;
}
}
// construct format for printing help
char *
Command::fmt_help (int nc, char head)
{
int len, max_len, i;
static char fmt[BUFSIZ];
max_len = 0;
for (i = 0; i < nc; i++)
{
len = (int) strlen (cmd_lst[i].str);
if (cmd_lst[i].alt)
len += (int) strlen (cmd_lst[i].alt) + 2;
if (cmd_lst[i].arg)
len += (int) strlen (cmd_lst[i].arg) + 2;
if (max_len < len)
max_len = len;
}
snprintf (fmt, sizeof (fmt), NTXT (" %c%%-%ds %%s\n"), head, max_len + 1);
return fmt;
}
void
Command::init_desc ()
{
if (desc[0] != NULL)
return;
desc[FUNCS] = GTXT ("display functions with current metrics");
desc[HOTPCS] = GTXT ("display hot PC's with current metrics");
desc[HOTLINES] = GTXT ("display hot lines with current metrics");
desc[FDETAIL] = GTXT ("display summary metrics for each function");
desc[OBJECTS] = GTXT ("display object list with errors or warnings");
desc[COMPARE] = GTXT ("enable comparison mode for experiments *");
desc[PRINTMODE] = GTXT ("set the mode for printing tables *");
desc[LDETAIL] = GTXT ("display summary metrics for each hot line");
desc[PDETAIL] = GTXT ("display summary metrics for each hot PC");
desc[SOURCE] = GTXT ("display annotated source for function/file");
desc[DISASM] = GTXT ("display annotated disassembly for function/file");
desc[SCOMPCOM] = GTXT ("set compiler commentary classes for source *");
desc[STHRESH] = GTXT ("set highlight threshold for source *");
desc[DCOMPCOM] = GTXT ("set compiler commentary classes for disasm *");
desc[COMPCOM] = GTXT ("set compiler commentary classes for both source and disasm *");
desc[DTHRESH] = GTXT ("set highlight threshold for disasm *");
desc[METRIC_LIST] = GTXT ("display the available metrics and dmetrics keywords");
desc[METRICS] = GTXT ("set a new list of metrics");
desc[SORT] = GTXT ("sort tables by the specified metric");
desc[GPROF] = GTXT ("display the callers-callees for each function");
desc[CALLTREE] = GTXT ("display the tree of function calls");
desc[CALLFLAME] = GTXT ("request calltree flame chart -- not a command, but used in the tabs command");
desc[GMETRIC_LIST] = GTXT ("display the available callers-callees metrics");
desc[FSINGLE] = GTXT ("display the summary metrics for specified function");
desc[CSINGLE] = GTXT ("display the callers-callees for the specified function");
desc[CPREPEND] = GTXT ("add specified function to the head of the callstack fragment");
desc[CAPPEND] = GTXT ("add specified function to the end of the callstack fragment");
desc[CRMFIRST] = GTXT ("remove the first function from the callstack fragment");
desc[CRMLAST] = GTXT ("remove the last function from the callstack fragment");
desc[LEAKS] = GTXT ("display memory leaks, aggregated by callstack");
desc[ALLOCS] = GTXT ("display allocations, aggregated by callstack");
desc[HEAP] = GTXT ("display memory allocations and leaks, aggregated by callstack");
desc[HEAPSTAT] = GTXT ("display heap statistics report");
desc[IOACTIVITY] = GTXT ("display I/O activity report, aggregated by file name");
desc[IOVFD] = GTXT ("display I/O activity report, aggregated by file descriptor");
desc[IOCALLSTACK] = GTXT ("display I/O activity report, aggregated by callstack");
desc[IOSTAT] = GTXT ("display I/O statistics report");
desc[RACE_ACCS] = GTXT ("dump race access events");
desc[DMPI_MSGS] = GTXT ("dump mpi messages");
desc[DMPI_FUNCS] = GTXT ("dump mpi function calls");
desc[DMPI_EVENTS] = GTXT ("dump mpi trace events");
desc[DMEM] = GTXT ("debug command for internal use");
desc[DUMP_GC] = GTXT ("dump Java garbage collector events");
desc[DKILL] = GTXT ("send process p signal s");
desc[DEADLOCK_EVNTS] = GTXT ("display deadlock events");
desc[DEADLOCK_SUM] = GTXT ("display summary for the deadlock event");
desc[HEADER] = GTXT ("display information about the experiment");
desc[OVERVIEW_NEW] = GTXT ("display the overview of all loaded experiments");
desc[SAMPLE_DETAIL] = GTXT ("display the current sample list with data");
desc[STATISTICS] = GTXT ("display the execution statistics data");
desc[EXP_LIST] = GTXT ("display the existing experiments");
desc[DESCRIBE] = GTXT ("describe recorded data and tokens available for filtering data");
desc[OBJECT_SHOW] = GTXT ("set load objects to show all functions *");
desc[OBJECT_HIDE] = GTXT ("set load objects to hide functions *");
desc[OBJECT_API] = GTXT ("set load objects to show API (entry point) only *");
desc[OBJECTS_DEFAULT] = GTXT ("reset load objects show to defaults");
desc[OBJECT_LIST] = GTXT ("display load objects, functions-shown flag");
desc[OBJECT_SELECT] = GTXT ("set list of load objects whose functions are shown");
desc[SAMPLE_LIST] = GTXT ("display the list of existing samples");
desc[SAMPLE_SELECT] = GTXT ("set a new list of samples");
desc[THREAD_LIST] = GTXT ("display the list of existing threads");
desc[THREAD_SELECT] = GTXT ("set a new list of threads");
desc[LWP_LIST] = GTXT ("display the list of existing LWPs");
desc[LWP_SELECT] = GTXT ("set a new list of LWPs");
desc[CPU_LIST] = GTXT ("display the list of CPUs");
desc[CPU_SELECT] = GTXT ("set a new list of CPUs");
desc[OUTFILE] = GTXT ("open filename for subsequent output");
desc[APPENDFILE] = GTXT ("open filename for subsequent appended output");
desc[LIMIT] = GTXT ("limit output to the first n entries (n=0 for no limit)");
desc[NAMEFMT] = GTXT ("set long/short/mangled names for functions *");
desc[VIEWMODE] = GTXT ("set viewmode user|expert|machine *");
desc[EN_DESC] = GTXT ("enable descendant processes on|off|regex matches lineage or program name $");
desc[SETPATH] = GTXT ("set search path for annotated src/dis");
desc[ADDPATH] = GTXT ("add search path for annotated src/dis *");
desc[PATHMAP] = GTXT ("remap path prefix for annotated src/dis *");
desc[LIBDIRS] = GTXT ("set path where the gprofng libraries are installed");
desc[SCRIPT] = GTXT ("read er_print commands from script file");
desc[PROCSTATS] = GTXT ("display processing statistics");
desc[ADD_EXP] = GTXT ("add experiment or group");
desc[DROP_EXP] = GTXT ("drop experiment");
desc[OPEN_EXP] = GTXT ("open experiment or group (drops all loaded experiments first)");
desc[VERSION_cmd] = GTXT ("display the current release version");
desc[HELP] = GTXT ("display the list of available commands");
desc[QUIT] = GTXT ("terminate processing and exit");
desc[DMETRICS] = GTXT ("set default function list metrics $");
desc[DSORT] = GTXT ("set default function list sort metric $");
desc[TLMODE] = GTXT ("set default timeline mode, align, depth $");
desc[TLDATA] = GTXT ("set default timeline visible data $");
desc[TABS] = GTXT ("set default visible tabs $");
desc[RTABS] = GTXT ("set default visible tabs for Thread Analyzer Experiment $");
desc[INDXOBJ] = GTXT ("display index objects of a specified type with current metrics");
desc[INDXOBJLIST] = GTXT ("display list of index objects");
desc[INDXOBJDEF] = GTXT ("define a new index object type *");
desc[INDX_METRIC_LIST] = GTXT ("display the available index object metrics");
desc[IFREQ] = GTXT ("display instruction-frequency report");
desc[TIMELINE] = GTXT ("request timeline -- not a command, but used in the tabs command");
desc[MPI_TIMELINE] = GTXT ("request mpi-timeline -- not a command, but used in the tabs command");
desc[MPI_CHART] = GTXT ("request mpi chart -- not a command, but used in the tabs command");
desc[DUALSOURCE] = GTXT ("request dualsource tab -- not a command, but used in the tabs command");
desc[SOURCEDISAM] = GTXT ("request source/disassembly tab -- not a command, but used in the tabs command");
desc[DUMPNODES] = GTXT ("dump pathtree node table");
desc[DUMPSTACKS] = GTXT ("dump Experiment callstack tables");
desc[DUMPUNK] = GTXT ("dump <Unknown> PCs");
desc[DUMPFUNC] = GTXT ("dump functions whose name matches string");
desc[DUMPDOBJS] = GTXT ("dump dataobjects whose name matches string");
desc[DUMPMAP] = GTXT ("dump load-object map");
desc[DUMPENTITIES] = GTXT ("dump threads, lwps, cpus");
desc[DUMP_PROFILE] = GTXT ("dump clock profile events");
desc[DUMP_SYNC] = GTXT ("dump synchronization trace events");
desc[DUMP_IOTRACE] = GTXT ("dump IO trace events");
desc[DUMP_HWC] = GTXT ("dump HWC profile events");
desc[DUMP_HEAP] = GTXT ("dump heap trace events");
desc[IGNORE_NO_XHWCPROF] = GTXT ("ignore absence of -xhwcprof info in dataspace profiling $");
desc[IGNORE_FS_WARN] = GTXT ("ignore filesystem (nfs, ...) warning $");
desc[HHELP] = GTXT ("display help including unsupported commands");
desc[QQUIT] = GTXT ("terminate processing and exit");
desc[LOADOBJECT] = GTXT ("display the address map with current metrics");
desc[LOADOBJECT_LIST] = GTXT ("display segments, indicating which are selected");
desc[LOADOBJECT_SELECT] = GTXT ("set a new list of segments");
desc[FILTERS] = GTXT ("define a filter");
fhdr = GTXT ("\nCommands controlling the function list:");
cchdr = GTXT ("\nCommands controlling the callers-callees and calltree lists:");
lahdr = GTXT ("\nCommands controlling the leak and allocation lists:");
iohdr = GTXT ("\nCommand controlling the I/O activity report:");
rahdr = GTXT ("\nCommands controlling the race events lists:");
ddhdr = GTXT ("\nCommands controlling the deadlock events lists:");
typehdr = GTXT ("equivalent to \"memobj type\", or \"indxobj type\"");
typehdr2 = GTXT (" where type is a memory object or index object type");
sdhdr = GTXT ("\nCommands controlling the source and disassembly listings:");
lsthdr = GTXT ("\nCommands listing experiments, samples and threads:");
lohdr = GTXT ("\nCommands controlling load object selection:");
obj_allhdr = GTXT (" the special object name `all' refers to all load objects");
methdr = GTXT ("\nCommands that list metrics:");
othdr = GTXT ("\nCommands that print other displays:");
outhdr = GTXT ("\nCommands that control output:");
mischdr = GTXT ("\nMiscellaneous commands:");
exphdr = GTXT ("\nCommands for experiments (scripts and interactive mode only):");
deflthdr = GTXT ("\nDefault-setting commands:");
selhdr = GTXT ("\nCommands controlling old-style filters/selection:");
filthdr = GTXT ("\nCommands controlling filters:");
indxobjhdr = GTXT ("\nCommands controlling the index objects:");
unsuphdr = GTXT ("\nUnsupported commands:");
helphdr = GTXT ("\nHelp command:");
}

286
gprofng/src/Command.h Normal file
View file

@ -0,0 +1,286 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _COMMAND_H
#define _COMMAND_H
#include <stdio.h>
#include <sys/types.h>
#include "Metric.h"
#include "Hist_data.h"
#include "dbe_types.h"
#include "vec.h"
#include "enums.h"
// This enum lists all the commands parsed by er_print
// The ordering here is not important, but LAST_CMD must
// be defined as the last command for which a help line will exist
// Command.cc has a matching list, and the ordering in
// that list determines what shows up under the help and xhelp commands.
// In particular, the entry for HELP is the last one printed
// for the help command, and the entry for HHELP is the last
// one printed for xhelp.
enum CmdType
{
// Pathtree-related commands
FUNCS = 0,
HOTPCS,
HOTLINES,
FDETAIL,
OBJECTS,
LDETAIL,
PDETAIL,
SOURCE,
DISASM,
METRIC_LIST,
METRICS,
SORT,
GPROF,
GMETRIC_LIST,
FSINGLE,
CSINGLE,
CPREPEND,
CAPPEND,
CRMFIRST,
CRMLAST,
CALLTREE,
CALLFLAME,
// Source/disassembly control commands
SCOMPCOM,
STHRESH,
DCOMPCOM,
COMPCOM,
DTHRESH,
// Heap trace-related commands
LEAKS,
ALLOCS,
HEAP,
HEAPSTAT,
// I/O trace-related commands
IOACTIVITY,
IOVFD,
IOCALLSTACK,
IOSTAT,
// Race detection related commands
RACE_EVNTS,
RACE_SUM,
// Deadlock detection commands
DEADLOCK_EVNTS,
DEADLOCK_SUM,
// DataSpace commands
DOBJECTS,
DO_SINGLE,
DO_LAYOUT,
DO_METRIC_LIST,
// MemorySpace commands
MEMOBJ,
MEMOBJLIST,
MEMOBJDEF,
MEMOBJDROP,
MACHINEMODEL,
// Custom tab commands
INDXOBJDEF,
INDXOBJLIST,
INDXOBJ,
INDX_METRIC_LIST,
// Old-style filtering commands
OBJECT_LIST,
OBJECT_SELECT,
SAMPLE_LIST,
SAMPLE_SELECT,
THREAD_LIST,
THREAD_SELECT,
LWP_LIST,
LWP_SELECT,
CPU_LIST,
CPU_SELECT,
// Shared Object display commands
OBJECT_SHOW,
OBJECT_HIDE,
OBJECT_API,
OBJECTS_DEFAULT,
// the new filtering commands
FILTERS,
// Miscellaneous commands
COMPARE,
PRINTMODE,
HEADER,
OVERVIEW_NEW,
SAMPLE_DETAIL,
STATISTICS,
EXP_LIST,
DESCRIBE,
OUTFILE,
APPENDFILE,
LIMIT,
NAMEFMT,
VIEWMODE,
EN_DESC,
SETPATH,
ADDPATH,
PATHMAP,
LIBDIRS,
SCRIPT,
VERSION_cmd,
QUIT,
PROCSTATS,
// Experiments handling commands
ADD_EXP,
DROP_EXP,
OPEN_EXP,
// .rc-only Commands
DMETRICS,
DSORT,
TLMODE,
TLDATA,
TABS,
TIMELINE,
MPI_TIMELINE,
MPI_CHART,
TIMELINE_CLASSIC_TBR,
SOURCE_V2,
DISASM_V2,
RTABS,
DUALSOURCE,
SOURCEDISAM,
HELP, // this is the last of the commands listed with "help"
IFREQ,
DUMPNODES,
DUMPSTACKS,
DUMPUNK,
DUMPFUNC,
DUMPDOBJS,
DUMPMAP,
DUMPENTITIES,
DUMP_PROFILE,
DUMP_SYNC,
DUMP_HWC,
DUMP_HEAP,
DUMP_IOTRACE,
RACE_ACCS,
DMPI_FUNCS,
DMPI_MSGS,
DMPI_EVENTS,
DMEM,
DUMP_GC,
DKILL,
IGNORE_NO_XHWCPROF,
IGNORE_FS_WARN,
QQUIT,
HHELP, // this is the last command listed with "xhelp"
NO_CMD, // Dummy command, used for headers in help
DUMMY_CMD, // Dummy command, used for help
// unused commands
LOADOBJECT,
LOADOBJECT_LIST,
LOADOBJECT_SELECT,
// Internal-only Commands
LAST_CMD, // No more commands for which a help line is possible
STDIN,
COMMENT,
WHOAMI,
// Error return "commands"
AMBIGUOUS_CMD,
UNKNOWN_CMD
};
typedef struct
{
const CmdType token; // command key
const char *str; // command string
const char *alt; // alternate command string
const char *arg; // argument string for help
const int arg_count; // no. of arguments
char **desc; // description for help
} Cmdtable;
// Command class: never instantiated, completely static
class Command
{
public:
// look up a string in the command table, return type, set number of args
static CmdType get_command (char *cmd, int &arg_count, int &param);
static const char *get_cmd_str (CmdType type);
static void print_help (char *prog_name, bool cmd_line, bool usermode, FILE *outf);
static char *get_err_string (Cmd_status err);
static const char *DEFAULT_METRICS; // default if no .rc files read
static const char *DEFAULT_SORT; // default if no .rc files read
static const char *DEFAULT_CMD; // token for default
static const char *ALL_CMD; // token for all
static const char *ANY_CMD; // token for any
static const char *NONE_CMD; // token for none
static const char *HWC_CMD; // token for all HWC
static const char *BIT_CMD; // token for any bit-derived metric
private:
static const int user_no; // the last user command
static const int hidden_no; // the last hidden command
static const int command_no; // the last parsable command
static void init_desc ();
static char *fmt_help (int nc, char head);
};
// Analyzer display tabs
struct DispTab
{
DispTab (int ntype, int num, bool vis, CmdType token)
{
type = ntype;
order = num;
visible = vis;
available = true;
cmdtoken = token;
}
void setAvailability (bool val) { available = val; }
int type; // Display type
int order; // Order in which tabs should appear in GUI
bool visible; // Is Tab visible
bool available; // Is tab available for this experiment
CmdType cmdtoken; // command token
int param; // command parameter (used for memory space)
};
#endif /* ! _COMMAND_H */

313
gprofng/src/CompCom.cc Normal file
View file

@ -0,0 +1,313 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>
#include <sys/param.h>
#include "demangle.h"
#include "gp-defs.h"
#include "StringBuilder.h"
#include "CompCom.h"
#include "Elf.h"
#include "util.h"
#include "i18n.h"
#include "comp_com.c"
CompComment::CompComment (Elf *_elf, int _compcom)
{
elf = _elf;
compcom = _compcom;
elf_cls = elf->elf_getclass ();
}
CompComment::~CompComment () { }
int
CompComment::get_align (int64_t offset, int align)
{
int val = (int) (offset % align);
if (val)
val = align - val;
return val;
}
/*
* Preprocesses the header structure, builds a table of messages with the line
* numbers, PCoffsets, original index, and compmsg pointer for each message.
* If the show_bits field is not in the message, this routine would fill it in
* from the mapping from COMPMSG_ID
*/
int
CompComment::compcom_open (CheckSrcName check_src)
{
if (check_src == NULL)
return 0;
Elf_Data *data = elf->elf_getdata (compcom);
uint64_t b_offset = data->d_off;
if (get_align (b_offset, 4)) // not align 4
return 0;
char *CommData = (char *) data->d_buf;
uint64_t offset = b_offset;
for (uint64_t e_offset = b_offset + data->d_size; offset < e_offset;)
{
offset += get_align (offset, (int) data->d_align);
if (offset >= e_offset)
return 0;
compcomhdr *hdr = (compcomhdr *) (CommData + (offset - b_offset));
int hdr_msgcount = elf->decode (hdr->msgcount);
int hdr_srcname = elf->decode (hdr->srcname);
int hdr_stringlen = elf->decode (hdr->stringlen);
int hdr_paramcount = elf->decode (hdr->paramcount);
size_t length = sizeof (compcomhdr) + hdr_msgcount * sizeof (compmsg) +
hdr_paramcount * sizeof (int32_t);
if (offset + length + hdr_stringlen > e_offset || hdr_srcname < 0
|| hdr_srcname >= hdr_stringlen)
return 0;
// check source file
char *src_name = (char *) (((char*) hdr) + length + hdr_srcname);
if (check_src (src_name))
{
msgs = (compmsg *) (((char *) hdr) + sizeof (compcomhdr));
params = (int32_t *) ((char *) msgs + hdr_msgcount * sizeof (compmsg));
strs = (char *) ((char *) params + hdr_paramcount * sizeof (int32_t));
// initialize the I18N/L10N strings & set the visible table
ccm_vis_init ();
return hdr_msgcount;
}
offset += (length + hdr_stringlen);
}
return 0;
}
char *
CompComment::get_demangle_name (char *fname)
{
if (*fname == '_')
return cplus_demangle (fname, DMGL_PARAMS);
return NULL;
}
/*
* takes the message, and returns the I18N string for the message.
*/
char *
CompComment::compcom_format (int index, compmsg *msg, int &visible)
{
compmsg *p = msgs + index;
msg->instaddr = elf->decode (p->instaddr);
msg->lineno = elf->decode (p->lineno);
msg->msg_type = elf->decode (p->msg_type);
msg->nparam = elf->decode (p->nparam);
msg->param_index = elf->decode (p->param_index);
int vindex = ccm_vis_index (msg->msg_type);
char *mbuf;
Ccm_Primtype_t prim_ty;
visible = ccm_attrs[vindex].vis;
if (ccm_attrs[vindex].msg == NULL)
{
/* Print CCM_UNKNOWN message */
int uindex = ccm_vis_index (CCM_UNKNOWN);
visible = ccm_attrs[uindex].vis;
return dbe_sprintf (ccm_attrs[uindex].msg, vindex);
}
/*
* Construct the output buffer based on the primitive types of the
* message parameters.
*
* Parameter lists have to be handled carefully -- the 1 parameter
* is built up of all the elements separated by ", ".
*
* Old way: Case by message format string.
*/
int *ind = params + msg->param_index;
int plist_idx = ccm_paramlist_index (msg->msg_type);
if (plist_idx <= 0)
{
/* No parameter list to handle; 0 parameters case is handled */
enum
{
MAX_COMPCOM_ARGS = 13
};
char *parms[MAX_COMPCOM_ARGS];
if (msg->nparam >= MAX_COMPCOM_ARGS)
{
fprintf (stderr,
GTXT ("Warning: improperly formatted compiler commentary message (%d parameters >= %d);\n please report this bug against the compiler\n"),
msg->nparam, MAX_COMPCOM_ARGS);
return NULL;
}
for (int i = 0; i < MAX_COMPCOM_ARGS; i++)
parms[i] = NULL; // initialize array
int prm_cnt = ccm_num_params (msg->msg_type);
if (prm_cnt != msg->nparam)
{
fprintf (stderr,
GTXT ("Warning, improperly formatted compiler commentary message (parameter count mismatch = %d, param# = %d, msg_type = %x, `%s');\n please report this bug against the compiler\n"),
prm_cnt, msg->nparam, msg->msg_type, ccm_attrs[vindex].msg);
return NULL;
}
for (int i = 0; i < msg->nparam; i++)
{
/* Parameters in message-type numbered from '1' */
prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
if (prim_ty == CCM_PRIMTYPE_INTEGER)
{
unsigned long v = elf->decode (ind[i]);
parms[i] = (char*) v;
}
else if (prim_ty == CCM_PRIMTYPE_STRING)
{
char *fname = strs + elf->decode (ind[i]);
char *demName = get_demangle_name (fname);
parms[i] = demName ? demName : dbe_strdup (fname);
}
else if (prim_ty == CCM_PRIMTYPE_HEXSTRING)
parms[i] = dbe_sprintf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"),
(unsigned long long) msg->instaddr);
else
{
fprintf (stderr,
GTXT ("Warning, improperly formatted compiler commentary message (unexpected primitive type %d);\n please report this bug against the compiler\n"),
prim_ty);
// Dummy code to avoid compiler's warning: static function ccm_param_hightype is not used
Ccm_Hitype_t hightype = CCM_HITYPE_NONE;
if (hightype != CCM_HITYPE_NONE)
hightype = ccm_param_hightype (msg->msg_type, i + 1);
return NULL;
}
}
/*
* Must make sure to pass _ALL_ params; may pass more because
* the format won't access the 'extra' parameters if all the
* rules for messages have been followed.
*/
mbuf = dbe_sprintf (ccm_attrs[vindex].msg, parms[0], parms[1], parms[2],
parms[3], parms[4], parms[5], parms[6], parms[7],
parms[8], parms[9], parms[10], parms[11]);
// Cleanup allocated memory.
for (int i = 0; i < msg->nparam; i++)
{
prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
if (prim_ty == CCM_PRIMTYPE_STRING || prim_ty == CCM_PRIMTYPE_HEXSTRING)
free (parms[i]);
}
}
else
{
/*
* Parameter list messages never have 0 parameters; the
* primitive type for the parameter list elements is always
* the same. And as of 22-Sep-2006, it was always
* CCM_PRIMTYPE_STRING.
*
* Account for different bases of parameter indices and
* 'nparam' count (1 and 0, respectively).
*/
char *parms[3];
if (plist_idx > (int) ((sizeof (parms) / sizeof (char*))))
{
fprintf (stderr,
GTXT ("Warning: improperly formatted compiler commentary message (msg->nparam=%d plist_idx=%d);\n please report this bug against the compiler\n"),
msg->nparam, plist_idx);
return NULL;
}
for (size_t i = 0; i < (sizeof (parms) / sizeof (char*)); i++)
parms[i] = NULL; // initialize array
StringBuilder sb;
prim_ty = ccm_param_primtype (msg->msg_type, plist_idx);
for (int i = plist_idx - 1; i < msg->nparam; i++)
{
if (i != plist_idx - 1)
sb.append (GTXT (", "));
if (prim_ty == CCM_PRIMTYPE_INTEGER)
sb.append (elf->decode (ind[i]));
else if (prim_ty == CCM_PRIMTYPE_STRING)
{
char *fname = strs + elf->decode (ind[i]);
char *demName = get_demangle_name (fname);
if (demName)
{
sb.append (demName);
delete demName;
}
else
sb.append (fname);
}
else if (prim_ty == CCM_PRIMTYPE_HEXSTRING)
sb.appendf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"),
(unsigned long long) msg->instaddr);
}
parms[plist_idx - 1] = sb.toString ();
for (int i = 0; i < plist_idx - 1; i++)
{
prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
if (prim_ty == CCM_PRIMTYPE_INTEGER)
{
unsigned long v = elf->decode (ind[i]);
parms[i] = (char*) v;
}
else if (prim_ty == CCM_PRIMTYPE_STRING)
{
char *fname = strs + elf->decode (ind[i]);
char *demName = get_demangle_name (fname);
parms[i] = demName ? demName : dbe_strdup (fname);
}
else if (prim_ty == CCM_PRIMTYPE_HEXSTRING)
parms[i] = dbe_sprintf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"),
(unsigned long long) msg->instaddr);
else
{
fprintf (stderr,
GTXT ("Warning, improperly formatted compiler commentary message (unexpected primitive type %d);\n please report this bug against the compiler\n"),
prim_ty);
return NULL;
}
}
/*
* We have reduced the parameter list to a single string (as
* the printf format specifier requires), so only have
* 'plist_idx' parameters.
*/
mbuf = dbe_sprintf (ccm_attrs[vindex].msg, parms[0], parms[1], parms[2]);
// Cleanup allocated memory.
free (parms[plist_idx - 1]);
for (int i = 0; i < plist_idx - 1; i++)
{
prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
if (prim_ty == CCM_PRIMTYPE_STRING || prim_ty == CCM_PRIMTYPE_STRING)
free (parms[i]);
}
}
return mbuf;
}

63
gprofng/src/CompCom.h Normal file
View file

@ -0,0 +1,63 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#ifndef _COMPCOM_H
#define _COMPCOM_H
#include <sys/types.h>
#include "comp_com.h"
class Elf;
typedef int (*CheckSrcName) (char *);
class CompComment
{
public:
CompComment (Elf *_elf, int _compcom);
~CompComment ();
int compcom_open (CheckSrcName check_src);
char *compcom_format (int index, compmsg *msg, int &visible);
private:
int get_align (int64_t, int align);
char *get_demangle_name (char *fname);
Elf *elf;
int compcom, elf_cls;
compmsg *msgs; /* the array of messages */
int32_t *params; /* the parameters used in the messages parameters are
* either integers or string-indices */
char *strs; /* the strings used in the messages */
};
class ComC
{
public:
ComC () { com_str = NULL; };
~ComC () { free (com_str); };
int sec;
int type;
int visible;
int line;
char *com_str;
};
#endif /* _COMPCOM_H */

193
gprofng/src/DataObject.cc Normal file
View file

@ -0,0 +1,193 @@
/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
#include "config.h"
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include "util.h"
#include "DbeSession.h"
#include "Application.h"
#include "DataObject.h"
#include "Module.h"
#include "debug.h"
DataObject::DataObject ()
{
name = NULL;
parent = NULL;
master = NULL;
_unannotated_name = NULL;
_typename = NULL;
_instname = NULL;
scope = NULL;
EAs = new Vector<DbeEA*>;
size = 0;
offset = (uint64_t) (-1);
}
DataObject::~DataObject ()
{
free (_unannotated_name);
free (_typename);
free (_instname);
EAs->destroy ();
delete EAs;
}
// get_addr() doesn't return an actual address for a DataObject
// but rather synthesises an address-like identifier tuple.
// XXXX since an aggregate and its first element have identical tuples
// may need to arrange for special-purpose sorting "by address"
uint64_t
DataObject::get_addr ()
{
uint64_t addr;
if (parent && parent->get_typename ())
addr = MAKE_ADDRESS (parent->id, offset); // element
else if (parent)
addr = MAKE_ADDRESS (parent->id, id) | 0x8000000000000000ULL; // Scalar, Unknown
else if (id == dbeSession->get_Scalars_DataObject ()->id)
addr = MAKE_ADDRESS (id, 0) | 0x8000000000000000ULL; // Scalar aggregate
else if (id == dbeSession->get_Unknown_DataObject ()->id)
addr = MAKE_ADDRESS (id, 0) | 0x8000000000000000ULL; // Unknown aggregate
else
addr = MAKE_ADDRESS (id, 0); // aggregate
return addr;
}
Histable *
DataObject::convertto (Histable_type type, Histable *)
{
return type == DOBJECT ? this : NULL;
}
char
DataObject::get_offset_mark ()
{
enum
{
blocksize = 32
};
if (size == 0 || offset == -1)
return '?'; // undefined
if (size > blocksize)
return '#'; // requires multiple blocks
if (size == blocksize && (offset % blocksize == 0))
return '<'; // fits block entirely
if (offset % blocksize == 0)
return '/'; // starts block
if ((offset + size) % blocksize == 0)
return '\\'; // closes block
if (offset / blocksize == ((offset + size) / blocksize))
return '|'; // inside block
return 'X'; // crosses blocks unnecessarily
}
char *
DataObject::get_offset_name ()
{
char *offset_name;
if (parent && parent->get_typename ()) // element
offset_name = dbe_sprintf (GTXT ("%c%+6lld .{%s %s}"),
get_offset_mark (), (long long) offset,
_typename ? _typename : GTXT ("NO_TYPE"),
_instname ? _instname : GTXT ("-")); // "NO_NAME"
else if ((offset != -1) && (offset > 0)) // filler
offset_name = dbe_sprintf (GTXT ("%c%+6lld %s"), get_offset_mark (),
(long long) offset, get_name ());
else if (parent) // Scalar/Unknown element
offset_name = dbe_sprintf (GTXT (" .%s"), get_unannotated_name ());
else // aggregate
offset_name = dbe_strdup (get_name ());
return offset_name;
}
void
DataObject::set_dobjname (char *type_name, char *inst_name)
{
_unannotated_name = _typename = _instname = NULL;
if (inst_name)
_instname = dbe_strdup (inst_name);
char *buf;
if (parent == dbeSession->get_Scalars_DataObject ())
{
if (type_name)
_typename = dbe_strdup (type_name);
_unannotated_name = dbe_sprintf (NTXT ("{%s %s}"), type_name,
inst_name ? inst_name : NTXT ("-"));
buf = dbe_sprintf (NTXT ("%s.%s"), parent->get_name (), _unannotated_name);
}
else if (parent == dbeSession->get_Unknown_DataObject ())
{
_unannotated_name = dbe_strdup (type_name);
buf = dbe_sprintf (NTXT ("%s.%s"), parent->get_name (), _unannotated_name);
}
else
{
if (type_name)
_typename = dbe_strdup (type_name);
if (parent && parent->get_typename ())
buf = dbe_sprintf (NTXT ("%s.{%s %s}"),
parent->get_name () ? parent->get_name () : NTXT ("ORPHAN"),
type_name ? type_name : NTXT ("NO_TYPE"),
inst_name ? inst_name : NTXT ("-")); // "NO_NAME"
else
buf = dbe_sprintf (NTXT ("{%s %s}"),
type_name ? type_name : NTXT ("NO_TYPE"),
inst_name ? inst_name : NTXT ("-")); // "NO_NAME"
}
name = buf;
dbeSession->dobj_updateHT (this);
}
void
DataObject::set_name (char *string)
{
name = dbe_strdup (string);
dbeSession->dobj_updateHT (this);
}
DbeEA *
DataObject::find_dbeEA (Vaddr EA)
{
DbeEA *dbeEA;
int left = 0;
int right = EAs->size () - 1;
while (left <= right)
{
int index = (left + right) / 2;
dbeEA = EAs->fetch (index);
if (EA < dbeEA->eaddr)
right = index - 1;
else if (EA > dbeEA->eaddr)
left = index + 1;
else
return dbeEA;
}
// None found, create a new one
dbeEA = new DbeEA (this, EA);
EAs->insert (left, dbeEA);
return dbeEA;
}

Some files were not shown because too many files have changed in this diff Show more