diff options
Diffstat (limited to 'sysdeps/posix/sprofil.c')
-rw-r--r-- | sysdeps/posix/sprofil.c | 355 |
1 files changed, 0 insertions, 355 deletions
diff --git a/sysdeps/posix/sprofil.c b/sysdeps/posix/sprofil.c deleted file mode 100644 index f704b9e8f4..0000000000 --- a/sysdeps/posix/sprofil.c +++ /dev/null @@ -1,355 +0,0 @@ -/* 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 <assert.h> -#include <signal.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sigsetops.h> - -#include <sys/time.h> -#include <sys/profil.h> - -#ifndef SIGPROF -# include <gmon/sprofil.c> -#else - -#include <libc-internal.h> - -struct region - { - size_t offset; - size_t nsamples; - unsigned int scale; - union - { - void *vp; - unsigned short *us; - unsigned int *ui; - } - sample; - size_t start; - size_t end; - }; - -struct prof_info - { - unsigned int num_regions; - struct region *region; - struct region *last, *overflow; - struct itimerval saved_timer; - struct sigaction saved_action; - }; - -static unsigned int overflow_counter; - -static struct region default_overflow_region = - { - .offset = 0, - .nsamples = 1, - .scale = 2, - .sample = { &overflow_counter }, - .start = 0, - .end = ~(size_t) 0 - }; - -static struct prof_info prof_info; - -static unsigned long int -pc_to_index (size_t pc, size_t offset, unsigned int scale, int prof_uint) -{ - size_t i = (pc - offset) / (prof_uint ? sizeof (int) : sizeof (short)); - - if (sizeof (unsigned long long int) > sizeof (size_t)) - return (unsigned long long int) i * scale / 65536; - else - return i / 65536 * scale + i % 65536 * scale / 65536; -} - -static inline size_t -index_to_pc (unsigned long int n, size_t offset, unsigned int scale, - int prof_uint) -{ - size_t pc, bin_size = (prof_uint ? sizeof (int) : sizeof (short)); - - if (sizeof (unsigned long long int) > sizeof (size_t)) - pc = offset + (unsigned long long int) n * bin_size * 65536ull / scale; - else - pc = (offset + n * bin_size / scale * 65536 - + n * bin_size % scale * 65536 / scale); - - if (pc_to_index (pc, offset, scale, prof_uint) < n) - /* Adjust for rounding error. */ - ++pc; - - assert (pc_to_index (pc - 1, offset, scale, prof_uint) < n - && pc_to_index (pc, offset, scale, prof_uint) >= n); - - return pc; -} - -static void -profil_count (void *pcp, int prof_uint) -{ - struct region *region, *r = prof_info.last; - size_t lo, hi, mid, pc = (unsigned long int) pcp; - unsigned long int i; - - /* Fast path: pc is in same region as before. */ - if (pc >= r->start && pc < r->end) - region = r; - else - { - /* Slow path: do a binary search for the right region. */ - lo = 0; hi = prof_info.num_regions - 1; - while (lo <= hi) - { - mid = (lo + hi) / 2; - - r = prof_info.region + mid; - if (pc >= r->start && pc < r->end) - { - prof_info.last = r; - region = r; - break; - } - - if (pc < r->start) - hi = mid - 1; - else - lo = mid + 1; - } - - /* No matching region: increment overflow count. There is no point - in updating the cache here, as it won't hit anyhow. */ - region = prof_info.overflow; - } - - i = pc_to_index (pc, region->offset, region->scale, prof_uint); - if (i < r->nsamples) - { - if (prof_uint) - { - if (r->sample.ui[i] < (unsigned int) ~0) - ++r->sample.ui[i]; - } - else - { - if (r->sample.us[i] < (unsigned short) ~0) - ++r->sample.us[i]; - } - } - else - { - if (prof_uint) - ++prof_info.overflow->sample.ui[0]; - else - ++prof_info.overflow->sample.us[0]; - } -} - -static inline void -profil_count_ushort (void *pcp) -{ - profil_count (pcp, 0); -} - -static inline void -profil_count_uint (void *pcp) -{ - profil_count (pcp, 1); -} - -/* Get the machine-dependent definition of `__profil_counter', the signal - handler for SIGPROF. It calls `profil_count' (above) with the PC of the - interrupted code. */ -#define __profil_counter __profil_counter_ushort -#define profil_count(pc) profil_count (pc, 0) -#include <profil-counter.h> - -#undef __profil_counter -#undef profil_count - -#define __profil_counter __profil_counter_uint -#define profil_count(pc) profil_count (pc, 1) -#include <profil-counter.h> - -static int -insert (int i, unsigned long int start, unsigned long int end, struct prof *p, - int prof_uint) -{ - struct region *r; - size_t to_copy; - - if (start >= end) - return 0; /* don't bother with empty regions */ - - if (prof_info.num_regions == 0) - r = malloc (sizeof (*r)); - else - r = realloc (prof_info.region, (prof_info.num_regions + 1) * sizeof (*r)); - if (r == NULL) - return -1; - - to_copy = prof_info.num_regions - i; - if (to_copy > 0) - memmove (r + i + 1, r + i, to_copy * sizeof (*r)); - - r[i].offset = p->pr_off; - r[i].nsamples = p->pr_size / (prof_uint ? sizeof (int) : sizeof (short)); - r[i].scale = p->pr_scale; - r[i].sample.vp = p->pr_base; - r[i].start = start; - r[i].end = end; - - prof_info.region = r; - ++prof_info.num_regions; - - if (p->pr_off == 0 && p->pr_scale == 2) - prof_info.overflow = r; - - return 0; -} - -/* Add a new profiling region. If the new region overlaps with - existing ones, this may add multiple subregions so that the final - data structure is free of overlaps. The absence of overlaps makes - it possible to use a binary search in profil_count(). Note that - this function depends on new regions being presented in DECREASING - ORDER of starting address. */ - -static int -add_region (struct prof *p, int prof_uint) -{ - unsigned long int nsamples; - size_t start, end; - unsigned int i; - - if (p->pr_scale < 2) - return 0; - - nsamples = p->pr_size / (prof_uint ? sizeof (int) : sizeof (short)); - - start = p->pr_off; - end = index_to_pc (nsamples, p->pr_off, p->pr_scale, prof_uint); - - /* Merge with existing regions. */ - for (i = 0; i < prof_info.num_regions; ++i) - { - if (start < prof_info.region[i].start) - { - if (end < prof_info.region[i].start) - break; - else if (insert (i, start, prof_info.region[i].start, p, prof_uint) - < 0) - return -1; - } - start = prof_info.region[i].end; - } - return insert (i, start, end, p, prof_uint); -} - -static int -pcmp (const void *left, const void *right) -{ - struct prof *l = *(struct prof **) left; - struct prof *r = *(struct prof **) right; - - if (l->pr_off < r->pr_off) - return 1; - else if (l->pr_off > r->pr_off) - return -1; - return 0; -} - -int -__sprofil (struct prof *profp, int profcnt, struct timeval *tvp, - unsigned int flags) -{ - struct prof *p[profcnt]; - struct itimerval timer; - struct sigaction act; - int i; - - if (tvp != NULL) - { - /* Return profiling period. */ - unsigned long int t = 1000000 / __profile_frequency (); - tvp->tv_sec = t / 1000000; - tvp->tv_usec = t % 1000000; - } - - if (prof_info.num_regions > 0) - { - /* Disable profiling. */ - if (__setitimer (ITIMER_PROF, &prof_info.saved_timer, NULL) < 0) - return -1; - - if (__sigaction (SIGPROF, &prof_info.saved_action, NULL) < 0) - return -1; - - free (prof_info.region); - return 0; - } - - prof_info.num_regions = 0; - prof_info.region = NULL; - prof_info.overflow = &default_overflow_region; - - for (i = 0; i < profcnt; ++i) - p[i] = profp + i; - - /* Sort in order of decreasing starting address: */ - qsort (p, profcnt, sizeof (p[0]), pcmp); - - /* Add regions in order of decreasing starting address: */ - for (i = 0; i < profcnt; ++i) - if (add_region (p[i], (flags & PROF_UINT) != 0) < 0) - { - free (prof_info.region); - prof_info.num_regions = 0; - prof_info.region = NULL; - return -1; - } - - if (prof_info.num_regions == 0) - return 0; - - prof_info.last = prof_info.region; - - /* Install SIGPROF handler. */ - if (flags & PROF_UINT) - act.sa_handler = (sighandler_t) &__profil_counter_uint; - else - act.sa_handler = (sighandler_t) &__profil_counter_ushort; - act.sa_flags = SA_RESTART; - __sigfillset (&act.sa_mask); - if (__sigaction (SIGPROF, &act, &prof_info.saved_action) < 0) - return -1; - - /* Setup profiling timer. */ - timer.it_value.tv_sec = 0; - timer.it_value.tv_usec = 1; - timer.it_interval = timer.it_value; - return __setitimer (ITIMER_PROF, &timer, &prof_info.saved_timer); -} - -weak_alias (__sprofil, sprofil) - -#endif /* SIGPROF */ |