<?xml version="1.0"?>
<!DOCTYPE webpage
  PUBLIC "-//NetBSD//DTD Website-based NetBSD Extension//EN"
         "http://www.NetBSD.org/XML/htdocs/lang/share/xml/website-netbsd.dtd">

<webpage id="docs-kernel-profiling-index">
  <config param="desc" value=""/>
  <config param="cvstag" 
    value="$NetBSD: index.xml,v 1.2 2011/01/24 00:47:56 jakllsch Exp $"/>
  <config param="rcsdate" value="$Date: 2011/01/24 00:47:56 $"/>
<head>

    <!-- Copyright (c) 1994-2005
    The NetBSD Foundation, Inc.  ALL RIGHTS RESERVED. -->

    <title>NetBSD Documentation: Kernel Profiling HOWTO</title>
  </head>


  <para>This is a description of how kernel profiling works, and how to
    use it. This documentation was written by Matthias Drochner
    <email>drochner@zel459.zel.kfa-juelich.de</email>.</para>

  <sect1 role="toc">
    <sect2 id="kern-prof">
      <title>Kernel Profiling</title>

      <sect3 id="how-does-it-work">
      <title>How does it work</title>


      <para>Two different sets of data about the behaviour
	of the profiled code are recorded independently:
	the frequency of every function call (call graph
	profiling) and the time spent in each function,
	estimated by the probability of the program counter
	being within the function when sampled at a random
	time which is in turn estimated by the fraction
	of profiling timer interrupts occurring while the
	function in question is executing.
	The &man.gprof.1; utility interprets the data. There are
	some limitations caused by the missing correlation
	between the two data sets which are noted in the BUGS
	section of its man page.</para>

      <para>Kernel profiling and user program profiling are
	mostly similar; there are only small differences
	in the way the profiling data are accessed and
	how the profiling is controlled.</para>

      <para>The data related to kernel profiling are located
	within a global structure <emphasis
	  role="bold"><code>_gmonparam</code></emphasis> which is
	initialized by <emphasis
	  role="bold"><code>kmstartup()</code></emphasis> (in
	<emphasis
	  role="bold"><filename>kern/subr_prof.c</filename></emphasis>)
	during system initialization.
	The user level control program <emphasis
	  role="bold">&man.kgmon.8;</emphasis> uses
	<emphasis role="bold">&man.sysctl.3;</emphasis> calls for
	control and data access, and partly <emphasis
	  role="bold">&man.kvm.3;</emphasis> accesses (also in the
	standard case where a live kernel is profiled!).</para>
    </sect3>

      <sect3 id="call-graph-recording">
	<title>Call graph recording</title>

	<para>The profiling flag (<emphasis
	    role="bold"><code>-pg</code></emphasis>) causes the
	  compiler to issue a call to <emphasis
	    role="bold"><code>mcount()</code></emphasis> on every
	  function entry.
	  This is dispatched by machine specific glue to
	  <emphasis
	    role="bold"><code>_mcount(frompc,selfpc)</code></emphasis>,
	  which is implemented in 
	  <emphasis
	    role="bold"><filename>sys/lib/libkern/mcount.c</filename></emphasis>.
	  <emphasis role="bold"><code>frompc</code></emphasis> is
	  the address the function was called from, and <emphasis
	    role="bold"><code>selfpc</code></emphasis> is
	  the address of the called function itself.</para>

	<para>For every (<emphasis
	    role="bold"><code>frompc</code></emphasis>, <emphasis
	    role="bold"><code>selfpc</code></emphasis>) pair
	  encountered during the profiling, a <emphasis
	    role="bold"><code>struct tostruct</code></emphasis> is
	  allocated from the array pointed to by <emphasis
	    role="bold"><code>_gmonparam.tos</code></emphasis>
	  The entries are simply allocated from the beginning
	  to the end in the order of first use. Some magic
	  within <emphasis
	    role="bold"><code>kmstartup()</code></emphasis> determines
	  the size of the array from the kernel's text size -- it
	  seems that this is kind of an "educated guess".</para>

	<para>The <emphasis role="bold"><code>struct tostruct</code></emphasis> 
	  entries contain the address of the called function
	  (<emphasis role="bold"><code>selfpc</code></emphasis>)
	  together with a histogramming counter. Entries belonging to the
	  same calling address form a linked list. The list
	  heads (ie the index of the first entry within the
	  <emphasis role="bold"><code>_gmonparam.tos</code></emphasis>
	  array belonging to a particular calling address) are located
	  in a second data array 
	  <emphasis role="bold"><code>_gmonparam.froms</code></emphasis>
	  which is indexed by the calling address 
	  (<emphasis role="bold"><code>frompc</code></emphasis>)
	  divided by some value (which should not be larger than the
	  minimal distance of two calls within the code - see also the
	  comments in <emphasis 
	    role="bold"><filename>sys/sys/gmon.h</filename></emphasis>).</para>

	<para>Note that for standard function calls there is only
	  one <emphasis role="bold"><code>selfpc</code></emphasis> for
	  each <emphasis role="bold"><code>frompc</code></emphasis>, so
	  that the typical list consists of one member only.</para>
      </sect3>

      <sect3 id="statistical-profiling">
	<title>Statistical profiling</title>

	<para>If profiling is started, a profiling timer interrupt
	  is set up which calls <emphasis
	    role="bold"><code>statclock()</code></emphasis> (see
	  <emphasis
	    role="bold"><filename>sys/kern/kern_clock.c</filename></emphasis>).
	  This should be a timer independent of the normal system
	  clock to avoid interferences with functions running
	  synchronously to system clock ticks. <emphasis
	    role="bold"><code>statclock()</code></emphasis> is used for
	  both user program and kernel profiling.</para>

	<para>The program counter at the time of the interruption,
	  divided by some value again, is used as index into
	  the histogram <emphasis
	    role="bold"><code>_gmonparam.kcount</code></emphasis> and the
	  corresponding cell is incremented.</para>
      </sect3>

      <sect3 id="how-to-use-it">
	<title>How to use it</title>


	<itemizedlist>
	  <listitem>Build and boot a profiling kernel. For this, use
	    the <emphasis role="bold"><code>-p</code></emphasis> flag to
	    <emphasis role="bold">&man.config.1;</emphasis>.
	    Otherwise, there is nothing special. The profiling kernel
	    will print a message like:
	    <screen>Profiling kernel, textsize=1611256 [f0100000..f02895f8]</screen>
	    after autoconfiguration, before the root filesystem
	    is mounted.</listitem>
	  <listitem>Make sure <emphasis
	      role="bold"><code>/netbsd</code></emphasis> is the
	    currently running kernel, or use the <emphasis
	      role="bold"><code>-N</code></emphasis> option in the
	    <emphasis role="bold">&man.kgmon.8;</emphasis>
	    invocations below.</listitem>
	  <listitem>Start profiling with <emphasis
	      role="bold"><code>kgmon -b</code></emphasis>.</listitem>
	  <listitem>Run some applications which stress the part of the
	    system you want to investigate.</listitem>
	  <listitem>Stop profiling with <emphasis
	      role="bold"><code>kgmon -h</code></emphasis>.</listitem>
	  <listitem>Run <emphasis 
	      role="bold"><code>kgmon -p</code></emphasis> to write
	    the collected data into a file <emphasis
	      role="bold"><filename>gmon.out</filename></emphasis>.</listitem>
	  <listitem>Before measuring different things, reset the
	    in-kernel profiling data buffers with <emphasis
	      role="bold"><code>kgmon -r</code></emphasis>.</listitem>
	  <listitem>To get a human readable interpretation from
	    <emphasis role="bold"><filename>gmon.out</filename></emphasis>,
	    run
	    <screen>% gprof /netbsd gmon.out &gt; gprof.txt</screen></listitem>
	  <listitem>Try to make sense of the data.</listitem>
	</itemizedlist>
      </sect3>
    </sect2>
  </sect1>

  <parentsec url="../" text="NetBSD Documentation: Kernel"/>

</webpage>

