فهرست منبع

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

Eric Andersen 22 سال پیش
والد
کامیت
12d9322b4f
2فایلهای تغییر یافته به همراه114 افزوده شده و 1 حذف شده
  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