Many UNIX systems support the profil(2) system call. This is an examining profiler that forms part of the kernel. The timer interrupt, or some other periodic timer, collects the PC value at the time of interrupt, and stores this in the relevant bin in a histogram buffer supplied by user space. This simple technique is reasonably fast, but has issues with resolution; also it is inflexible.
Linux does not implement profil(2), preferring a user space solution (see Section 3.4). For reference, version 4 of the GNU C library included a patch for a kernel implementation of profil(2).
The kernel provides the necessary support for POSIX interval timers, via setitimer(2). The timer type ITIMER_PROF counts both user-space time and the time the target process spends in the kernel, and delivers a SIGPROF signal on expiration. A profiler may install a signal handler for SIGPROF and use the si_addr field of the siginfo_t structure to collect a PC value histogram. Unfortunately this technique is low-resolution, and the use of signals can cause problems with profiler overhead.
The IA-64 port provides an interface[ia64] to the hardware performance mechanisms with the perfmonctl(2) system call. The standard IA-32 kernel features drivers for user-space access to the machine-specific registers, which can be used to set up the hardware performance counting mechanisms [ia32],[athlon].
Linux kernels from 2.5.43 onwards provide the OProfile profiler interface, discussed later.
Text-format information is available for every process in the system via the /proc file system, with a directory for each process named by its process ID. You can collect page fault data, memory usage data, and similar statistics from these files, which may be useful for characterising performance.
The /proc file formats are mostly described in the proc(5) manpage (make sure you have a recent man-pages package installed[manpages]). When in doubt, look in the kernel source (fs/proc/), and the source for top(1), ps(1), etc.