⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 profil.c

📁 Glibc 2.3.2源代码(解压后有100多M)
💻 C
字号:
/* Low-level statistical profiling support function.  Mach/Hurd version.   Copyright (C) 1995, 1996, 1997, 2000, 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 <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;/* 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);/* 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_tupdate_waiter (u_short *sample_buffer, size_t size, size_t offset, u_int scale){  error_t err;  if (profile_thread == MACH_PORT_NULL)    {      /* Set up the profiling collector thread.  */      static void profile_waiter (void);      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 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 voidfetch_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 voidprofile_waiter (void){  mach_msg_header_t msg;  mach_port_t timeout_reply_port;  profil_reply_port = __mach_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 voidfork_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 voidfork_profil_parent (void){  __spin_unlock (&lock);}text_set_element (_hurd_fork_parent_hook, fork_profil_parent);/* In the childs, unlock the interlock, and start a profiling thread up   if necessary. */static voidfork_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>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -