Remove support for call profiling

The entire infrastructure relied on an ACK feature, and as such, it
has been broken for years now, with no easy way to repair it.

Change-Id: I783c2a21276967af115a642199f31fef0f14a572
This commit is contained in:
David van Moolenbroek 2014-09-30 12:31:44 +00:00
parent e5808135dd
commit 1dcfbcd173
31 changed files with 26 additions and 1279 deletions

View file

@ -288,7 +288,7 @@
./usr/bin/cpio minix-sys
./usr/bin/cpp minix-sys gcccmds
./usr/bin/cpp minix-sys llvm
./usr/bin/cprofalyze minix-sys
./usr/bin/cprofalyze minix-sys obsolete
./usr/bin/crc minix-sys
./usr/bin/cron minix-sys
./usr/bin/crontab minix-sys

View file

@ -910,7 +910,6 @@
#define __learn_tree ___learn_tree
#if defined(__minix)
#define cprofile _cprofile /* LSC: Is this really needed? */
#define sprofile _sprofile /* LSC: Is this really needed? */
/* Needed to allow RS and VM to provide their own implementations. */

View file

@ -1,7 +1,6 @@
# Makefile for profile and cprofalyze.pl
# Makefile for profile
PROG= profile
SCRIPTS= cprofalyze.pl
MAN=
.include <bsd.prog.mk>

View file

@ -1,273 +0,0 @@
#!/usr/pkg/bin/perl
#
# cprofalyze.pl
#
# Analyzes the output files created by the profile command for
# Call Profiling.
#
# Changes:
# 14 Aug, 2006 Created (Rogier Meurs)
#
$UNSIGNED_MAX_DIV_K = 2**32/1000;
if ($#ARGV == 0 || process_args(@ARGV)) {
print "Usage:\n";
print " cprofalyze.pl <clock> [-f] [-aoct] [-i] [-n number] file ...\n\n";
print " clock CPU clock of source machine in MHz (mandatory)\n";
print " -f print totals per function (original order lost)\n";
print " -a sort alphabetically (default)\n";
print " -o no sort (original order)\n";
print " -c sort by number of calls\n";
print " -t sort by time spent\n";
print " -n print maximum of number lines per process\n";
print " -i when -[ao] used: print full paths\n";
exit 1;
}
sub process_args {
$_ = shift;
return 1 unless /^(\d+)$/;
return 1 if $1 == 0;
$MHz = $1;
$sort_method = "A";
while (@_[0] =~ /^-/) {
$_ = shift;
SWITCH: {
if (/^-a$/) { $sort_method = "A"; last SWITCH; }
if (/^-o$/) { $sort_method = "O"; last SWITCH; }
if (/^-c$/) { $sort_method = "C"; last SWITCH; }
if (/^-t$/) { $sort_method = "T"; last SWITCH; }
if (/^-i$/) { $print_full_paths = 1; last SWITCH; }
if (/^-f$/) { $print_totals = 1; last SWITCH; }
if (/^-n$/) {
$_ = shift;
return 1 unless /^(\d+)$/;
return 1 unless $1 > 0;
$show_paths = $1;
last SWITCH;
}
return 1;
}
}
$print_full_paths == 1 && ($sort_method eq "T" || $sort_method eq "C") &&
{ $print_full_paths = 0 };
@files = @_;
return 0;
}
print <<EOF;
Notes:
- Calls attributed to a path are calls done on that call level.
For instance: a() is called once and calls b() twice. Call path "a" is
attributed 1 call, call path "a b" is attributed 2 calls.
- Time spent blocking is included.
- Time attributed to a path is time spent on that call level.
For instance: a() spends 10 cycles in its own body and calls b() which
spends 5 cycles in its body. Call path "a" is attributed 10 cycles,
call path "a b" is attributed 5 cycles.
- Time is attributed when a function exits. Functions calls that have not
returned yet are therefore not measured. This is most notable in main
functions that are printed as having zero cycles.
- When "profile reset" was run, the actual resetting in a process happens
when a function is entered. In some processes (for example, blocking
ones) this may not happen immediately, or at all.
EOF
print "Clockspeed entered: $MHz MHz. ";
SWITCH: {
if ($sort_method eq "A")
{ print "Sorting alphabetically. "; last SWITCH; }
if ($sort_method eq "C")
{ print "Sorting by calls. "; last SWITCH; }
if ($sort_method eq "T")
{ print "Sorting by time spent. "; last SWITCH; }
print "No sorting applied. ";
}
print "\n";
$print_totals and print "Printing totals per function. ";
$show_paths == 0 ? print "Printing all call paths.\n" :
print "Printing max. $show_paths lines per process.\n";
foreach $file (@files) {
$file_res = read_file($file);
next if $file_res == 0;
print_file($print_totals ? make_totals($file_res) : $file_res);
}
exit 0;
sub read_file
{
$file = shift;
my %file_res = ();
my @exe;
my $exe_name, $slots_used, $buf, $lo, $hi, $cycles_div_k, $ms;
unless (open(FILE, $file)) {
print "\nERROR: Unable to open $file: $!\n";
return 0;
}
$file =~ s/^.*\///; # basename
# First line: check file type.
$_ = <FILE>; chomp;
if (!/^call$/) {
if (/^stat$/) {
print "Statistical Profiling output file: ";
print "Use sprofalyze.pl instead.\n";
} else {
print "Not a profiling output file.\n";
}
return 0;
}
# Second line: header with call path string size.
$_ = <FILE>; chomp;
($CPATH_MAX_LEN, $PROCNAME_LEN) = split(/ /);
$SLOT_SIZE = $CPATH_MAX_LEN + 16;
$EXE_HEADER_SIZE = $PROCNAME_LEN + 4;
# Read in the data for all the processes and put it in a hash of lists.
# A list for each process, which contains lists itself for each call
# path.
until(eof(FILE)) {
read(FILE, $buf, $EXE_HEADER_SIZE) == $EXE_HEADER_SIZE or
die ("Short read.");
($exe_name, $slots_used) = unpack("Z${PROCNAME_LEN}i", $buf);
@exe = ();
for ($i=0; $i<$slots_used; $i++) {
read(FILE, $buf, $SLOT_SIZE) == $SLOT_SIZE or
die ("Short read.");
($chain, $cpath, $calls, $lo, $hi) =
unpack("iA${CPATH_MAX_LEN}iII", $buf);
$cycles_div_k = $hi * $UNSIGNED_MAX_DIV_K;
$cycles_div_k += $lo / 1000;
$ms = $cycles_div_k / $MHz;
push @exe, [ ($cpath, $calls, $ms) ];
}
$file_res{$exe_name} = [ @exe ];
}
return \%file_res;
}
# Aggregate calls and cycles of paths into totals for each function.
sub make_totals
{
my $ref = shift;
my %file_res = %{$ref};
my $exe;
my %res, %calls, %time;
my @totals;
foreach $exe (sort keys %file_res) {
@totals = ();
%calls = ();
%time = ();
@ar = @{$file_res{$exe}};
foreach $path (@ar) {
$_ = $path->[0];
s/^.* //; # basename of call path
$calls{$_} += $path->[1];
$time{$_} += $path->[2];
}
foreach $func (keys %calls) {
push @totals, [ ($func, $calls{$func}, $time{$func}) ];
}
$res{$exe} = [ @totals ];
}
return \%res;
}
sub print_file
{
my $ref = shift;
my %file_res = %{$ref};
my $exe;
printf "\n========================================";
printf "========================================\n";
printf("Data file: %s\n", $file);
printf "========================================";
printf "========================================\n\n";
# If we have the kernel, print it first. Then the others.
print_exe($file_res{"kernel"}, "kernel") if exists($file_res{"kernel"});
foreach $exe (sort keys %file_res) {
print_exe($file_res{$exe}, $exe) unless $exe eq "kernel";
}
}
sub print_exe
{
my $ref = shift;
my $name = shift;
my @exe = @{$ref};
my @funcs, @oldfuncs;
my $slots_used = @exe;
# Print a header.
printf "----------------------------------------";
printf "----------------------------------------\n";
$print_totals ? printf "%-8s %60s functions\n", $name, $slots_used :
printf "%-8s %59s call paths\n", $name, $slots_used;
printf "----------------------------------------";
printf "----------------------------------------\n";
printf("%10s %12s path\n", "calls", "msecs");
printf "----------------------------------------";
printf "----------------------------------------\n";
SWITCH: {
if ($sort_method eq "A") {
@exe = sort { lc($a->[0]) cmp lc($b->[0]) } @exe; last SWITCH; }
if ($sort_method eq "C") {
@exe = reverse sort { $a->[1] <=> $b->[1] } @exe; last SWITCH; }
if ($sort_method eq "T") {
@exe = reverse sort { $a->[2] <=> $b->[2] } @exe; last SWITCH; }
last SWITCH;
}
my $paths;
@oldfuncs = ();
foreach $path (@exe) {
printf("%10u %12.2f ", $path->[1], $path->[2]);
if ($print_full_paths == 1 ||
($sort_method eq "C" || $sort_method eq "T")) {
print $path->[0];
} else {
@funcs = split(/ /, $path->[0]);
for (my $j=0; $j<=$#funcs; $j++) {
if ($j<=$#oldfuncs && $funcs[$j] eq $oldfuncs[$j]) {
print " ---";
} else {
print " " if ($j > 0);
print $funcs[$j];
}
}
@oldfuncs = @funcs;
}
print "\n";
last if (++$paths == $show_paths);
}
print "\n";
}

View file

@ -1,6 +1,6 @@
/* profile - profile operating system
*
* The profile command is used to control Statistical and Call Profiling.
* The profile command is used to control statistical profiling.
* It writes the profiling data collected by the kernel to a file.
*
* Changes:
@ -27,14 +27,8 @@
#define START 1
#define STOP 2
#define GET 3
#define RESET 4
#define SPROF (action==START||action==STOP)
#define CPROF (!SPROF)
#define DEF_OUTFILE_S "profile.stat.out"
#define DEF_OUTFILE_C "profile.call.out"
#define DEF_OUTFILE (SPROF?DEF_OUTFILE_S:DEF_OUTFILE_C)
#define DEF_OUTFILE "profile.stat.out"
#define NPIPE "/tmp/profile.npipe"
#define MIN_MEMSIZE 1
#define DEF_MEMSIZE 64
@ -55,7 +49,6 @@ char *outfile = "";
char *mem_ptr;
int outfile_fd, npipe_fd;
struct sprof_info_s sprof_info;
struct cprof_info_s cprof_info;
#define HASH_MOD 128
struct sproc {
@ -69,13 +62,10 @@ static struct sproc * proc_hash[HASH_MOD];
int handle_args(int argc, char *argv[]);
int start(void);
int stop(void);
int get(void);
int reset(void);
int create_named_pipe(void);
int alloc_mem(void);
int init_outfile(void);
int write_outfile(void);
int write_outfile_cprof(void);
int write_outfile_sprof(void);
void detach(void);
@ -119,17 +109,14 @@ int main(int argc, char *argv[])
return 1;
}
printf("Statistical Profiling:\n");
printf("Usage:\n");
printf(" profile start [--rtc | --nmi] "
"[-m memsize] [-o outfile] [-f frequency]\n");
printf(" profile stop\n\n");
printf(" --rtc is default, --nmi allows kernel profiling\n");
printf("Call Profiling:\n");
printf(" profile get [-m memsize] [-o outfile]\n");
printf(" profile reset\n\n");
printf(" - --rtc is default, --nmi allows kernel profiling\n");
printf(" - memsize in MB, default: %u\n", DEF_MEMSIZE);
printf(" - default output file: profile.{stat|call}.out\n");
printf( " - sample frequencies for --rtc (default: %u):\n", DEF_FREQ);
printf(" - default output file: profile.stat.out\n");
printf(" - sample frequencies for --rtc (default: %u):\n", DEF_FREQ);
printf(" 3 8192 Hz 10 64 Hz\n");
printf(" 4 4096 Hz 11 32 Hz\n");
printf(" 5 2048 Hz 12 16 Hz\n");
@ -137,7 +124,7 @@ int main(int argc, char *argv[])
printf(" 7 512 Hz 14 4 Hz\n");
printf(" 8 256 Hz 15 2 Hz\n");
printf(" 9 128 Hz\n\n");
printf("Use [sc]profalyze.pl to analyze output file.\n");
printf("Use sprofalyze to analyze output file.\n");
return 1;
}
@ -148,12 +135,6 @@ int main(int argc, char *argv[])
case STOP:
if (stop()) return 1;
break;
case GET:
if (get()) return 1;
break;
case RESET:
if (reset()) return 1;
break;
default:
break;
}
@ -197,14 +178,6 @@ int handle_args(int argc, char *argv[])
if (strcmp(*argv, "stop") == 0) {
if (action) return EACTION;
action = STOP;
} else
if (strcmp(*argv, "get") == 0) {
if (action) return EACTION;
action = GET;
} else
if (strcmp(*argv, "reset") == 0) {
if (action) return EACTION;
action = RESET;
}
}
@ -212,12 +185,10 @@ int handle_args(int argc, char *argv[])
if (!action) return EHELP;
/* Init unspecified parameters. */
if (action == START || action == GET) {
if (action == START) {
if (strcmp(outfile, "") == 0) outfile = DEF_OUTFILE;
if (mem_size == 0) mem_size = DEF_MEMSIZE;
mem_size *= MB; /* mem_size in bytes */
}
if (action == START) {
mem_size -= mem_size % sizeof(struct sprof_sample); /* align to sample size */
if (freq == 0) freq = DEF_FREQ; /* default frequency */
}
@ -325,69 +296,6 @@ int stop()
}
int get()
{
/* Get function for call profiling.
*
* Create output file. Allocate memory. Perform system call to get
* profiling table and write it to file. Clean up.
*/
if (init_outfile()) return 1;
printf("Getting call profiling data.\n");
if (alloc_mem()) return 1;
if (cprofile(PROF_GET, mem_size, &cprof_info, mem_ptr)) {
perror("cprofile");
fprintf(stderr, "Error getting data.\n");
return 1;
}
mem_used = cprof_info.mem_used;
if (mem_used == -1) {
fprintf(stderr, "ERROR: unable to get data due to insufficient memory.\n");
fprintf(stderr, "Try increasing available memory using the -m switch.\n");
} else
if (cprof_info.err) {
fprintf(stderr, "ERROR: the following error(s) happened during profiling:\n");
if (cprof_info.err & CPROF_CPATH_OVERRUN)
fprintf(stderr, " call path overrun\n");
if (cprof_info.err & CPROF_STACK_OVERRUN)
fprintf(stderr, " call stack overrun\n");
if (cprof_info.err & CPROF_TABLE_OVERRUN)
fprintf(stderr, " hash table overrun\n");
fprintf(stderr, "Try changing values in /usr/src/include/minix/profile.h ");
fprintf(stderr, "and then rebuild the system.\n");
} else
if (write_outfile()) return 1;
close(outfile_fd);
free(mem_ptr);
return 0;
}
int reset()
{
/* Reset function for call profiling.
*
* Perform system call to reset profiling table.
*/
printf("Resetting call profiling data.\n");
if (cprofile(PROF_RESET, 0, 0, 0)) {
perror("cprofile");
fprintf(stderr, "Error resetting data.\n");
return 1;
}
return 0;
}
int alloc_mem()
{
if ((mem_ptr = malloc(mem_size)) == 0) {
@ -465,13 +373,9 @@ int write_outfile()
printf("Writing to %s ...", outfile);
/* Write header. */
if (SPROF)
sprintf(header, "stat\n%u %u %u\n", sizeof(struct sprof_info_s),
sizeof(struct sprof_sample),
sizeof(struct sprof_proc));
else
sprintf(header, "call\n%u %u\n",
CPROF_CPATH_MAX_LEN, CPROF_PROCNAME_LEN);
sprintf(header, "stat\n%u %u %u\n", sizeof(struct sprof_info_s),
sizeof(struct sprof_sample),
sizeof(struct sprof_proc));
n = write(outfile_fd, header, strlen(header));
@ -480,60 +384,13 @@ int write_outfile()
return 1;
}
/* for sprofile, raw data will do; cprofile is handled by a script that needs
* some preprocessing to be done by us
*/
if (SPROF) {
written = write_outfile_sprof();
} else {
written = write_outfile_cprof();
}
written = write_outfile_sprof();
if (written < 0) return -1;
printf(" header %d bytes, data %d bytes.\n", strlen(header), written);
return 0;
}
int write_outfile_cprof()
{
int towrite, written = 0;
struct sprof_sample *sample;
/* Write data. */
towrite = mem_used == -1 ? mem_size : mem_used;
sample = (struct sprof_sample *) mem_ptr;
while (towrite > 0) {
unsigned bytes;
char entry[12];
char * name;
name = get_proc_name(sample->proc);
if (!name) {
add_proc((struct sprof_proc *)sample);
bytes = sizeof(struct sprof_proc);
towrite -= bytes;
sample = (struct sprof_sample *)(((char *) sample) + bytes);
continue;
}
memset(entry, 0, 12);
memcpy(entry, name, strlen(name));
memcpy(entry + 8, &sample->pc, 4);
if (write(outfile_fd, entry, 12) != 12) {
fprintf(stderr, "Error writing to outfile %s.\n", outfile);
return -1;
}
towrite -= sizeof(struct sprof_sample);
sample++;
written += 12;
}
return written;
}
int write_outfile_sprof()
{
int towrite;

View file

@ -50,7 +50,7 @@
#define PM_REBOOT (PM_BASE + 37)
#define PM_SVRCTL (PM_BASE + 38)
#define PM_SPROF (PM_BASE + 39)
#define PM_CPROF (PM_BASE + 40)
/* PM call number 40 is currently unused. */
#define PM_SRV_FORK (PM_BASE + 41)
#define PM_SRV_KILL (PM_BASE + 42)
#define PM_EXEC_NEW (PM_BASE + 43)

View file

@ -238,8 +238,6 @@
# define SYS_READBIOS (KERNEL_CALL + 35) /* sys_readbios() */
# define SYS_SPROF (KERNEL_CALL + 36) /* sys_sprof() */
# define SYS_CPROF (KERNEL_CALL + 37) /* sys_cprof() */
# define SYS_PROFBUF (KERNEL_CALL + 38) /* sys_profbuf() */
# define SYS_STIME (KERNEL_CALL + 39) /* sys_stime() */
# define SYS_SETTIME (KERNEL_CALL + 40) /* sys_settime() */
@ -272,7 +270,7 @@
#define SYS_BASIC_CALLS \
SYS_EXIT, SYS_SAFECOPYFROM, SYS_SAFECOPYTO, SYS_VSAFECOPY, SYS_GETINFO, \
SYS_TIMES, SYS_SETALARM, SYS_SETGRANT, \
SYS_PROFBUF, SYS_DIAGCTL, SYS_STATECTL, SYS_SAFEMEMSET
SYS_DIAGCTL, SYS_STATECTL, SYS_SAFEMEMSET
/* Field names for SYS_DEVIO, SYS_VDEVIO, SYS_SDEVIO. */
# define _DIO_INPUT 0x001

View file

@ -89,7 +89,6 @@
/* Enable or disable system profiling. */
#define SPROFILE 0 /* statistical profiling */
#define CPROFILE 0 /* call profiling */
/* PCI configuration parameters */
#define NR_PCIBUS 40

View file

@ -419,16 +419,6 @@ typedef struct {
} mess_lc_ipc_shmget;
_ASSERT_MSG_SIZE(mess_lc_ipc_shmget);
typedef struct {
int action;
vir_bytes ctl_ptr;
vir_bytes mem_ptr;
size_t mem_size;
uint8_t padding[40];
} mess_lc_pm_cprof;
_ASSERT_MSG_SIZE(mess_lc_pm_cprof);
typedef struct {
vir_bytes name;
size_t namelen;
@ -1027,17 +1017,6 @@ typedef struct {
} mess_lsys_krn_sys_copy;
_ASSERT_MSG_SIZE(mess_lsys_krn_sys_copy);
typedef struct {
endpoint_t endpt;
int action;
vir_bytes ctl_ptr;
vir_bytes mem_ptr;
size_t mem_size;
uint8_t padding[36];
} mess_lsys_krn_sys_cprof;
_ASSERT_MSG_SIZE(mess_lsys_krn_sys_cprof);
typedef struct {
int request;
int port;
@ -1135,14 +1114,6 @@ typedef struct {
} mess_lsys_krn_sys_privctl;
_ASSERT_MSG_SIZE(mess_lsys_krn_sys_privctl);
typedef struct {
vir_bytes ctl_ptr;
vir_bytes mem_ptr;
uint8_t padding[48];
} mess_lsys_krn_sys_profbuf;
_ASSERT_MSG_SIZE(mess_lsys_krn_sys_profbuf);
typedef struct {
int request;
long int port;
@ -2075,7 +2046,6 @@ typedef struct {
mess_lc_ipc_shmctl m_lc_ipc_shmctl;
mess_lc_ipc_shmdt m_lc_ipc_shmdt;
mess_lc_ipc_shmget m_lc_ipc_shmget;
mess_lc_pm_cprof m_lc_pm_cprof;
mess_lc_pm_exec m_lc_pm_exec;
mess_lc_pm_exit m_lc_pm_exit;
mess_lc_pm_getsid m_lc_pm_getsid;
@ -2143,7 +2113,6 @@ typedef struct {
mess_lsys_krn_sys_abort m_lsys_krn_sys_abort;
mess_lsys_krn_sys_clear m_lsys_krn_sys_clear;
mess_lsys_krn_sys_copy m_lsys_krn_sys_copy;
mess_lsys_krn_sys_cprof m_lsys_krn_sys_cprof;
mess_lsys_krn_sys_devio m_lsys_krn_sys_devio;
mess_lsys_krn_sys_diagctl m_lsys_krn_sys_diagctl;
mess_lsys_krn_sys_exec m_lsys_krn_sys_exec;
@ -2154,7 +2123,6 @@ typedef struct {
mess_lsys_krn_sys_irqctl m_lsys_krn_sys_irqctl;
mess_lsys_krn_sys_memset m_lsys_krn_sys_memset;
mess_lsys_krn_sys_privctl m_lsys_krn_sys_privctl;
mess_lsys_krn_sys_profbuf m_lsys_krn_sys_profbuf;
mess_lsys_krn_sys_sdevio m_lsys_krn_sys_sdevio;
mess_lsys_krn_sys_setalarm m_lsys_krn_sys_setalarm;
mess_lsys_krn_sys_setgrant m_lsys_krn_sys_setgrant;

View file

@ -5,8 +5,7 @@
#include <sys/types.h>
/*
* Types relating to system profiling. Types are supplied for both
* statistical profiling and call profiling.
* Types relating to system profiling.
*/
# define PROF_START 0 /* start statistical profiling */
@ -35,72 +34,7 @@ struct sprof_proc {
char name[PROC_NAME_LEN];
};
# define PROF_GET 2 /* get call profiling tables */
# define PROF_RESET 3 /* reset call profiling tables */
/* Hash table size in each profiled process is table size + index size.
*
* Table size = CPROF_TABLE_SIZE * (CPROF_CPATH_MAX_LEN + 16).
* Index size = CPROF_INDEX_SIZE * 4;
*
* Making CPROF_CPATH_MAX_LEN too small may cause call path overruns.
* Making CPROF_TABLE_SIZE too small may cause table overruns.
*
* There are some restrictions: processes in the boot image are loaded
* below 16 MB and the kernel is loaded in lower memory (below 640 kB). The
* latter is reason to use a different size for the kernel table.
*/
#define CPROF_TABLE_SIZE_OTHER 3000 /* nr of slots in hash table */
#define CPROF_TABLE_SIZE_KERNEL 1500 /* kernel has a smaller table */
#define CPROF_CPATH_MAX_LEN 256 /* len of cpath string field: */
/* MUST BE MULTIPLE OF WORDSIZE */
#define CPROF_INDEX_SIZE (10*1024)/* size of index to hash table */
#define CPROF_STACK_SIZE 24 /* size of call stack */
#define CPROF_PROCNAME_LEN 8 /* len of proc name field */
#define CPROF_CPATH_OVERRUN 0x1 /* call path overrun */
#define CPROF_STACK_OVERRUN 0x2 /* call stack overrun */
#define CPROF_TABLE_OVERRUN 0x4 /* hash table overrun */
#define CPROF_ANNOUNCE_OTHER 1 /* processes announce their profiling
* data on n-th entry of procentry */
#define CPROF_ACCOUNCE_KERNEL 10000 /* kernel announces not directly */
/* Prototype for function called by procentry to get size of table. */
int profile_get_tbl_size(void);
/* Prototype for function called by procentry to get announce number. */
int profile_get_announce(void);
/* Prototype for function called by procentry to announce control struct
* and table locations to the kernel. */
void profile_register(void *ctl_ptr, void *tbl_ptr);
/* Info struct to be copied from kernel to user program. */
struct cprof_info_s {
int mem_used;
int err;
};
/* Data structures for control structure and profiling data table in the
* in the profiled processes.
*/
struct cprof_ctl_s {
int reset; /* kernel sets to have table reset */
int slots_used; /* proc writes nr slots used in table */
int err; /* proc writes errors that occurred */
};
struct cprof_tbl_s {
struct cprof_tbl_s *next; /* next in chain */
char cpath[CPROF_CPATH_MAX_LEN]; /* string with call path */
int calls; /* nr of executions of path */
u64_t cycles; /* execution time of path, in cycles */
};
int sprofile(int action, int size, int freq, int type, void *ctl_ptr,
void *mem_ptr);
int cprofile(int action, int size, void *ctl_ptr, void *mem_ptr);
#endif /* PROFILE_H */

View file

@ -250,9 +250,6 @@ int pci_get_bar(int devind, int port, u32_t *base, u32_t *size, int
/* Profiling. */
int sys_sprof(int action, int size, int freq, int type, endpoint_t
endpt, void *ctl_ptr, void *mem_ptr);
int sys_cprof(int action, int size, endpoint_t endpt, void *ctl_ptr,
void *mem_ptr);
int sys_profbuf(void *ctl_ptr, void *mem_ptr);
/* machine context */
int sys_getmcontext(endpoint_t proc, vir_bytes mcp);

View file

@ -44,7 +44,6 @@ void bsp_finish_booting(void)
#if SPROFILE
sprofiling = 0; /* we're not profiling until instructed to */
#endif /* SPROFILE */
cprof_procs_no = 0; /* init nr of hash table slots used */
cpu_identify();

View file

@ -1,15 +1,6 @@
/*
* This file contains several functions and variables used for system
* profiling.
*
* Statistical Profiling:
* The interrupt handler for profiling clock.
*
* Call Profiling:
* The table used for profiling data and a function to get its size.
*
* The function used by kernelspace processes to register the locations
* of their control struct and profiling table.
* This file contains several functions and variables used for statistical
* system profiling, in particular the interrupt handler for profiling clock.
*
* Changes:
* 14 Aug, 2006 Created, (Rogier Meurs)
@ -169,55 +160,3 @@ void nmi_sprofile_handler(struct nmi_frame * frame)
}
#endif /* SPROFILE */
#if CPROFILE
/*
* The following variables and functions are used by the procentry/
* procentry syslib functions when linked with kernelspace processes.
* For userspace processes, the same variables and function are defined
* elsewhere. This enables different functionality and variable sizes,
* which is needed is a few cases.
*/
/* A small table is declared for the kernelspace processes. */
struct cprof_tbl_s cprof_tbl[CPROF_TABLE_SIZE_KERNEL];
/* Function that returns table size. */
int profile_get_tbl_size(void)
{
return CPROF_TABLE_SIZE_KERNEL;
}
/* Function that returns on which execution of procentry to announce. */
int profile_get_announce(void)
{
return CPROF_ACCOUNCE_KERNEL;
}
/*
* The kernel "announces" its control struct and table locations
* to itself through this function.
*/
void profile_register(ctl_ptr, tbl_ptr)
void *ctl_ptr;
void *tbl_ptr;
{
int proc_nr;
vir_bytes vir_dst;
struct proc *rp;
if(cprof_procs_no >= NR_SYS_PROCS)
return;
/* Store process name, control struct, table locations. */
rp = proc_addr(SYSTEM);
cprof_proc_info[cprof_procs_no].endpt = rp->p_endpoint;
cprof_proc_info[cprof_procs_no].name = rp->p_name;
cprof_proc_info[cprof_procs_no].ctl_v = (vir_bytes) ctl_ptr;
cprof_proc_info[cprof_procs_no].buf_v = (vir_bytes) tbl_ptr;
cprof_procs_no++;
}
#endif

View file

@ -21,18 +21,5 @@ void nmi_sprofile_handler(struct nmi_frame * frame);
#endif /* SPROFILE */
EXTERN int cprof_mem_size; /* available user memory for data */
EXTERN struct cprof_info_s cprof_info; /* profiling info for user program */
EXTERN int cprof_procs_no; /* number of profiled processes */
EXTERN struct cprof_proc_info_s { /* info about profiled process */
endpoint_t endpt; /* endpoint */
char *name; /* name */
vir_bytes ctl_v; /* location of control struct */
vir_bytes buf_v; /* location of buffer */
int slots_used; /* table slots used */
} cprof_proc_info_inst;
EXTERN struct cprof_proc_info_s cprof_proc_info[NR_SYS_PROCS];
#endif /* PROFILE_H */

View file

@ -246,8 +246,6 @@ void system_init(void)
/* Profiling. */
map(SYS_SPROF, do_sprofile); /* start/stop statistical profiling */
map(SYS_CPROF, do_cprofile); /* get/reset call profiling data */
map(SYS_PROFBUF, do_profbuf); /* announce locations to kernel */
/* arm-specific. */
#if defined(__arm__)

View file

@ -186,13 +186,6 @@ int do_sprofile(struct proc * caller, message *m_ptr);
#define do_sprofile NULL
#endif
int do_cprofile(struct proc * caller, message *m_ptr);
int do_profbuf(struct proc * caller, message *m_ptr);
#if ! CPROFILE
#define do_cprofile NULL
#define do_profbuf NULL
#endif
int do_getmcontext(struct proc * caller, message *m_ptr);
int do_setmcontext(struct proc * caller, message *m_ptr);
#if ! USE_MCONTEXT

View file

@ -33,8 +33,6 @@ SRCS+= \
do_sigreturn.c \
do_abort.c \
do_getinfo.c \
do_cprofile.c \
do_profbuf.c \
do_vmctl.c \
do_mcontext.c \
do_schedule.c \

View file

@ -1,152 +0,0 @@
/* The kernel call that is implemented in this file:
* m_type: SYS_CPROF
*
* The parameters for this kernel call are:
* m_lsys_krn_cprof.action (get/reset profiling data)
* m_lsys_krn_cprof.mem_size (available memory for data)
* m_lsys_krn_cprof.endpt (endpoint of caller)
* m_lsys_krn_cprof.ctl_ptr (location of info struct)
* m_lsys_krn_cprof.mem_ptr (location of memory for data)
*
* Changes:
* 14 Aug, 2006 Created (Rogier Meurs)
*/
#include "kernel/system.h"
#include <string.h>
#if CPROFILE
static struct cprof_ctl_s cprof_ctl_inst;
static struct cprof_tbl_s cprof_tbl_inst;
/*===========================================================================*
* do_cprofile *
*===========================================================================*/
int do_cprofile(struct proc * caller, message * m_ptr)
{
int proc_nr, i;
phys_bytes len;
vir_bytes vir_dst;
switch (m_ptr->m_lsys_krn_cprof.action) {
case PROF_RESET:
/* Reset profiling tables. */
cprof_ctl_inst.reset = 1;
printf("CPROFILE notice: resetting tables:");
for (i=0; i<cprof_procs_no; i++) {
printf(" %s", cprof_proc_info[i].name);
/* Test whether proc still alive. */
if (!isokendpt(cprof_proc_info[i].endpt, &proc_nr)) {
printf("endpt not valid %u (%s)\n",
cprof_proc_info[i].endpt, cprof_proc_info[i].name);
continue;
}
/* Set reset flag. */
data_copy(KERNEL, (vir_bytes) &cprof_ctl_inst.reset,
cprof_proc_info[i].endpt, cprof_proc_info[i].ctl_v,
sizeof(cprof_ctl_inst.reset));
}
printf("\n");
return OK;
case PROF_GET:
/* Get profiling data.
*
* Calculate physical addresses of user pointers. Copy to user
* program the info struct. Copy to user program the profiling
* tables of the profiled processes.
*/
if(!isokendpt(m_ptr->m_lsys_krn_cprof.endpt, &proc_nr))
return EINVAL;
cprof_mem_size = m_ptr->m_lsys_krn_cprof.mem_size;
printf("CPROFILE notice: getting tables:");
/* Copy control structs of profiled processes to calculate total
* nr of bytes to be copied to user program and find out if any
* errors happened. */
cprof_info.mem_used = 0;
cprof_info.err = 0;
for (i=0; i<cprof_procs_no; i++) {
printf(" %s", cprof_proc_info[i].name);
/* Test whether proc still alive. */
if (!isokendpt(cprof_proc_info[i].endpt, &proc_nr)) {
printf("endpt not valid %u (%s)\n",
cprof_proc_info[i].endpt, cprof_proc_info[i].name);
continue;
}
/* Copy control struct from proc to local variable. */
data_copy(cprof_proc_info[i].endpt, cprof_proc_info[i].ctl_v,
KERNEL, (vir_bytes) &cprof_ctl_inst,
sizeof(cprof_ctl_inst));
/* Calculate memory used. */
cprof_proc_info[i].slots_used = cprof_ctl_inst.slots_used;
cprof_info.mem_used += CPROF_PROCNAME_LEN;
cprof_info.mem_used += sizeof(cprof_proc_info_inst.slots_used);
cprof_info.mem_used += cprof_proc_info[i].slots_used *
sizeof(cprof_tbl_inst);
/* Collect errors. */
cprof_info.err |= cprof_ctl_inst.err;
}
printf("\n");
/* Do we have the space available? */
if (cprof_mem_size < cprof_info.mem_used) cprof_info.mem_used = -1;
/* Copy the info struct to the user process. */
data_copy(KERNEL, (vir_bytes) &cprof_info,
m_ptr->m_lsys_krn_cprof.endpt, m_ptr->m_lsys_krn_cprof.ctl_ptr,
sizeof(cprof_info));
/* If there is no space or errors occurred, don't bother copying. */
if (cprof_info.mem_used == -1 || cprof_info.err) return OK;
/* For each profiled process, copy its name, slots_used and profiling
* table to the user process. */
vir_dst = m_ptr->m_lsys_krn_cprof.mem_ptr;
for (i=0; i<cprof_procs_no; i++) {
len = (phys_bytes) strlen(cprof_proc_info[i].name);
data_copy(KERNEL, (vir_bytes) cprof_proc_info[i].name,
m_ptr->m_lsys_krn_cprof.endpt, vir_dst, len);
vir_dst += CPROF_PROCNAME_LEN;
len = (phys_bytes) sizeof(cprof_ctl_inst.slots_used);
data_copy(cprof_proc_info[i].endpt,
cprof_proc_info[i].ctl_v + sizeof(cprof_ctl_inst.reset),
m_ptr->m_lsys_krn_cprof.endpt, vir_dst, len);
vir_dst += len;
len = (phys_bytes)
(sizeof(cprof_tbl_inst) * cprof_proc_info[i].slots_used);
data_copy(cprof_proc_info[i].endpt, cprof_proc_info[i].buf_v,
m_ptr->m_lsys_krn_cprof.endpt, vir_dst, len);
vir_dst += len;
}
return OK;
default:
return EINVAL;
}
}
#endif /* CPROFILE */

View file

@ -1,50 +0,0 @@
/* The kernel call that is implemented in this file:
* m_type: SYS_PROFBUF
*
* The parameters for this kernel call are:
* m_lsys_krn_sys_profbuf.ctl_ptr (location of control struct)
* m_lsys_krn_sys_profbuf.mem_ptr (location of profiling table)
*
* Changes:
* 14 Aug, 2006 Created (Rogier Meurs)
*/
#include "kernel/system.h"
#if CPROFILE
/*===========================================================================*
* do_profbuf *
*===========================================================================*/
int do_profbuf(struct proc * caller, message * m_ptr)
{
/* This kernel call is used by profiled system processes when Call
* Profiling is enabled. It is called on the first execution of procentry.
* By means of this kernel call, the profiled processes inform the kernel
* about the location of their profiling table and the control structure
* which is used to enable the kernel to have the tables cleared.
*/
int proc_nr;
struct proc *rp;
/* Store process name, control struct, table locations. */
if(!isokendpt(caller->p_endpoint, &proc_nr))
return EDEADSRCDST;
if(cprof_procs_no >= NR_SYS_PROCS)
return ENOSPC;
rp = proc_addr(proc_nr);
cprof_proc_info[cprof_procs_no].endpt = caller->p_endpoint;
cprof_proc_info[cprof_procs_no].name = rp->p_name;
cprof_proc_info[cprof_procs_no].ctl_v = m_ptr->m_lsys_krn_sys_profbuf.ctl_ptr;
cprof_proc_info[cprof_procs_no].buf_v = m_ptr->m_lsys_krn_sys_profbuf.mem_ptr;
cprof_procs_no++;
return OK;
}
#endif /* CPROFILE */

View file

@ -25,7 +25,7 @@ SRCS+= accept.c access.c adjtime.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \
getrusage.c setrlimit.c setpgid.c
# Minix specific syscalls / utils.
SRCS+= cprofile.c sprofile.c stack_utils.c _mcontext.c
SRCS+= sprofile.c stack_utils.c _mcontext.c
# Emulation for missing lchown/lchmod
OBJS+= lchown.o lchmod.o

View file

@ -1,24 +0,0 @@
#include <sys/cdefs.h>
#include "namespace.h"
#ifdef __weak_alias
__weak_alias(cprofile, _cprofile)
#endif
#include <lib.h>
#include <string.h>
#include <minix/profile.h>
int cprofile(int action, int size, void *ctl_ptr, void *mem_ptr)
{
message m;
memset(&m, 0, sizeof(m));
m.m_lc_pm_cprof.action = action;
m.m_lc_pm_cprof.mem_size = size;
m.m_lc_pm_cprof.ctl_ptr = ctl_ptr;
m.m_lc_pm_cprof.mem_ptr = mem_ptr;
return _syscall(PM_PROC_NR, PM_CPROF, &m);
}

View file

@ -52,7 +52,6 @@ SRCS+= \
stacktrace.c \
sys_abort.c \
sys_clear.c \
sys_cprof.c \
sys_diagctl.c \
sys_endsig.c \
sys_exec.c \
@ -68,7 +67,6 @@ SRCS+= \
sys_padconf.c \
sys_physcopy.c \
sys_privctl.c \
sys_profbuf.c \
sys_runctl.c \
sys_safecopy.c \
sys_safememset.c \

View file

@ -7,8 +7,6 @@ HERE=${.CURDIR}/arch/${MACHINE_ARCH}
SRCS+= \
get_randomness.c \
getidle.c \
profile.c \
profile_extern.c \
ser_putc.c \
spin.c \
sys_eniop.c \

View file

@ -1,271 +0,0 @@
/*
* profile.c - library functions for call profiling
*
* For processes that were compiled using ACK with the -Rcem-p option,
* procentry and procexit will be called on entry and exit of their
* functions. Procentry/procexit are implemented here as generic library
* functions.
*
* Changes:
* 14 Aug, 2006 Created (Rogier Meurs)
*/
#include <lib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <minix/profile.h>
#include <minix/sysutil.h>
#include <minix/u64.h>
#include <minix/minlib.h>
static char cpath[CPROF_CPATH_MAX_LEN]; /* current call path string */
static int cpath_len; /* current call path len */
static struct cprof_tbl_s *cprof_slot; /* slot of current function */
struct stack_s { /* stack entry */
int cpath_len; /* call path len */
struct cprof_tbl_s *slot; /* table slot */
u64_t start_1; /* count @ begin of procentry */
u64_t start_2; /* count @ end of procentry */
u64_t spent_deeper; /* spent in called functions */
};
static struct stack_s cprof_stk[CPROF_STACK_SIZE]; /* stack */
static int cprof_stk_top; /* top of stack */
EXTERN struct cprof_tbl_s cprof_tbl[]; /* hash table */
static int cprof_tbl_size; /* nr of slots */
static struct cprof_tbl_s *idx[CPROF_INDEX_SIZE]; /* index to table */
static struct cprof_ctl_s control; /* for comms with kernel */
static int cprof_announce; /* announce on n-th execution
* of procentry */
static int cprof_locked; /* for reentrancy */
static void cprof_init(void);
static void reset(void);
static void clear_tbl(void);
void procentry(char *name)
{
static int init = 0;
unsigned hash = 0, x = 0;
int i = 0;
struct cprof_tbl_s *last;
char c;
u64_t start;
/* Procentry is not reentrant. */
if (cprof_locked) return; else cprof_locked = 1;
/* Read CPU cycle count into local variable. */
read_tsc_64(&start);
/* Run init code once after system boot. */
if (init == 0) {
cprof_init();
init++;
}
/* Announce once. */
if (init > -1 && init++ == cprof_announce) {
/* Tell kernel about control structure and table locations.
*
* In userspace processes, the library function profile_register
* will be used. This function does a kernel call (sys_profbuf) to
* announce to the kernel the location of the control struct and
* hash table. The control struct is used by the kernel to write
* a flag if resetting of the table is requested. The location of
* the table is needed to copy the information to the user process
* that requests it.
*
* Kernelspace processes don't use the library function but have
* their own implemention that executes logic similar to sys_profbuf.
* The reason for this is that the kernel is non-reentrant, therefore
* a kernelspace process is not able to do a kernel call itself since
* this would cause a deadlock.
*/
profile_register((void *) &control, (void *) &cprof_tbl);
init = -1;
}
/* Only continue if sane. */
if (control.err) return;
/* Check if kernel instructed to reset profiling data. */
if (control.reset) reset();
/* Increase stack. */
if (++cprof_stk_top == CPROF_STACK_SIZE) {
printf("CPROFILE error: stack overrun\n");
control.err |= CPROF_STACK_OVERRUN;
return;
}
/* Save initial cycle count on stack. */
cprof_stk[cprof_stk_top].start_1 = start;
/* Check available call path len. */
if (cpath_len + strlen(name) + 1 > CPROF_CPATH_MAX_LEN) {
printf("CPROFILE error: call path overrun\n");
control.err |= CPROF_CPATH_OVERRUN;
return;
}
/* Save previous call path length on stack. */
cprof_stk[cprof_stk_top].cpath_len = cpath_len;
/* Generate new call path string and length.*/
if (cprof_stk_top > 0) /* Path is space separated. */
cpath[cpath_len++] = ' ';
while ((c = *(name++)) != '\0') /* Append function name. */
cpath[cpath_len++] = c;
cpath[cpath_len] = '\0'; /* Null-termination. */
/* Calculate hash for call path string (algorithm: ELF). */
for (i=0; i<cpath_len; i++) {
hash = (hash << 4) + cpath[i];
if ((x = hash & 0xF0000000L) != 0) {
hash ^= (x >> 24);
hash &= ~x;
}
}
hash %= CPROF_INDEX_SIZE;
/* Look up the slot for this call path in the hash table. */
for (cprof_slot = idx[hash]; cprof_slot != 0; cprof_slot = cprof_slot->next)
if (strcmp(cprof_slot->cpath, cpath) == 0) break;
if (cprof_slot)
cprof_slot->calls++; /* found slot: update call counter */
else {
/* Not found: insert path into hash table. */
if (control.slots_used == cprof_tbl_size) {
printf("CPROFILE error: table overrun\n");
control.err |= CPROF_TABLE_OVERRUN;
return;
}
/* Set values for new slot. */
cprof_slot = &cprof_tbl[control.slots_used++];
strlcpy(cprof_slot->cpath, cpath, sizeof(cprof_slot->cpath));
cprof_slot->calls = 1;
/* Update index. */
if (idx[hash] == 0) {
/* No collision: simple update. */
idx[hash] = cprof_slot;
} else {
/* Collision: update last in chain. */
for (last = idx[hash]; last->next != 0; last = last->next);
last->next = cprof_slot;
}
}
/* Save slot on stack. */
cprof_stk[cprof_stk_top].slot = cprof_slot;
/* Again save CPU cycle count on stack. */
read_tsc_64(&cprof_stk[cprof_stk_top].start_2);
cprof_locked = 0;
}
void procexit(char *UNUSED(name))
{
u64_t stop, spent;
u32_t tsc_lo, tsc_hi;
/* Procexit is not reentrant. */
if (cprof_locked) return; else cprof_locked = 1;
/* First thing: read CPU cycle count into local variable. */
read_tsc(&tsc_hi, &tsc_lo);
stop = make64(tsc_lo, tsc_hi);
/* Only continue if sane. */
if (control.err) return;
/* Update cycle count for this call path. Exclude time spent in procentry/
* procexit by using measurements taken at end of procentry and begin of
* procexit (the "small" difference). This way, only the call overhead for
* the procentry/procexit functions will be attributed to this call path,
* not the procentry/procexit cycles.
*/
/* Calculate "small" difference. */
spent = stop - cprof_stk[cprof_stk_top].start_2;
cprof_stk[cprof_stk_top].slot->cycles +=
spent - cprof_stk[cprof_stk_top].spent_deeper;
/* Clear spent_deeper for call level we're leaving. */
cprof_stk[cprof_stk_top].spent_deeper = ((u64_t)(0));
/* Adjust call path string and stack. */
cpath_len = cprof_stk[cprof_stk_top].cpath_len;
cpath[cpath_len] = '\0';
/* Update spent_deeper for call level below. Include time spent in
* procentry/procexit by using measurements taken at begin of procentry
* and end of procexit (the "big" difference). This way the time spent in
* procentry/procexit will be included in spent_deeper and therefore, since
* this value is substracted from the lower call level, it will not be
* attributed to any call path. This way, pollution of the statistics
* because of procentry/procexit is kept to a minimum.
*/
/* Read CPU cycle count. */
read_tsc(&tsc_hi, &tsc_lo);
stop = make64(tsc_lo, tsc_hi);
/* Calculate "big" difference. */
spent = stop - cprof_stk[cprof_stk_top].start_1;
cprof_stk_top--; /* decrease stack */
if (cprof_stk_top >= 0) /* don't update non-existent level -1 */
cprof_stk[cprof_stk_top].spent_deeper += spent;
cprof_locked = 0;
}
static void cprof_init(void)
{
int i;
cpath[0] = '\0';
cpath_len = 0;
cprof_stk_top = -1;
control.reset = 0;
control.err = 0;
cprof_tbl_size = profile_get_tbl_size();
cprof_announce = profile_get_announce();
clear_tbl();
for (i=0; i<CPROF_STACK_SIZE; i++) {
cprof_stk[i].cpath_len = 0;
cprof_stk[i].slot = 0;
cprof_stk[i].start_1 = ((u64_t)(0));
cprof_stk[i].start_2 = ((u64_t)(0));
cprof_stk[i].spent_deeper = ((u64_t)(0));
}
}
static void reset(void)
{
clear_tbl();
control.reset = 0;
}
static void clear_tbl(void)
{
int i;
/* Reset profiling table. */
control.slots_used = 0;
for (i=0; i<CPROF_INDEX_SIZE; i++) idx[i] = 0; /* clear index */
for (i=0; i<cprof_tbl_size; i++) { /* clear table */
memset(cprof_tbl[i].cpath, '\0', CPROF_CPATH_MAX_LEN);
cprof_tbl[i].next = 0;
cprof_tbl[i].calls = 0;
cprof_tbl[i].cycles = make64(0, 0);
}
}

View file

@ -1,44 +0,0 @@
/*
* Library function used by system profiling.
*
* The variables and functions in this file are used by the procentry/
* procentry syslib functions when linked with userspace processes. For
* kernel processes, the same variables and function are defined
* elsewhere. This enables different functionality and variable sizes,
* which is needed is a few cases.
*
* Changes:
* 14 Aug, 2006 Created (Rogier Meurs)
*/
#include <lib.h>
#include <minix/profile.h>
#include <minix/syslib.h>
/* A regular sized table is declared for the userspace processes. */
struct cprof_tbl_s cprof_tbl[CPROF_TABLE_SIZE_OTHER];
/* Function that returns table size. */
int profile_get_tbl_size(void)
{
return CPROF_TABLE_SIZE_OTHER;
}
/* Function that returns on which execution of procentry to announce. */
int profile_get_announce(void)
{
return CPROF_ANNOUNCE_OTHER;
}
/*
* Userspace processes announce their control struct and table locations
* to the kernel through this function.
*/
void profile_register(ctl_ptr, tbl_ptr)
void *ctl_ptr;
void *tbl_ptr;
{
sys_profbuf(ctl_ptr, tbl_ptr);
}

View file

@ -1,23 +0,0 @@
#include "syslib.h"
/*===========================================================================*
* sys_cprof *
*===========================================================================*/
int sys_cprof(action, size, endpt, ctl_ptr, mem_ptr)
int action; /* get/reset profiling tables */
int size; /* size of allocated memory */
endpoint_t endpt; /* caller endpoint */
void *ctl_ptr; /* location of info struct */
void *mem_ptr; /* location of allocated memory */
{
message m;
m.m_lsys_krn_sys_cprof.action = action;
m.m_lsys_krn_sys_cprof.mem_size = size;
m.m_lsys_krn_sys_cprof.endpt = endpt;
m.m_lsys_krn_sys_cprof.ctl_ptr = (vir_bytes)ctl_ptr;
m.m_lsys_krn_sys_cprof.mem_ptr = (vir_bytes)mem_ptr;
return(_kernel_call(SYS_CPROF, &m));
}

View file

@ -1,17 +0,0 @@
#include "syslib.h"
/*===========================================================================*
* sys_profbuf *
*===========================================================================*/
int sys_profbuf(ctl_ptr, mem_ptr)
void *ctl_ptr; /* pointer to control structure */
void *mem_ptr; /* pointer to profiling table */
{
message m;
m.m_lsys_krn_sys_profbuf.ctl_ptr = (vir_bytes)ctl_ptr;
m.m_lsys_krn_sys_profbuf.mem_ptr = (vir_bytes)mem_ptr;
return(_kernel_call(SYS_PROFBUF, &m));
}

View file

@ -1,9 +1,7 @@
.TH PROFILE 1
.SH NAME
profile \- MINIX system profiling control command
profile \- MINIX statistical profiling control command
.SH SYNOPSIS
Statistical profiling:
.PP
.B "profile start"
[
.B -m
@ -21,41 +19,17 @@ Statistical profiling:
.B "profile stop "
.br
.B "sprofalyze.pl"
.PP
Call profiling:
.PP
.B "profile get"
[
.B "-m"
.I memsize
]
[
.B "-o"
.I outfile
]
.br
.B "profile reset"
.br
.B "cprofalyze.pl"
.SH DESCRIPTION
This command controls MINIX system profiling. There is support for
statistical profiling, which causes a CMOS interrupt to regularly sample
the position of the program counter, and call profiling, which uses
compiler hooks to measure the time and frequency of call paths.
For statistical profiling support, recompile the kernel with SPROFILE in
<minix/config.h> set to 1. For call profiling support, recompile the
system with new libraries with CPROFILE <minix/config.h> set to 1 and
environment variable CPROFILE set to -Rcem-p.
the position of the program counter. To enable support for this,
recompile the kernel with SPROFILE in
<minix/config.h> set to 1.
.SH OPTIONS
.IP start
start measuring using statistical profiling.
.IP stop
stop measuring using statistical profiling.
.IP get
retrieve call profiling data
.IP reset
reset call profiling data
.IP "-m"
memory buffer size used to store profiling data in, allocated by the
profile command.
@ -65,9 +39,7 @@ output file.
frequency for statistical sampling.
.PP
After you have the output file, analysis can be done using the
.B sprofalyze.pl
and
.B cprofalyze.pl
commands.
.B sprofalyze
command.
.SH AUTHOR
Rogier Meurs

View file

@ -2,7 +2,6 @@
*
* The entry points in this file are:
* do_sprofile: start/stop statistical profiling
* do_cprofile: get/reset call profiling tables
*
* Changes:
* 14 Aug, 2006 Created (Rogier Meurs)
@ -44,32 +43,3 @@ int do_sprofile(void)
return ENOSYS;
#endif
}
/*===========================================================================*
* do_cprofile *
*===========================================================================*/
int do_cprofile(void)
{
#if CPROFILE
int r;
switch(m_in.m_lc_pm_cprof.action) {
case PROF_GET:
return sys_cprof(PROF_GET, m_in.m_lc_pm_cprof.mem_size, who_e,
m_in.m_lc_pm_cprof.ctl_ptr, m_in.m_lc_pm_cprof.mem_ptr);
case PROF_RESET:
return sys_cprof(PROF_RESET,0,0,0,0);
default:
return EINVAL;
}
#else
return ENOSYS;
#endif
}

View file

@ -54,7 +54,6 @@ int sched_nice(struct mproc *rmp, int nice);
/* profile.c */
int do_sprofile(void);
int do_cprofile(void);
/* signal.c */
int do_kill(void);

View file

@ -51,7 +51,6 @@ int (* const call_vec[NR_PM_CALLS])(void) = {
CALL(PM_REBOOT) = do_reboot, /* reboot(2) */
CALL(PM_SVRCTL) = do_svrctl, /* svrctl(2) */
CALL(PM_SPROF) = do_sprofile, /* sprofile(2) */
CALL(PM_CPROF) = do_cprofile, /* cprofile(2) */
CALL(PM_SRV_FORK) = do_srv_fork, /* srv_fork(2) */
CALL(PM_SRV_KILL) = do_srv_kill, /* srv_kill(2) */
CALL(PM_EXEC_NEW) = do_newexec,