diff options
Diffstat (limited to 'REORG.TODO/gmon')
-rw-r--r-- | REORG.TODO/gmon/Makefile | 55 | ||||
-rw-r--r-- | REORG.TODO/gmon/Versions | 22 | ||||
-rw-r--r-- | REORG.TODO/gmon/bb_exit_func.c | 74 | ||||
-rw-r--r-- | REORG.TODO/gmon/bb_init_func.c | 53 | ||||
-rw-r--r-- | REORG.TODO/gmon/gmon.c | 422 | ||||
-rw-r--r-- | REORG.TODO/gmon/mcount.c | 180 | ||||
-rw-r--r-- | REORG.TODO/gmon/prof-freq.c | 55 | ||||
-rw-r--r-- | REORG.TODO/gmon/profil.c | 40 | ||||
-rw-r--r-- | REORG.TODO/gmon/sprofil.c | 35 | ||||
-rw-r--r-- | REORG.TODO/gmon/sys/gmon.h | 201 | ||||
-rw-r--r-- | REORG.TODO/gmon/sys/gmon_out.h | 79 | ||||
-rw-r--r-- | REORG.TODO/gmon/sys/profil.h | 60 | ||||
-rw-r--r-- | REORG.TODO/gmon/tst-profile-static.c | 10 | ||||
-rw-r--r-- | REORG.TODO/gmon/tst-sprofil.c | 171 |
14 files changed, 1457 insertions, 0 deletions
diff --git a/REORG.TODO/gmon/Makefile b/REORG.TODO/gmon/Makefile new file mode 100644 index 0000000000..6ff4cb0dfb --- /dev/null +++ b/REORG.TODO/gmon/Makefile @@ -0,0 +1,55 @@ +# Copyright (C) 1995-2017 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library 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 +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <http://www.gnu.org/licenses/>. + +# +# Sub-makefile for gmon portion of the library. +# +subdir := gmon + +include ../Makeconfig + +headers := sys/gmon.h sys/gmon_out.h sys/profil.h +routines := gmon mcount profil sprofil bb_init_func bb_exit_func prof-freq + +elide-routines.os = bb_init_func bb_exit_func + +tests = tst-sprofil +ifeq ($(build-profile),yes) +tests += tst-profile-static +tests-static += tst-profile-static + +LDFLAGS-tst-profile-static = -profile +endif + +# The mcount code won't work without a frame pointer. +CFLAGS-mcount.c := -fno-omit-frame-pointer + +include ../Rules + +# We cannot compile mcount.c with -pg because that would +# create recursive calls. Just copy the normal static object. +# On systems where `profil' is not a system call, the same +# problem exists for the internal functions in profil.c. + +noprof := mcount $(sysdep_noprof) +ifeq (,$(filter profil,$(unix-syscalls))) +noprof += profil sprofil +endif + +$(noprof:%=$(objpfx)%.op): %.op: %.o + rm -f $@ + ln $< $@ diff --git a/REORG.TODO/gmon/Versions b/REORG.TODO/gmon/Versions new file mode 100644 index 0000000000..d0b63334f2 --- /dev/null +++ b/REORG.TODO/gmon/Versions @@ -0,0 +1,22 @@ +libc { + GLIBC_2.0 { + # functions with special/multiple interfaces + _mcount; + + # Profiling support + __monstartup; _mcleanup; __profile_frequency; + + # m* + monstartup; + + # p* + profil; profil_counter; + } + GLIBC_2.2 { + # m* + moncontrol; + } + GLIBC_2.2.3 { + sprofil; + } +} diff --git a/REORG.TODO/gmon/bb_exit_func.c b/REORG.TODO/gmon/bb_exit_func.c new file mode 100644 index 0000000000..3ad344a216 --- /dev/null +++ b/REORG.TODO/gmon/bb_exit_func.c @@ -0,0 +1,74 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by David Mosberger (davidm@cs.arizona.edu). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* __bb_exit_func() dumps all the basic-block statistics linked into + the __bb_head chain to .d files. */ + +#include <sys/gmon.h> +#include <sys/gmon_out.h> +#include <sys/types.h> + +#include <stdio.h> +#include <stdio_ext.h> +#include <string.h> + +#define OUT_NAME "gmon.out" + + +extern struct __bb *__bb_head attribute_hidden; + + +void +__bb_exit_func (void) +{ + const int version = GMON_VERSION; + struct gmon_hdr ghdr; + struct __bb *ptr; + FILE *fp; + fp = fopen (OUT_NAME, "wb"); + if (!fp) + { + perror (OUT_NAME); + return; + } + /* No threads use this stream. */ + __fsetlocking (fp, FSETLOCKING_BYCALLER); + + memcpy (&ghdr.cookie[0], GMON_MAGIC, 4); + memcpy (&ghdr.version, &version, sizeof (version)); + fwrite_unlocked (&ghdr, sizeof (ghdr), 1, fp); + + for (ptr = __bb_head; ptr != 0; ptr = ptr->next) + { + u_int ncounts = ptr->ncounts; + u_char tag; + u_int i; + + tag = GMON_TAG_BB_COUNT; + fwrite_unlocked (&tag, sizeof (tag), 1, fp); + fwrite_unlocked (&ncounts, sizeof (ncounts), 1, fp); + + for (i = 0; i < ncounts; ++i) + { + fwrite_unlocked (&ptr->addresses[i], sizeof (ptr->addresses[0]), 1, + fp); + fwrite_unlocked (&ptr->counts[i], sizeof (ptr->counts[0]), 1, fp); + } + } + fclose (fp); +} diff --git a/REORG.TODO/gmon/bb_init_func.c b/REORG.TODO/gmon/bb_init_func.c new file mode 100644 index 0000000000..e0fe756da8 --- /dev/null +++ b/REORG.TODO/gmon/bb_init_func.c @@ -0,0 +1,53 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by David Mosberger (davidm@cs.arizona.edu). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* __bb_init_func is invoked at the beginning of each function, before + any registers have been saved. This generic routine should work + provided that calling this function doesn't mangle the arguments + passed to the function being called. If that's not the case, a + system specific routine must be provided. */ + +#include <sys/types.h> +#include <sys/gmon.h> + +#include <stdlib.h> + +void +__bb_init_func (struct __bb *bb) +{ + struct gmonparam *p = &_gmonparam; + + if (bb->zero_word != 0) + { + return; /* handle common case quickly */ + } + + /* insert this basic-block into basic-block list: */ + bb->zero_word = 1; + bb->next = __bb_head; + __bb_head = bb; + + if (bb->next == 0 && p->state != GMON_PROF_ON) + { + /* we didn't register _mcleanup yet and pc profiling doesn't seem + to be active, so let's register it now: */ + extern void *__dso_handle __attribute__ ((__weak__)); + __cxa_atexit ((void (*) (void *)) _mcleanup, NULL, + &__dso_handle ? __dso_handle : NULL); + } +} diff --git a/REORG.TODO/gmon/gmon.c b/REORG.TODO/gmon/gmon.c new file mode 100644 index 0000000000..f394a7870e --- /dev/null +++ b/REORG.TODO/gmon/gmon.c @@ -0,0 +1,422 @@ +/*- + * Copyright (c) 1983, 1992, 1993, 2011 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <sys/param.h> +#include <sys/time.h> +#include <sys/gmon.h> +#include <sys/gmon_out.h> +#include <sys/uio.h> + +#include <errno.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <wchar.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stddef.h> +#include <unistd.h> +#include <libc-internal.h> +#include <not-cancel.h> + + +/* Head of basic-block list or NULL. */ +struct __bb *__bb_head attribute_hidden; + +struct gmonparam _gmonparam attribute_hidden = { GMON_PROF_OFF }; + +/* + * See profil(2) where this is described: + */ +static int s_scale; +#define SCALE_1_TO_1 0x10000L + +#define ERR(s) write_not_cancel (STDERR_FILENO, s, sizeof (s) - 1) + +void moncontrol (int mode); +void __moncontrol (int mode); +static void write_hist (int fd) internal_function; +static void write_call_graph (int fd) internal_function; +static void write_bb_counts (int fd) internal_function; + +/* + * Control profiling + * profiling is what mcount checks to see if + * all the data structures are ready. + */ +void +__moncontrol (int mode) +{ + struct gmonparam *p = &_gmonparam; + + /* Don't change the state if we ran into an error. */ + if (p->state == GMON_PROF_ERROR) + return; + + if (mode) + { + /* start */ + __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale); + p->state = GMON_PROF_ON; + } + else + { + /* stop */ + __profil(NULL, 0, 0, 0); + p->state = GMON_PROF_OFF; + } +} +weak_alias (__moncontrol, moncontrol) + + +void +__monstartup (u_long lowpc, u_long highpc) +{ + int o; + char *cp; + struct gmonparam *p = &_gmonparam; + + /* + * round lowpc and highpc to multiples of the density we're using + * so the rest of the scaling (here and in gprof) stays in ints. + */ + p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->textsize = p->highpc - p->lowpc; + p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms)); + p->hashfraction = HASHFRACTION; + p->log_hashfraction = -1; + /* The following test must be kept in sync with the corresponding + test in mcount.c. */ + if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) { + /* if HASHFRACTION is a power of two, mcount can use shifting + instead of integer division. Precompute shift amount. */ + p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1; + } + p->fromssize = p->textsize / HASHFRACTION; + p->tolimit = p->textsize * ARCDENSITY / 100; + if (p->tolimit < MINARCS) + p->tolimit = MINARCS; + else if (p->tolimit > MAXARCS) + p->tolimit = MAXARCS; + p->tossize = p->tolimit * sizeof(struct tostruct); + + cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1); + if (! cp) + { + ERR("monstartup: out of memory\n"); + p->tos = NULL; + p->state = GMON_PROF_ERROR; + return; + } + p->tos = (struct tostruct *)cp; + cp += p->tossize; + p->kcount = (HISTCOUNTER *)cp; + cp += p->kcountsize; + p->froms = (ARCINDEX *)cp; + + p->tos[0].link = 0; + + o = p->highpc - p->lowpc; + if (p->kcountsize < (u_long) o) + { +#ifndef hp300 + s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1; +#else + /* avoid floating point operations */ + int quot = o / p->kcountsize; + + if (quot >= 0x10000) + s_scale = 1; + else if (quot >= 0x100) + s_scale = 0x10000 / quot; + else if (o >= 0x800000) + s_scale = 0x1000000 / (o / (p->kcountsize >> 8)); + else + s_scale = 0x1000000 / ((o << 8) / p->kcountsize); +#endif + } else + s_scale = SCALE_1_TO_1; + + __moncontrol(1); +} +weak_alias (__monstartup, monstartup) + + +static void +internal_function +write_hist (int fd) +{ + u_char tag = GMON_TAG_TIME_HIST; + + if (_gmonparam.kcountsize > 0) + { + struct real_gmon_hist_hdr + { + char *low_pc; + char *high_pc; + int32_t hist_size; + int32_t prof_rate; + char dimen[15]; + char dimen_abbrev; + } thdr; + struct iovec iov[3] = + { + { &tag, sizeof (tag) }, + { &thdr, sizeof (struct gmon_hist_hdr) }, + { _gmonparam.kcount, _gmonparam.kcountsize } + }; + + if (sizeof (thdr) != sizeof (struct gmon_hist_hdr) + || (offsetof (struct real_gmon_hist_hdr, low_pc) + != offsetof (struct gmon_hist_hdr, low_pc)) + || (offsetof (struct real_gmon_hist_hdr, high_pc) + != offsetof (struct gmon_hist_hdr, high_pc)) + || (offsetof (struct real_gmon_hist_hdr, hist_size) + != offsetof (struct gmon_hist_hdr, hist_size)) + || (offsetof (struct real_gmon_hist_hdr, prof_rate) + != offsetof (struct gmon_hist_hdr, prof_rate)) + || (offsetof (struct real_gmon_hist_hdr, dimen) + != offsetof (struct gmon_hist_hdr, dimen)) + || (offsetof (struct real_gmon_hist_hdr, dimen_abbrev) + != offsetof (struct gmon_hist_hdr, dimen_abbrev))) + abort (); + + thdr.low_pc = (char *) _gmonparam.lowpc; + thdr.high_pc = (char *) _gmonparam.highpc; + thdr.hist_size = _gmonparam.kcountsize / sizeof (HISTCOUNTER); + thdr.prof_rate = __profile_frequency (); + strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen)); + thdr.dimen_abbrev = 's'; + + writev_not_cancel_no_status (fd, iov, 3); + } +} + + +static void +internal_function +write_call_graph (int fd) +{ +#define NARCS_PER_WRITEV 32 + u_char tag = GMON_TAG_CG_ARC; + struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV] + __attribute__ ((aligned (__alignof__ (char*)))); + ARCINDEX from_index, to_index; + u_long from_len; + u_long frompc; + struct iovec iov[2 * NARCS_PER_WRITEV]; + int nfilled; + + for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled) + { + iov[2 * nfilled].iov_base = &tag; + iov[2 * nfilled].iov_len = sizeof (tag); + + iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled]; + iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record); + } + + nfilled = 0; + from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms); + for (from_index = 0; from_index < from_len; ++from_index) + { + if (_gmonparam.froms[from_index] == 0) + continue; + + frompc = _gmonparam.lowpc; + frompc += (from_index * _gmonparam.hashfraction + * sizeof (*_gmonparam.froms)); + for (to_index = _gmonparam.froms[from_index]; + to_index != 0; + to_index = _gmonparam.tos[to_index].link) + { + struct arc + { + char *frompc; + char *selfpc; + int32_t count; + } + arc; + + arc.frompc = (char *) frompc; + arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc; + arc.count = _gmonparam.tos[to_index].count; + memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0])); + + if (++nfilled == NARCS_PER_WRITEV) + { + writev_not_cancel_no_status (fd, iov, 2 * nfilled); + nfilled = 0; + } + } + } + if (nfilled > 0) + writev_not_cancel_no_status (fd, iov, 2 * nfilled); +} + + +static void +internal_function +write_bb_counts (int fd) +{ + struct __bb *grp; + u_char tag = GMON_TAG_BB_COUNT; + size_t ncounts; + size_t i; + + struct iovec bbhead[2] = + { + { &tag, sizeof (tag) }, + { &ncounts, sizeof (ncounts) } + }; + struct iovec bbbody[8]; + size_t nfilled; + + for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2) + { + bbbody[i].iov_len = sizeof (grp->addresses[0]); + bbbody[i + 1].iov_len = sizeof (grp->counts[0]); + } + + /* Write each group of basic-block info (all basic-blocks in a + compilation unit form a single group). */ + + for (grp = __bb_head; grp; grp = grp->next) + { + ncounts = grp->ncounts; + writev_not_cancel_no_status (fd, bbhead, 2); + for (nfilled = i = 0; i < ncounts; ++i) + { + if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2) + { + writev_not_cancel_no_status (fd, bbbody, nfilled); + nfilled = 0; + } + + bbbody[nfilled++].iov_base = (char *) &grp->addresses[i]; + bbbody[nfilled++].iov_base = &grp->counts[i]; + } + if (nfilled > 0) + writev_not_cancel_no_status (fd, bbbody, nfilled); + } +} + + +static void +write_gmon (void) +{ + int fd = -1; + char *env; + + env = getenv ("GMON_OUT_PREFIX"); + if (env != NULL && !__libc_enable_secure) + { + size_t len = strlen (env); + char buf[len + 20]; + __snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ()); + fd = open_not_cancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666); + } + + if (fd == -1) + { + fd = open_not_cancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, + 0666); + if (fd < 0) + { + char buf[300]; + int errnum = errno; + __fxprintf (NULL, "_mcleanup: gmon.out: %s\n", + __strerror_r (errnum, buf, sizeof buf)); + return; + } + } + + /* write gmon.out header: */ + struct real_gmon_hdr + { + char cookie[4]; + int32_t version; + char spare[3 * 4]; + } ghdr; + if (sizeof (ghdr) != sizeof (struct gmon_hdr) + || (offsetof (struct real_gmon_hdr, cookie) + != offsetof (struct gmon_hdr, cookie)) + || (offsetof (struct real_gmon_hdr, version) + != offsetof (struct gmon_hdr, version))) + abort (); + memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie)); + ghdr.version = GMON_VERSION; + memset (ghdr.spare, '\0', sizeof (ghdr.spare)); + write_not_cancel (fd, &ghdr, sizeof (struct gmon_hdr)); + + /* write PC histogram: */ + write_hist (fd); + + /* write call-graph: */ + write_call_graph (fd); + + /* write basic-block execution counts: */ + write_bb_counts (fd); + + close_not_cancel_no_status (fd); +} + + +void +__write_profiling (void) +{ + int save = _gmonparam.state; + _gmonparam.state = GMON_PROF_OFF; + if (save == GMON_PROF_ON) + write_gmon (); + _gmonparam.state = save; +} +#ifndef SHARED +/* This symbol isn't used anywhere in the DSO and it is not exported. + This would normally mean it should be removed to get the same API + in static libraries. But since profiling is special in static libs + anyway we keep it. But not when building the DSO since some + quality assurance tests will otherwise trigger. */ +weak_alias (__write_profiling, write_profiling) +#endif + + +void +_mcleanup (void) +{ + __moncontrol (0); + + if (_gmonparam.state != GMON_PROF_ERROR) + write_gmon (); + + /* free the memory. */ + free (_gmonparam.tos); +} diff --git a/REORG.TODO/gmon/mcount.c b/REORG.TODO/gmon/mcount.c new file mode 100644 index 0000000000..9d4a1a50fa --- /dev/null +++ b/REORG.TODO/gmon/mcount.c @@ -0,0 +1,180 @@ +/*- + * Copyright (c) 1983, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if !defined(lint) && !defined(KERNEL) && defined(LIBC_SCCS) +static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; +#endif + +#include <unistd.h> +#include <sys/param.h> +#include <sys/gmon.h> + +/* This file provides the machine-dependent definitions of the _MCOUNT_DECL + and MCOUNT macros. */ +#include <machine-gmon.h> + +#include <atomic.h> + +/* + * mcount is called on entry to each function compiled with the profiling + * switch set. _mcount(), which is declared in a machine-dependent way + * with _MCOUNT_DECL, does the actual work and is either inlined into a + * C routine or called by an assembly stub. In any case, this magic is + * taken care of by the MCOUNT definition in <machine/profile.h>. + * + * _mcount updates data structures that represent traversals of the + * program's call graph edges. frompc and selfpc are the return + * address and function address that represents the given call graph edge. + * + * Note: the original BSD code used the same variable (frompcindex) for + * both frompcindex and frompc. Any reasonable, modern compiler will + * perform this optimization. + */ +_MCOUNT_DECL(frompc, selfpc) /* _mcount; may be static, inline, etc */ +{ + ARCINDEX *frompcindex; + struct tostruct *top, *prevtop; + struct gmonparam *p; + ARCINDEX toindex; + int i; + + p = &_gmonparam; + /* + * check that we are profiling + * and that we aren't recursively invoked. + */ + if (atomic_compare_and_exchange_bool_acq (&p->state, GMON_PROF_BUSY, + GMON_PROF_ON)) + return; + + /* + * check that frompcindex is a reasonable pc value. + * for example: signal catchers get called from the stack, + * not from text space. too bad. + */ + frompc -= p->lowpc; + if (frompc > p->textsize) + goto done; + + /* The following test used to be + if (p->log_hashfraction >= 0) + But we can simplify this if we assume the profiling data + is always initialized by the functions in gmon.c. But + then it is possible to avoid a runtime check and use the + smae `if' as in gmon.c. So keep these tests in sync. */ + if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) { + /* avoid integer divide if possible: */ + i = frompc >> p->log_hashfraction; + } else { + i = frompc / (p->hashfraction * sizeof(*p->froms)); + } + frompcindex = &p->froms[i]; + toindex = *frompcindex; + if (toindex == 0) { + /* + * first time traversing this arc + */ + toindex = ++p->tos[0].link; + if (toindex >= p->tolimit) + /* halt further profiling */ + goto overflow; + + *frompcindex = toindex; + top = &p->tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->link = 0; + goto done; + } + top = &p->tos[toindex]; + if (top->selfpc == selfpc) { + /* + * arc at front of chain; usual case. + */ + top->count++; + goto done; + } + /* + * have to go looking down chain for it. + * top points to what we are looking at, + * prevtop points to previous top. + * we know it is not at the head of the chain. + */ + for (; /* goto done */; ) { + if (top->link == 0) { + /* + * top is end of the chain and none of the chain + * had top->selfpc == selfpc. + * so we allocate a new tostruct + * and link it to the head of the chain. + */ + toindex = ++p->tos[0].link; + if (toindex >= p->tolimit) + goto overflow; + + top = &p->tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->link = *frompcindex; + *frompcindex = toindex; + goto done; + } + /* + * otherwise, check the next arc on the chain. + */ + prevtop = top; + top = &p->tos[top->link]; + if (top->selfpc == selfpc) { + /* + * there it is. + * increment its count + * move it to the head of the chain. + */ + top->count++; + toindex = prevtop->link; + prevtop->link = top->link; + top->link = *frompcindex; + *frompcindex = toindex; + goto done; + } + + } +done: + p->state = GMON_PROF_ON; + return; +overflow: + p->state = GMON_PROF_ERROR; + return; +} + +/* + * Actual definition of mcount function. Defined in <machine/profile.h>, + * which is included by <sys/gmon.h>. + */ +MCOUNT diff --git a/REORG.TODO/gmon/prof-freq.c b/REORG.TODO/gmon/prof-freq.c new file mode 100644 index 0000000000..ffcc67931b --- /dev/null +++ b/REORG.TODO/gmon/prof-freq.c @@ -0,0 +1,55 @@ +/* Return frequency of ticks reported by profil. Generic version. */ +/*- + * Copyright (c) 1983, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include <sys/types.h> +#include <sys/time.h> +#include <libc-internal.h> + +int +__profile_frequency (void) +{ + /* + * Discover the tick frequency of the machine if something goes wrong, + * we return 0, an impossible hertz. + */ + struct itimerval tim; + + tim.it_interval.tv_sec = 0; + tim.it_interval.tv_usec = 1; + tim.it_value.tv_sec = 0; + tim.it_value.tv_usec = 0; + __setitimer(ITIMER_REAL, &tim, 0); + __setitimer(ITIMER_REAL, 0, &tim); + if (tim.it_interval.tv_usec < 2) + return 0; + return (1000000 / tim.it_interval.tv_usec); +} +libc_hidden_def (__profile_frequency) diff --git a/REORG.TODO/gmon/profil.c b/REORG.TODO/gmon/profil.c new file mode 100644 index 0000000000..330e8bd996 --- /dev/null +++ b/REORG.TODO/gmon/profil.c @@ -0,0 +1,40 @@ +/* Low-level statistical profiling support function. Stub version. + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> + +/* Enable statistical profiling, writing samples of the PC into at most + SIZE bytes of SAMPLE_BUFFER; every processor clock tick while profiling + is enabled, the system examines the user PC and increments + SAMPLE_BUFFER[((PC - OFFSET) / 2) * SCALE / 65536]. If SCALE is zero, + disable profiling. Returns zero on success, -1 on error. */ + +int +__profil (u_short *sample_buffer, size_t size, size_t offset, u_int scale) +{ + if (scale == 0) + /* Disable profiling. */ + return 0; + + __set_errno (ENOSYS); + return -1; +} +weak_alias (__profil, profil) +stub_warning (profil) diff --git a/REORG.TODO/gmon/sprofil.c b/REORG.TODO/gmon/sprofil.c new file mode 100644 index 0000000000..c14ddda7fc --- /dev/null +++ b/REORG.TODO/gmon/sprofil.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2001-2017 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang <davidm@hpl.hp.com>. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> + +#include <sys/profil.h> +#include <sys/time.h> + +int +__sprofil (struct prof *profp, int profcnt, struct timeval *tvp, + unsigned int flags) +{ + if (profcnt == 0) + return 0; + + __set_errno (ENOSYS); + return -1; +} + +weak_alias (__sprofil, sprofil) diff --git a/REORG.TODO/gmon/sys/gmon.h b/REORG.TODO/gmon/sys/gmon.h new file mode 100644 index 0000000000..b4cc3b043a --- /dev/null +++ b/REORG.TODO/gmon/sys/gmon.h @@ -0,0 +1,201 @@ +/*- + * Copyright (c) 1982, 1986, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + * + * @(#)gmon.h 8.2 (Berkeley) 1/4/94 + */ + +#ifndef _SYS_GMON_H +#define _SYS_GMON_H 1 + +#include <features.h> + +#include <sys/types.h> + +/* + * See gmon_out.h for gmon.out format. + */ + +/* structure emitted by "gcc -a". This must match struct bb in + gcc/libgcc2.c. It is OK for gcc to declare a longer structure as + long as the members below are present. */ +struct __bb +{ + long zero_word; + const char *filename; + long *counts; + long ncounts; + struct __bb *next; + const unsigned long *addresses; +}; + +extern struct __bb *__bb_head; + +/* + * histogram counters are unsigned shorts (according to the kernel). + */ +#define HISTCOUNTER unsigned short + +/* + * fraction of text space to allocate for histogram counters here, 1/2 + */ +#define HISTFRACTION 2 + +/* + * Fraction of text space to allocate for from hash buckets. + * The value of HASHFRACTION is based on the minimum number of bytes + * of separation between two subroutine call points in the object code. + * Given MIN_SUBR_SEPARATION bytes of separation the value of + * HASHFRACTION is calculated as: + * + * HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1); + * + * For example, on the VAX, the shortest two call sequence is: + * + * calls $0,(r0) + * calls $0,(r0) + * + * which is separated by only three bytes, thus HASHFRACTION is + * calculated as: + * + * HASHFRACTION = 3 / (2 * 2 - 1) = 1 + * + * Note that the division above rounds down, thus if MIN_SUBR_FRACTION + * is less than three, this algorithm will not work! + * + * In practice, however, call instructions are rarely at a minimal + * distance. Hence, we will define HASHFRACTION to be 2 across all + * architectures. This saves a reasonable amount of space for + * profiling data structures without (in practice) sacrificing + * any granularity. + */ +#define HASHFRACTION 2 + +/* + * Percent of text space to allocate for tostructs. + * This is a heuristic; we will fail with a warning when profiling programs + * with a very large number of very small functions, but that's + * normally OK. + * 2 is probably still a good value for normal programs. + * Profiling a test case with 64000 small functions will work if + * you raise this value to 3 and link statically (which bloats the + * text size, thus raising the number of arcs expected by the heuristic). + */ +#define ARCDENSITY 3 + +/* + * Always allocate at least this many tostructs. This + * hides the inadequacy of the ARCDENSITY heuristic, at least + * for small programs. + */ +#define MINARCS 50 + +/* + * The type used to represent indices into gmonparam.tos[]. + */ +#define ARCINDEX unsigned long + +/* + * Maximum number of arcs we want to allow. + * Used to be max representable value of ARCINDEX minus 2, but now + * that ARCINDEX is a long, that's too large; we don't really want + * to allow a 48 gigabyte table. + * The old value of 1<<16 wasn't high enough in practice for large C++ + * programs; will 1<<20 be adequate for long? FIXME + */ +#define MAXARCS (1 << 20) + +struct tostruct { + unsigned long selfpc; + long count; + ARCINDEX link; +}; + +/* + * a raw arc, with pointers to the calling site and + * the called site and a count. + */ +struct rawarc { + unsigned long raw_frompc; + unsigned long raw_selfpc; + long raw_count; +}; + +/* + * general rounding functions. + */ +#define ROUNDDOWN(x,y) (((x)/(y))*(y)) +#define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y)) + +/* + * The profiling data structures are housed in this structure. + */ +struct gmonparam { + long int state; + unsigned short *kcount; + unsigned long kcountsize; + ARCINDEX *froms; + unsigned long fromssize; + struct tostruct *tos; + unsigned long tossize; + long tolimit; + unsigned long lowpc; + unsigned long highpc; + unsigned long textsize; + unsigned long hashfraction; + long log_hashfraction; +}; + +/* + * Possible states of profiling. + */ +#define GMON_PROF_ON 0 +#define GMON_PROF_BUSY 1 +#define GMON_PROF_ERROR 2 +#define GMON_PROF_OFF 3 + +/* + * Sysctl definitions for extracting profiling information from the kernel. + */ +#define GPROF_STATE 0 /* int: profiling enabling variable */ +#define GPROF_COUNT 1 /* struct: profile tick count buffer */ +#define GPROF_FROMS 2 /* struct: from location hash bucket */ +#define GPROF_TOS 3 /* struct: destination/count structure */ +#define GPROF_GMONPARAM 4 /* struct: profiling parameters (see above) */ + +__BEGIN_DECLS + +/* Set up data structures and start profiling. */ +extern void __monstartup (unsigned long __lowpc, unsigned long __highpc) __THROW; +extern void monstartup (unsigned long __lowpc, unsigned long __highpc) __THROW; + +/* Clean up profiling and write out gmon.out. */ +extern void _mcleanup (void) __THROW; + +__END_DECLS + +#endif /* sys/gmon.h */ diff --git a/REORG.TODO/gmon/sys/gmon_out.h b/REORG.TODO/gmon/sys/gmon_out.h new file mode 100644 index 0000000000..4bd504c9e0 --- /dev/null +++ b/REORG.TODO/gmon/sys/gmon_out.h @@ -0,0 +1,79 @@ +/* Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by David Mosberger <davidm@cs.arizona.edu>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* This file specifies the format of gmon.out files. It should have + as few external dependencies as possible as it is going to be included + in many different programs. That is, minimize the number of #include's. + + A gmon.out file consists of a header (defined by gmon_hdr) followed by + a sequence of records. Each record starts with a one-byte tag + identifying the type of records, followed by records specific data. */ + +#ifndef _SYS_GMON_OUT_H +#define _SYS_GMON_OUT_H 1 + +#include <features.h> + +#define GMON_MAGIC "gmon" /* magic cookie */ +#define GMON_VERSION 1 /* version number */ + +/* For profiling shared object we need a new format. */ +#define GMON_SHOBJ_VERSION 0x1ffff + +__BEGIN_DECLS + +/* + * Raw header as it appears on file (without padding). This header + * always comes first in gmon.out and is then followed by a series + * records defined below. + */ +struct gmon_hdr + { + char cookie[4]; + char version[4]; + char spare[3 * 4]; + }; + +/* types of records in this file: */ +typedef enum + { + GMON_TAG_TIME_HIST = 0, + GMON_TAG_CG_ARC = 1, + GMON_TAG_BB_COUNT = 2 + } GMON_Record_Tag; + +struct gmon_hist_hdr + { + char low_pc[sizeof (char *)]; /* base pc address of sample buffer */ + char high_pc[sizeof (char *)]; /* max pc address of sampled buffer */ + char hist_size[4]; /* size of sample buffer */ + char prof_rate[4]; /* profiling clock rate */ + char dimen[15]; /* phys. dim., usually "seconds" */ + char dimen_abbrev; /* usually 's' for "seconds" */ + }; + +struct gmon_cg_arc_record + { + char from_pc[sizeof (char *)]; /* address within caller's body */ + char self_pc[sizeof (char *)]; /* address within callee's body */ + char count[4]; /* number of arc traversals */ + }; + +__END_DECLS + +#endif /* sys/gmon_out.h */ diff --git a/REORG.TODO/gmon/sys/profil.h b/REORG.TODO/gmon/sys/profil.h new file mode 100644 index 0000000000..0c50d1857c --- /dev/null +++ b/REORG.TODO/gmon/sys/profil.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2001-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _PROFIL_H +#define _PROFIL_H 1 + +#include <features.h> + +#include <sys/time.h> +#include <sys/types.h> + +/* This interface is intended to follow the sprofil() system calls as + described by the sprofil(2) man page of Irix v6.5, except that: + + - there is no a priori limit on number of text sections + - pr_scale is declared as unsigned long (instead of "unsigned int") + - pr_size is declared as size_t (instead of "unsigned int") + - pr_off is declared as void * (instead of "__psunsigned_t") + - the overflow bin (pr_base==0, pr_scale==2) can appear anywhere + in the profp array + - PROF_FAST has no effect */ + +struct prof + { + void *pr_base; /* buffer base */ + size_t pr_size; /* buffer size */ + size_t pr_off; /* pc offset */ + unsigned long int pr_scale; /* pc scaling (fixed-point number) */ + }; + +enum + { + PROF_USHORT = 0, /* use 16-bit counters (default) */ + PROF_UINT = 1 << 0, /* use 32-bit counters */ + PROF_FAST = 1 << 1 /* profile faster than usual */ + }; + + +__BEGIN_DECLS + +extern int sprofil (struct prof *__profp, int __profcnt, + struct timeval *__tvp, unsigned int __flags) __THROW; + +__END_DECLS + +#endif /* profil.h */ diff --git a/REORG.TODO/gmon/tst-profile-static.c b/REORG.TODO/gmon/tst-profile-static.c new file mode 100644 index 0000000000..b2f371e782 --- /dev/null +++ b/REORG.TODO/gmon/tst-profile-static.c @@ -0,0 +1,10 @@ +#include <stdio.h> +static int +do_test (void) +{ + puts ("Hello world"); + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/REORG.TODO/gmon/tst-sprofil.c b/REORG.TODO/gmon/tst-sprofil.c new file mode 100644 index 0000000000..b9a8e04cc1 --- /dev/null +++ b/REORG.TODO/gmon/tst-sprofil.c @@ -0,0 +1,171 @@ +/* Copyright (C) 2001-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by David Mosberger-Tang <davidm@hpl.hp.com>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/profil.h> + +#include <bits/wordsize.h> + +#define NELEMS(a) (sizeof (a)/sizeof ((a)[0])) + +size_t taddr[] = + { + 0x00001000, /* elf32/hppa */ + 0x08048000, /* Linux elf32/x86 */ + 0x80000000, /* Linux elf32/m68k */ + 0x00400000, /* Linux elf32/mips */ + 0x01800000, /* Linux elf32/ppc */ + 0x00010000 /* Linux elf32/sparc */ +#if __WORDSIZE > 32 + , + 0x4000000000000000, /* Linux elf64/ia64 */ + 0x0000000120000000, /* Linux elf64/alpha */ + 0x4000000000001000, /* elf64/hppa */ + 0x0000000100000000 /* Linux elf64/sparc */ +#endif + }; + +unsigned int buf[NELEMS (taddr)][0x10000 / sizeof (int)]; +unsigned int bshort[5][0x100 / sizeof (int)]; +unsigned int blong[1][0x1000 / sizeof (int)]; +unsigned int vlong[1][0x2000 / sizeof (int)]; + +static long int +fac (long int n) +{ + if (n == 0) + return 1; + return n * fac (n - 1); +} + +int +main (int argc, char **argv) +{ + unsigned int ovfl = 0, profcnt = 0; + struct timeval tv, start; + struct prof prof[32]; + double t_tick, delta; + long int sum = 0; + int i, j; + + for (i = 0; i < NELEMS (taddr); ++i) + { + prof[profcnt].pr_base = buf[i]; + prof[profcnt].pr_size = sizeof (buf[i]); + prof[profcnt].pr_off = taddr[i]; + prof[profcnt].pr_scale = 0x10000; + ++profcnt; + } + + prof[profcnt].pr_base = blong[0]; + prof[profcnt].pr_size = sizeof (blong[0]); + prof[profcnt].pr_off = 0x80001000; + prof[profcnt].pr_scale = 0x10000; + ++profcnt; + + prof[profcnt].pr_base = bshort[0]; + prof[profcnt].pr_size = sizeof (bshort[0]); + prof[profcnt].pr_off = 0x80000080; + prof[profcnt].pr_scale = 0x10000; + ++profcnt; + + prof[profcnt].pr_base = bshort[1]; + prof[profcnt].pr_size = sizeof (bshort[1]); + prof[profcnt].pr_off = 0x80000f80; + prof[profcnt].pr_scale = 0x10000; + ++profcnt; + + prof[profcnt].pr_base = bshort[2]; + prof[profcnt].pr_size = sizeof (bshort[2]); + prof[profcnt].pr_off = 0x80001080; + prof[profcnt].pr_scale = 0x10000; + ++profcnt; + + prof[profcnt].pr_base = bshort[3]; + prof[profcnt].pr_size = sizeof (bshort[3]); + prof[profcnt].pr_off = 0x80001f80; + prof[profcnt].pr_scale = 0x10000; + ++profcnt; + + prof[profcnt].pr_base = bshort[4]; + prof[profcnt].pr_size = sizeof (bshort[4]); + prof[profcnt].pr_off = 0x80002080; + prof[profcnt].pr_scale = 0x10000; + ++profcnt; + + prof[profcnt].pr_base = vlong[0]; + prof[profcnt].pr_size = sizeof (vlong[0]); + prof[profcnt].pr_off = 0x80000080; + prof[profcnt].pr_scale = 0x10000; + ++profcnt; + + /* Set up overflow counter (must be last on Irix). */ + prof[profcnt].pr_base = &ovfl; + prof[profcnt].pr_size = sizeof (ovfl); + prof[profcnt].pr_off = 0; + prof[profcnt].pr_scale = 2; + ++profcnt; + + /* Turn it on. */ + if (sprofil (prof, profcnt, &tv, PROF_UINT) < 0) + { + if (errno == ENOSYS) + exit (0); + perror ("sprofil"); + exit (1); + } + + t_tick = tv.tv_sec + 1e-6 * tv.tv_usec; + printf ("profiling period = %g ms\n", 1e3 * t_tick); + + gettimeofday (&start, NULL); + do + { + for (i = 0; i < 21; ++i) + sum += fac (i); + + gettimeofday (&tv, NULL); + timersub (&tv, &start, &tv); + delta = tv.tv_sec + 1e-6 * tv.tv_usec; + } + while (delta < 1000 * t_tick); + + printf ("sum = 0x%lx\n", sum); + + /* Turn it off. */ + if (sprofil (NULL, 0, NULL, 0) < 0) + { + if (errno == ENOSYS) + exit (0); + perror ("sprofil"); + exit (1); + } + + printf ("overflow = %u\n", ovfl); + for (i = 0; i < NELEMS (taddr); ++i) + for (j = 0; j < 0x10000 / sizeof (int); ++j) + if (buf[i][j] != 0) + printf ("%0*Zx\t%u\t(buffer %d)\n", + (int) (sizeof (size_t) * 2), + (taddr[i] + ((char *) &buf[i][j] - (char *) &buf[i][0])), + buf[i][j], i); + + return 0; +} |