diff options
Diffstat (limited to 'sysdeps/mach/hurd/profil.c')
-rw-r--r-- | sysdeps/mach/hurd/profil.c | 285 |
1 files changed, 0 insertions, 285 deletions
diff --git a/sysdeps/mach/hurd/profil.c b/sysdeps/mach/hurd/profil.c deleted file mode 100644 index 6830e0facc..0000000000 --- a/sysdeps/mach/hurd/profil.c +++ /dev/null @@ -1,285 +0,0 @@ -/* Low-level statistical profiling support function. Mach/Hurd 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> -#include <hurd.h> -#include <mach/mach4.h> -#include <mach/pc_sample.h> -#include <cthreads.h> -#include <assert.h> -#include <libc-internal.h> - - -#define MAX_PC_SAMPLES 512 /* XXX ought to be exported in kernel hdr */ - -static thread_t profile_thread = MACH_PORT_NULL; -static u_short *samples; -static size_t maxsamples; -static size_t pc_offset; -static size_t sample_scale; -static sampled_pc_seqno_t seqno; -static spin_lock_t lock = SPIN_LOCK_INITIALIZER; -static mach_msg_timeout_t collector_timeout; /* ms between collections. */ -static int profile_tick; - -/* Reply port used by profiler thread */ -static mach_port_t profil_reply_port = MACH_PORT_NULL; - -/* Forwards */ -static kern_return_t profil_task_get_sampled_pcs (mach_port_t, - sampled_pc_seqno_t *, - sampled_pc_array_t, - mach_msg_type_number_t *); -static void fetch_samples (void); -static void profile_waiter (void); - -/* 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. */ - -static error_t -update_waiter (u_short *sample_buffer, size_t size, size_t offset, u_int scale) -{ - error_t err; - - if (profile_thread == MACH_PORT_NULL) - { - if (profil_reply_port == MACH_PORT_NULL) - profil_reply_port = __mach_reply_port (); - /* Set up the profiling collector thread. */ - err = __thread_create (__mach_task_self (), &profile_thread); - if (! err) - err = __mach_setup_thread (__mach_task_self (), profile_thread, - &profile_waiter, NULL, NULL); - } - else - err = 0; - - if (! err) - { - err = __task_enable_pc_sampling (__mach_task_self (), &profile_tick, - SAMPLED_PC_PERIODIC); - if (!err && sample_scale == 0) - /* Profiling was not turned on, so the collector thread was - suspended. Resume it. */ - err = __thread_resume (profile_thread); - if (! err) - { - samples = sample_buffer; - maxsamples = size / sizeof *sample_buffer; - pc_offset = offset; - sample_scale = scale; - /* Calculate a good period for the collector thread. From TICK - and the kernel buffer size we get the length of time it takes - to fill the buffer; translate that to milliseconds for - mach_msg, and chop it in half for general lag factor. */ - collector_timeout = MAX_PC_SAMPLES * profile_tick / 1000 / 2; - } - } - - return err; -} - -int -__profile_frequency (void) -{ - return 1000000 / profile_tick; -} -libc_hidden_def (__profile_frequency) - -int -__profil (u_short *sample_buffer, size_t size, size_t offset, u_int scale) -{ - error_t err; - - __spin_lock (&lock); - - if (scale == 0) - { - /* Disable profiling. */ - int count; - - if (profile_thread != MACH_PORT_NULL) - __thread_suspend (profile_thread); - - /* Fetch the last set of samples */ - if (sample_scale) - fetch_samples (); - - err = __task_disable_pc_sampling (__mach_task_self (), &count); - sample_scale = 0; - seqno = 0; - } - else - err = update_waiter (sample_buffer, size, offset, scale); - - __spin_unlock (&lock); - - return err ? __hurd_fail (err) : 0; -} -weak_alias (__profil, profil) - -/* Fetch PC samples. This function must be very careful not to depend - on Hurd threadvar variables. We arrange that by using a special - stub arranged for at the end of this file. */ -static void -fetch_samples (void) -{ - sampled_pc_t pc_samples[MAX_PC_SAMPLES]; - mach_msg_type_number_t nsamples, i; - error_t err; - - nsamples = MAX_PC_SAMPLES; - - err = profil_task_get_sampled_pcs (__mach_task_self (), &seqno, - pc_samples, &nsamples); - if (err) - { - static error_t special_profil_failure; - static volatile int a, b, c; - - special_profil_failure = err; - a = 1; - b = 0; - while (1) - c = a / b; - } - - for (i = 0; i < nsamples; ++i) - { - /* Do arithmetic in long long to avoid overflow problems. */ - long long pc_difference = pc_samples[i].pc - pc_offset; - size_t idx = ((pc_difference / 2) * sample_scale) / 65536; - if (idx < maxsamples) - ++samples[idx]; - } -} - - -/* This function must be very careful not to depend on Hurd threadvar - variables. We arrange that by using special stubs arranged for at the - end of this file. */ -static void -profile_waiter (void) -{ - mach_msg_header_t msg; - mach_port_t timeout_reply_port; - - timeout_reply_port = __mach_reply_port (); - - while (1) - { - __spin_lock (&lock); - - fetch_samples (); - - __spin_unlock (&lock); - - __mach_msg (&msg, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, sizeof msg, - timeout_reply_port, collector_timeout, MACH_PORT_NULL); - } -} - -/* Fork interaction */ - -/* Before fork, lock the interlock so that we are in a clean state. */ -static void -fork_profil_prepare (void) -{ - __spin_lock (&lock); -} -text_set_element (_hurd_fork_prepare_hook, fork_profil_prepare); - -/* In the parent, unlock the interlock once fork is complete. */ -static void -fork_profil_parent (void) -{ - __spin_unlock (&lock); -} -text_set_element (_hurd_fork_parent_hook, fork_profil_parent); - -/* In the child, unlock the interlock, and start a profiling thread up - if necessary. */ -static void -fork_profil_child (void) -{ - u_short *sb; - size_t n, o, ss; - error_t err; - - __spin_unlock (&lock); - - if (profile_thread != MACH_PORT_NULL) - { - __mach_port_deallocate (__mach_task_self (), profile_thread); - profile_thread = MACH_PORT_NULL; - } - - sb = samples; - samples = NULL; - n = maxsamples; - maxsamples = 0; - o = pc_offset; - pc_offset = 0; - ss = sample_scale; - sample_scale = 0; - - if (ss != 0) - { - err = update_waiter (sb, n * sizeof *sb, o, ss); - assert_perror (err); - } -} -text_set_element (_hurd_fork_child_hook, fork_profil_child); - - - - -/* Special RPC stubs for profile_waiter are made by including the normal - source code, with special CPP state to prevent it from doing the - usual thing. */ - -/* Include these first; then our #define's will take full effect, not - being overridden. */ -#include <mach/mig_support.h> - -/* This need not do anything; it is always associated with errors, which - are fatal in profile_waiter anyhow. */ -#define __mig_put_reply_port(foo) - -/* Use our static variable instead of the usual threadvar mechanism for - this. */ -#define __mig_get_reply_port() profil_reply_port - -/* Make the functions show up as static */ -#define mig_external static - -/* Turn off the attempt to generate ld aliasing records. */ -#undef weak_alias -#define weak_alias(a,b) - -/* And change their names to avoid confusing disasters. */ -#define __vm_deallocate_rpc profil_vm_deallocate -#define __task_get_sampled_pcs profil_task_get_sampled_pcs - -/* And include the source code */ -#include <../mach/RPC_task_get_sampled_pcs.c> |