Forráskód Böngészése

Add an implementation of profil(), based on the version from
glibc, with several changes for use in uClibc.

Eric Andersen 22 éve
szülő
commit
12d9322b4f
2 módosított fájl, 114 hozzáadás és 1 törlés
  1. 1 1
      libc/sysdeps/linux/common/Makefile
  2. 113 0
      libc/sysdeps/linux/common/profil.c

+ 1 - 1
libc/sysdeps/linux/common/Makefile

@@ -26,7 +26,7 @@ CSRC=	waitpid.c getdnnm.c gethstnm.c getcwd.c ptrace.c \
 	truncate64.c getrlimit64.c setrlimit64.c creat64.c \
 	llseek.c pread_write.c _exit.c sync.c getdirname.c \
 	sendfile64.c xstatconv.c getdents.c getdents64.c vfork.c \
-	ulimit.c
+	ulimit.c profil.c
 ifneq ($(strip $(EXCLUDE_BRK)),y)
 CSRC+=sbrk.c
 endif

+ 113 - 0
libc/sysdeps/linux/common/profil.c

@@ -0,0 +1,113 @@
+/* Low-level statistical profiling support function.  Mostly POSIX.1 version.
+   Copyright (C) 1996,97,98,2002 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#ifndef SIGPROF
+
+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;
+}
+
+#else
+
+static u_short *samples;
+static size_t nsamples;
+static size_t pc_offset;
+static u_int pc_scale;
+
+static inline void
+profil_count (void *pc)
+{
+    size_t i = (pc - pc_offset - (void *) 0) / 2;
+    if (sizeof (unsigned long long int) > sizeof (size_t))
+	i = (unsigned long long int) i * pc_scale / 65536;
+    else
+	i = i / 65536 * pc_scale + i % 65536 * pc_scale / 65536;
+    if (i < nsamples)
+	++samples[i];
+}
+
+/* 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.  */
+#include <bits/profil-counter.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)
+{
+    static struct sigaction oact;
+    static struct itimerval otimer;
+    struct sigaction act;
+    struct itimerval timer;
+
+    if (sample_buffer == NULL)
+    {
+	/* Disable profiling.  */
+	if (samples == NULL)
+	    /* Wasn't turned on.  */
+	    return 0;
+
+	if (setitimer (ITIMER_PROF, &otimer, NULL) < 0)
+	    return -1;
+	samples = NULL;
+	return sigaction (SIGPROF, &oact, NULL);
+    }
+
+    if (samples)
+    {
+	/* Was already turned on.  Restore old timer and signal handler
+	   first.  */
+	if (setitimer (ITIMER_PROF, &otimer, NULL) < 0
+		|| sigaction (SIGPROF, &oact, NULL) < 0)
+	    return -1;
+    }
+
+    samples = sample_buffer;
+    nsamples = size / sizeof *samples;
+    pc_offset = offset;
+    pc_scale = scale;
+
+    act.sa_handler = (__sighandler_t) &profil_counter;
+    act.sa_flags = SA_RESTART;
+    __sigfillset (&act.sa_mask);
+    if (sigaction (SIGPROF, &act, &oact) < 0)
+	return -1;
+
+    timer.it_value.tv_sec = 0;
+    timer.it_value.tv_usec = 1;
+    timer.it_interval = timer.it_value;
+    return setitimer (ITIMER_PROF, &timer, &otimer);
+}
+
+#endif