Chapter 32
Profiling Support: liboskit_gprof.a

32.1 Introduction

The gprof program and associated libc and kernel routines provide a mechanism to produce an execution profile of an oskit-based kernel. The gprof program is linked right into the kernel, performing its data reduction and analysis just before the kernel exits and producing output to the console device. See gprof(1) for more information.

32.2 Caveats

The application to be profiled must be called “a.out”.

It is expected that the current behavior of generating ASCII output to the console device will be changed in the future. For example, the interface might be modified to allow specification of an oskit_stream object (Section 4) to which the binary “gmon.out” data would be written. Typically, this object would refer to a persistent file or a network connection with another machine.

See Section 32.4 for line-by-line instructions on using gprof in the OSKit, including some non-obvious linking magic. You may need to link against additional libraries to use gprof on your kernel; If your kernel does not use a bmod filesystem, you’ll need to additionally link against the memfs library.

32.3 API reference

32.3.1 profil: Enable, disable, or change statistical sampling

SYNOPSIS

#include <oskit/c/sys/gmon.h>

#include <oskit/c/sys/profile.h>

int profil(char *samples, int size, int offset, int scale);

DESCRIPTION

This function enables or disables the statistical sampling of the program counter for the kernel. If profiling is enabled, at RTC clock tick (see below), the program counter is recorded in the samples buffer. This function is most frequently called by moncontrol().

PARAMETERS
samples:
A buffer containing size bytes which is divided into a number of bins. A bin represents a range of addresses in which the PC was found when the profiling sample was taken.
size:
The size in bytes of the samples array.
offset:
The lowest address at which PC samples should be taken. In the oskit, this defaults to the location of the _start symbol.
scale:
The scale determines the granularity of the bins. A scale of 65536 means each bin gets 2 bytes of address range. A scale of 32768 gives 4 byte, etc. A scale value of 0 disables profiling.
RETURNS

Returns 0 if all is OK, or -1 on error. Sets errno to the reason for failure.

32.3.2 moncontrol: enable or disable profiling

SYNOPSIS

#include <oskit/c/sys/gmon.h>

#include <oskit/c/sys/profile.h>

void moncontrol(int mode);

DESCRIPTION

If mode is non-zero (true), enables profiling. If mode is zero, disables profiling.

PARAMETERS
mode:
Determines if profiling should be enabled or disabled

32.3.3 monstartup: Start profiling for the first time

SYNOPSIS

#include <oskit/c/sys/gmon.h>

#include <oskit/c/sys/profile.h>

void monstartup(unsigned long *lowpc, unsigned long *highpc);

DESCRIPTION

monstartup initiates profiling of the kernel; it should only be called once. Note that by default, monstartup is called by base_multiboot_main when profiling is enabled with configure. If you wish to delay profiling until a later time, disable the monstartup call in base_multiboot_main, and place your own call to monstartup later in your code.

PARAMETERS
lowpc:
The lowest address for which statistics should be collected. Usually the location of the _start symbol.
highpc:
The highest address for which statistics should be collected. Usually the location of the etext (end of text segment) symbol.

32.4 Using gprof

  1. Configure your sources with -enable-profiling
  2. When you link your program, link against:
    1. the _p versions of all libraries you would normally use
    2. the .po versions of all .o files you would use except crtn.o and multiboot.o (if you use them)
    3. Insert “-loskit_gprof -loskit_kern_p -loskit_c_p” immediately after the existing “-loskit_kern_p -loskit_c_p.” That’s right, another instance of the kern and C libs. If you use the FreeBSD C library, do the analogous thing. If the above doesn’t work, try including the libs more times (yes, this is bogus).
    4. Be sure to include the following libraries:
      • oskit_dev_p
      • oskit_lmm_p
      • oskit_memfs_p
  3. Run mkbsdimage multiboot_kernel multiboot_kernel:a.out
    or
    mkmbimage multiboot_kernel multiboot_kernel:a.out

    This step is necessary so gprof can access the kernel’s symbol table via the bmodfs.

  4. Run the kernel (if created as above, it would be named Image).
  5. Profiling output will be spit out at its exit.

32.5 Files

32.6 Changing parameters and other FAQs

32.6.1 The sampling rate

The default sampling rate is 8192 Hz, using the RTC as the source of the sampling interrupts. You can adjust this by modifying one #define in gmon.h:

Redefine #define PROFHZ xxxx to the sampling rate.

The rate you select must be a power of 2 between 128 and 8192.

32.6.2 How can I temporarily disable gprof’s output while still linking it in?

in base_console.c, change int enable_gprof = 1; to = 0.

32.6.3 Why isn’t there a command line option for it?

The FreeBSD boot manager won’t pass in the -p flag.

32.6.4 Why don’t my assembly routines register properly with mcount?

You need to hand-code stubs for them which call __mcount. Sorry. The compiler only autogenerates the _mcount stubs for C routines. The call to __mcount is performed for you if you use the oskit ENTRY() macro.

32.6.5 Why is the call graph wrong when a routine was called from an assembly function?

If you don’t use one of the oskit ENTRY macros, then your function’s symbol may not be declared properly. If you want to do it by hand, then declare the symbol:

             .globl symbol_name
             .type  symbol_name,@function
         

Note that this is taken care of for you by the macros in asm.h if you simply declare a function with ENTRY(x) or NON_GPROF_ENTRY(x).

32.6.6 What will gprof break?

Gprof takes over the RTC (irq 8). If you have code which uses the oskit interrupt request mechanism to grab irq 8, it won’t work. If your code just steals irq 8 by replacing the interrupt handler for it, you’ll break gprof.

Gprof installs some atexit handlers for the kernel ‘main’. These are installed in base_multiboot_main.c.