]> Zhao Yanbai Git Server - minix.git/commitdiff
System statistical and call profiling
authorBen Gras <ben@minix3.org>
Mon, 30 Oct 2006 15:53:38 +0000 (15:53 +0000)
committerBen Gras <ben@minix3.org>
Mon, 30 Oct 2006 15:53:38 +0000 (15:53 +0000)
support by Rogier Meurs <rogier@meurs.org>.

76 files changed:
commands/Makefile
commands/profile/Makefile [new file with mode: 0644]
commands/profile/cprofalyze.pl [new file with mode: 0755]
commands/profile/profile.c [new file with mode: 0644]
commands/profile/sprofalyze.pl [new file with mode: 0755]
commands/profile/tools/profextr.pl [new file with mode: 0755]
commands/profile/tools/proftsc.pl [new file with mode: 0755]
drivers/at_wini/Makefile
drivers/bios_wini/Makefile
drivers/cmos/Makefile
drivers/dp8390/Makefile
drivers/dpeth/Makefile
drivers/floppy/Makefile
drivers/fxp/Makefile
drivers/lance/Makefile
drivers/libdriver/Makefile
drivers/log/Makefile
drivers/memory/ramdisk/proto
drivers/pci/Makefile
drivers/printer/Makefile
drivers/random/Makefile
drivers/rescue/Makefile
drivers/rtl8139/Makefile
drivers/sb16/Makefile
drivers/ti1225/Makefile
drivers/tty/Makefile
drivers/tty/keymaps/Makefile
include/ibm/interrupt.h
include/minix/callnr.h
include/minix/com.h
include/minix/config.h
include/minix/profile.h [new file with mode: 0644]
include/minix/syslib.h
kernel/Makefile
kernel/kernel.h
kernel/main.c
kernel/profile.c [new file with mode: 0644]
kernel/profile.h [new file with mode: 0644]
kernel/system.c
kernel/system.h
kernel/system/Makefile
kernel/system/do_cprofile.c [new file with mode: 0644]
kernel/system/do_privctl.c
kernel/system/do_profbuf.c [new file with mode: 0644]
kernel/system/do_sprofile.c [new file with mode: 0644]
kernel/table.c
lib/other/Makefile.in
lib/other/_cprofile.c [new file with mode: 0644]
lib/other/_sprofile.c [new file with mode: 0644]
lib/syscall/Makefile.in
lib/syscall/cprofile.s [new file with mode: 0755]
lib/syscall/sprofile.s [new file with mode: 0755]
lib/syslib/Makefile.in
lib/syslib/sys_cprof.c [new file with mode: 0644]
lib/syslib/sys_profbuf.c [new file with mode: 0644]
lib/syslib/sys_sprof.c [new file with mode: 0644]
lib/sysutil/Makefile.in
lib/sysutil/profile.c [new file with mode: 0644]
lib/sysutil/profile_extern.c [new file with mode: 0644]
lib/sysutil/read_tsc.h [new file with mode: 0644]
lib/sysutil/read_tsc.s [new file with mode: 0644]
man/Makefile
man/man1/profile.1 [new file with mode: 0644]
servers/ds/Makefile
servers/inet/Makefile
servers/is/Makefile
servers/mfs/Makefile
servers/mfs/device.c
servers/pm/Makefile
servers/pm/profile.c [new file with mode: 0644]
servers/pm/proto.h
servers/pm/table.c
servers/rs/Makefile
servers/sm/Makefile
servers/vfs/Makefile
servers/vfs/table.c

index 1030ccf1c3732cdbd853493eb186de2688ae2bf9..8a8f2fcadbba7ea921ebc59581e49286f6b2f444 100755 (executable)
@@ -4,7 +4,7 @@ MAKE    = exec make -$(MAKEFLAGS)
 BZIP2=bzip2-1.0.3
 FLEX=flex-2.5.4
 
-SMALLPROGRAMS=`arch` aal advent ash autil awk bc byacc cawf cron de dhcpd dis88 elle elvis ftp101 ftpd200 ibm indent m4 make mdb mined patch pax ps reboot rlogind scripts sh simple syslogd talk talkd telnet telnetd urlget yap 
+SMALLPROGRAMS=`arch` aal advent ash autil awk bc byacc cawf cron de dhcpd dis88 elle elvis ftp101 ftpd200 ibm indent m4 make mdb mined patch pax profile ps reboot rlogind scripts sh simple syslogd talk talkd telnet telnetd urlget yap 
 
 usage:
        @echo "Usage: make all          # Compile all commands" >&2
diff --git a/commands/profile/Makefile b/commands/profile/Makefile
new file mode 100644 (file)
index 0000000..2fa766a
--- /dev/null
@@ -0,0 +1,29 @@
+# Makefile for profile and profalyze.pl
+
+CC=exec cc
+
+all:                   profile sprofalyze.pl cprofalyze.pl
+
+profile:               profile.c
+                       $(CC) -o $@ profile.c
+                       install -S 65m $@
+sprofalyze.pl:
+                       install $@
+
+cprofalyze.pl:
+                       install $@
+
+install: /usr/bin/profile /usr/bin/sprofalyze.pl /usr/bin/cprofalyze.pl
+
+/usr/bin/profile:      profile
+                       install -cs -o bin $? $@
+
+/usr/bin/sprofalyze.pl:        sprofalyze.pl
+                       install -o bin $? $@
+
+/usr/bin/cprofalyze.pl:        cprofalyze.pl
+                       install -o bin $? $@
+
+clean: 
+                       rm -f *.o core *.bak profile
+
diff --git a/commands/profile/cprofalyze.pl b/commands/profile/cprofalyze.pl
new file mode 100755 (executable)
index 0000000..caae0e7
--- /dev/null
@@ -0,0 +1,273 @@
+#!/usr/local/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";
+}
+
diff --git a/commands/profile/profile.c b/commands/profile/profile.c
new file mode 100644 (file)
index 0000000..c987a3e
--- /dev/null
@@ -0,0 +1,446 @@
+/* profile - profile operating system
+ *
+ * The profile command is used to control Statistical and Call Profiling.
+ * It writes the profiling data collected by the kernel to a file.
+ *
+ * Changes:
+ *   14 Aug, 2006   Created (Rogier Meurs)
+ */
+
+#define SPROFILE               1
+#define CPROFILE               1
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <minix/profile.h>
+
+#define EHELP                  1
+#define ESYNTAX                        2
+#define EMEM                   3
+#define EOUTFILE               4
+#define EFREQ                  5
+#define EACTION                        6       
+
+#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 NPIPE                  "/tmp/profile.npipe"
+#define MIN_MEMSIZE            1
+#define DEF_MEMSIZE            64
+#define MIN_FREQ               3
+#define MAX_FREQ               15
+#define DEF_FREQ               6
+#define BUFSIZE                        1024
+#define MB                     (1024*1024)
+#define SYNCING                        "SYNC"
+#define DEV_LOG                        "/dev/log"
+
+int action = 0;
+int mem_size = 0;
+int mem_used = 0;
+int freq = 0;
+char *outfile = "";
+char *mem_ptr;
+int outfile_fd, npipe_fd;
+struct sprof_info_s sprof_info;
+struct cprof_info_s cprof_info;
+
+_PROTOTYPE(int handle_args, (int argc, char *argv[]));
+_PROTOTYPE(int start, (void));
+_PROTOTYPE(int stop, (void));
+_PROTOTYPE(int get, (void));
+_PROTOTYPE(int reset, (void));
+_PROTOTYPE(int create_named_pipe, (void));
+_PROTOTYPE(int alloc_mem, (void));
+_PROTOTYPE(int init_outfile, (void));
+_PROTOTYPE(int write_outfile, (void));
+_PROTOTYPE(int detach, (void));
+
+int main(int argc, char *argv[])
+{
+  int res;
+
+  if (res = handle_args(argc, argv)) {
+       switch(res) {
+               case ESYNTAX:
+                       printf("Error in parameters.\n");
+                       return 1;
+                       break;
+               case EACTION:
+                       printf("Specify one of start|stop|get|reset.\n");
+                       return 1;
+                       break;
+               case EMEM:
+                       printf("Incorrect memory size.\n");
+                       return 1;
+                       break;
+               case EFREQ:
+                       printf("Incorrect frequency.\n");
+                       return 1;
+                       break;
+               case EOUTFILE:
+                       printf("Output filename missing.\n");
+                       return 1;
+                       break;
+               default:
+                       break;
+       }
+
+        printf("Statistical Profiling:\n");
+       printf("  profile start [-m memsize] [-o outfile] [-f frequency]\n");
+        printf("  profile stop\n\n");
+        printf("Call Profiling:\n");
+       printf("  profile get   [-m memsize] [-o outfile]\n");
+        printf("  profile reset\n\n");
+       printf("   - memsize in MB, default: %u\n", DEF_MEMSIZE);
+       printf("   - default output file: profile.{stat|call}.out\n");
+       printf( "   - sample frequencies (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");
+       printf("      6    1024 Hz          13      8 Hz\n");
+       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");
+       return 1;
+  }
+
+  switch(action) {
+         case START:
+               if (start()) return 1;
+               break;
+         case STOP:
+               if (stop()) return 1;
+               break;
+         case GET:
+               if (get()) return 1;
+               break;
+         case RESET:
+               if (reset()) return 1;
+               break;
+         default:
+               break;
+  }
+  return 0;
+}
+
+
+int handle_args(int argc, char *argv[])
+{
+  while (--argc) {
+       ++argv;
+
+       if (strcmp(*argv, "-h") == 0 || strcmp(*argv, "help") == 0 ||
+               strcmp(*argv, "--help") == 0) {
+               return EHELP;
+       } else
+       if (strcmp(*argv, "-m") == 0) {
+               if (--argc == 0) return ESYNTAX;
+               if (sscanf(*++argv, "%u", &mem_size) != 1 ||
+                       mem_size < MIN_MEMSIZE ) return EMEM;
+       } else
+       if (strcmp(*argv, "-f") == 0) {
+               if (--argc == 0) return ESYNTAX;
+               if (sscanf(*++argv, "%u", &freq) != 1 ||
+                       freq < MIN_FREQ || freq > MAX_FREQ) return EFREQ;
+       } else
+       if (strcmp(*argv, "-o") == 0) {
+               if (--argc == 0) return ESYNTAX;
+               outfile = *++argv;
+       } else
+       if (strcmp(*argv, "start") == 0) {
+               if (action) return EACTION;
+               action = START;
+       } else
+       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;
+       }
+  }
+  
+  /* No action specified. */
+  if (!action) return EHELP;
+
+  /* Init unspecified parameters. */
+  if (action == START || action == GET) {
+       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(sprof_sample); /* align to sample size */
+       if (freq == 0) freq = DEF_FREQ;            /* default frequency */
+  }
+  return 0;
+}      
+
+
+int start()
+{
+ /* This is the "starter process" for statistical profiling.
+  *
+  * Create output file for profiling data.  Create named pipe to
+  * synchronize with stopper process.  Fork so the parent can exit.
+  * Allocate memory for profiling data.  Start profiling in kernel.
+  * Complete detachment from terminal.  Write known string to named
+  * pipe, which blocks until read by stopper process.  Redirect
+  * stdout/stderr to the named pipe.  Write profiling data to file.
+  * Clean up.
+  */
+  int log_fd;
+
+  if (init_outfile() || create_named_pipe()) return 1;
+
+  printf("Starting statistical profiling.\n");
+
+  if (fork() != 0) exit(0);
+
+  if (alloc_mem()) return 1;
+
+  if (sprofile(PROF_START, mem_size, freq, &sprof_info, mem_ptr)) {
+       perror("sprofile");
+       printf("Error starting profiling.\n");
+       return 1;
+  }
+
+  detach();
+
+  /* Temporarily redirect to system log to catch errors. */
+  log_fd = open(DEV_LOG, O_WRONLY);
+  dup2(log_fd, 1);
+  dup2(log_fd, 2);
+
+  if ((npipe_fd = open(NPIPE, O_WRONLY)) < 0) {
+       printf("Unable to open named pipe %s.\n", NPIPE);
+       return 1;
+  } else
+       /* Synchronize with stopper process. */
+       write(npipe_fd, SYNCING, strlen(SYNCING));
+
+  /* Now redirect to named pipe. */
+  dup2(npipe_fd, 1);
+  dup2(npipe_fd, 2);
+
+  mem_used = sprof_info.mem_used;
+
+  if (mem_used == -1) {
+         printf("WARNING: Profiling was stopped prematurely due to ");
+         printf("insufficient memory.\n");
+         printf("Try increasing available memory using the -m switch.\n");
+  }
+
+  if (write_outfile()) return 1;
+
+  close(log_fd);
+  close(npipe_fd);
+  unlink(NPIPE);
+  close(outfile_fd);
+  free(mem_ptr);
+
+  return 0;
+}
+
+
+int stop()
+{
+  /* This is the "stopper" process for statistical profiling.
+   *
+   * Stop profiling in kernel.  Read known string from named pipe
+   * to synchronize with starter proces.  Read named pipe until EOF
+   * and write to stdout, this allows feedback from started process
+   * to be printed.
+   */
+  int n;
+  char buf[BUFSIZE];
+
+  if (sprofile(PROF_STOP, 0, 0, 0, 0)) {
+       perror("sprofile");
+       printf("Error stopping profiling.\n");
+       return 1;
+  } else printf("Statistical profiling stopped.\n");
+
+  if ((npipe_fd = open(NPIPE, O_RDONLY)) < 0) {
+       printf("Unable to open named pipe %s.\n", NPIPE);
+       return 1;
+  } else
+       /* Synchronize with starter process. */
+       read(npipe_fd, buf, strlen(SYNCING));
+
+  while ((n = read(npipe_fd, buf, BUFSIZE)) > 0)
+       write(1, buf, n);
+
+  close(npipe_fd);
+
+  return 0;
+}
+
+
+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");
+       printf("Error getting data.\n");
+       return 1;
+  }
+
+  mem_used = cprof_info.mem_used;
+
+  if (mem_used == -1) {
+       printf("ERROR: unable to get data due to insufficient memory.\n");
+       printf("Try increasing available memory using the -m switch.\n");
+  } else
+  if (cprof_info.err) {
+       printf("ERROR: the following error(s) happened during profiling:\n");
+       if (cprof_info.err & CPROF_CPATH_OVERRUN)
+               printf(" call path overrun\n");
+       if (cprof_info.err & CPROF_STACK_OVERRUN)
+               printf(" call stack overrun\n");
+       if (cprof_info.err & CPROF_TABLE_OVERRUN)
+               printf(" hash table overrun\n");
+       printf("Try changing values in /usr/src/include/minix/profile.h ");
+       printf("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");
+       printf("Error resetting data.\n");
+       return 1;
+  }
+
+  return 0;
+}
+
+
+int alloc_mem()
+{
+  if ((mem_ptr = malloc(mem_size)) == 0) {
+       printf("Unable to allocate memory.\n");
+       printf("Used chmem to increase available proces memory?\n");
+       return 1;
+  } else memset(mem_ptr, '\0', mem_size);
+
+  return 0;
+}
+
+
+int init_outfile()
+{
+  if ((outfile_fd = open(outfile, O_CREAT | O_TRUNC | O_WRONLY)) <= 0) {
+       printf("Unable to create outfile %s.\n", outfile);
+       return 1;
+  } else chmod(outfile, S_IRUSR | S_IWUSR);
+
+  return 0;
+}
+
+
+int create_named_pipe()
+{
+  if ((mkfifo(NPIPE, S_IRUSR | S_IWUSR) == -1) && (errno != EEXIST)) {
+       printf("Unable to create named pipe %s.\n", NPIPE);
+       return 1;
+  } else
+       return 0;
+}
+
+
+int detach()
+{
+  setsid();
+  (void) chdir("/");
+  close(0);
+  close(1);
+  close(2);
+}
+
+
+int write_outfile()
+{
+  int n, towrite, written = 0;
+  char *buf = mem_ptr;
+  char header[80];
+
+  printf("Writing to %s ...", outfile);
+
+  /* Write header. */
+  if (SPROF)
+       sprintf(header, "stat\n%d %d %d %d\n",  sprof_info.total_samples,
+                                               sprof_info.idle_samples,
+                                               sprof_info.system_samples,
+                                               sprof_info.user_samples);
+  else
+       sprintf(header, "call\n%u %u\n",
+                               CPROF_CPATH_MAX_LEN, CPROF_PROCNAME_LEN);
+
+  n = write(outfile_fd, header, strlen(header));
+
+  if (n < 0) { printf("Error writing to outfile %s.\n", outfile); return 1; }
+
+  /* Write data. */
+  towrite = mem_used == -1 ? mem_size : mem_used;
+
+  while (towrite > 0) {
+
+       n = write(outfile_fd, buf, towrite);
+
+       if (n < 0)
+               { printf("Error writing to outfile %s.\n", outfile); return 1; }
+
+       towrite -= n;
+       buf += n;
+       written += n;
+  }
+
+  printf(" header %d bytes, data %d bytes.\n", strlen(header), written);
+
+  return 0;
+}
+
diff --git a/commands/profile/sprofalyze.pl b/commands/profile/sprofalyze.pl
new file mode 100755 (executable)
index 0000000..3c2d7c0
--- /dev/null
@@ -0,0 +1,349 @@
+#!/usr/local/bin/perl
+#
+# sprofalyze.pl
+#
+# Analyzes the output files created by the profile command for
+# Statistical Profiling.
+#
+# Changes:
+#   14 Aug, 2006  Created (Rogier Meurs)
+#
+
+# Configuration options:
+
+# Location and parameters of nm program to extract symbol tables
+$nm = "/usr/bin/nm -dn";
+
+# Location of src (including trailing /)
+       $src_root = qw(
+/usr/src/
+       );
+
+# Location of system executables within src. Add new servers/drivers here.
+       @exes = qw(
+kernel/kernel
+
+servers/ds/ds
+servers/vfs/vfs
+servers/mfs/mfs
+servers/inet/inet
+servers/is/is
+servers/pm/pm
+servers/rs/rs
+servers/rs/service
+
+drivers/at_wini/at_wini
+drivers/bios_wini/bios_wini
+drivers/cmos/cmos
+drivers/dp8390/dp8390
+drivers/dpeth/dpeth
+drivers/floppy/floppy
+drivers/fxp/fxp
+drivers/lance/lance
+drivers/log/log
+drivers/memory/memory
+drivers/pci/pci
+drivers/printer/printer
+drivers/random/random
+drivers/rtl8139/rtl8139
+drivers/sb16/sb16_dsp
+drivers/sb16/sb16_mixer
+drivers/ti1225/ti1225
+drivers/tty/tty
+       );
+
+# 8< ----------- no user configurable parameters below this line ----------- >8
+
+$SAMPLE_SIZE = 12;
+$MINIMUM_PERC = 1.0;
+
+
+if ($#ARGV < 0 || process_args(@ARGV)) {
+  print "Usage:\n";
+  print "  sprofalyze.pl [-p percentage] file ...\n\n";
+  print "    percentage  print only processes/functions >= percentage\n";
+  exit 1;
+}
+
+sub process_args {
+  $_ = shift;
+
+  if (/^-p$/) {
+       $_ = shift;
+       return 1 unless /^(\d{1,2})(.\d+)?$/;
+       $MINIMUM_PERC = $1 + $2;
+  } else {
+       unshift @_, $_;
+  }
+
+  @files = @_;
+
+  return 1 unless @files > 0;
+
+  return 0;
+}
+
+if (read_symbols()) { exit 1; }
+
+print "Showing processes and functions using at least $MINIMUM_PERC% time.\n";
+
+foreach $file (@files) {
+  if (process_datafile($file)) { exit 1; }
+}                                                    
+
+exit 0;                                              
+                   
+
+sub read_symbols
+{
+  print "Building indexes from symbol tables:";
+
+  for ($i=0; $i<= $#exes; $i++) {
+       my $exe = @exes[$i];
+       $shortname = $exe;
+       $shortname =~ s/^.*\///;
+       print " " if $i <= $#exes;
+       print $shortname;
+
+       $fullname = $src_root . $exe;
+
+       if ((! -x $fullname) || (! -r $fullname)) {
+               print "\nERROR: $fullname does not exist or not readable.\n";
+               print "Did you do a make?\n";
+               return 1;
+       }
+
+       # Create a hash entry for each symbol table (text) entry.
+       foreach $_ (`$nm $fullname`) {
+               if (/^0{0,7}(\d{0,8})\s[tT]\s(\w{1,8})\n$/) {
+                       ${$shortname."_hash"}{$1} = $2;
+               }
+       }
+
+       # Create hash entries for every possible pc value. This will pay off.
+       @lines = sort { $a <=> $b } keys %{$shortname."_hash"};
+
+       for ($y = 0; $y <= $#lines; $y++) {
+               for ($z = @lines->[$y] + 1; $z < @lines->[$y + 1]; $z++) {
+                       ${$shortname."_hash"}{$z} =
+                               ${$shortname."_hash"}{@lines->[$y]}
+               }
+       }
+  }
+
+  # Clock and system are in kernel image but are seperate processes.
+  push(@exes, "clock");
+  push(@exes, "system");
+  %clock_hash = %kernel_hash;
+  %system_hash = %kernel_hash;
+
+  print ".\n\n";
+  return 0;
+}
+
+
+sub process_datafile
+{
+  my %res = ();
+  my %merged = ();
+  my $file = shift;
+  my $buf, $pc, $exe, $total_system_perc;
+
+  unless (open(FILE, $file)) {
+       print "\nERROR: Unable to open $file: $!\n";
+       return 0;
+  }
+
+  # First line: check file type.
+  $_ = <FILE>; chomp;
+  if (!/^stat$/) {
+       if (/^call$/) {
+               print "Call Profiling output file: ";
+               print "Use cprofalyze.pl instead.\n";
+       } else {
+               print "Not a profiling output file.\n";
+       }
+       return 0;
+  }      
+
+  $file =~ s/^.*\///;
+
+  printf "\n========================================";
+  printf "========================================\n";
+  printf("Data file: %s\n", $file);
+  printf "========================================";
+  printf "========================================\n\n";
+
+  # Read header with total, idle, system and user hits.
+  $_ = <FILE>;
+  chomp;
+
+  ($total_hits, $idle_hits, $system_hits, $user_hits) = split (/ /);
+
+  my $system_perc      = sprintf("%3.f", $system_hits / $total_hits * 100);
+  my $user_perc                = sprintf("%3.f", $user_hits / $total_hits * 100);
+  my $idle_perc                = 100 - $system_perc - $user_perc;
+
+  printf("  System process ticks: %10d (%3d%%)\n", $system_hits, $system_perc);
+  printf("    User process ticks: %10d (%3d%%)", $user_hits, $user_perc);
+  printf("          Details of system process\n");
+  printf("       Idle time ticks: %10d (%3d%%)", $idle_hits, $idle_perc);
+  printf("          samples, aggregated and\n");
+  printf("                        ----------  ----");
+  printf("           per process, are below.\n");
+  printf("           Total ticks: %10d (100%)\n\n", $total_hits);
+  # Read sample records from file and increase relevant counters.
+  until (eof(FILE)) {
+       read(FILE, $buf, $SAMPLE_SIZE) == $SAMPLE_SIZE  or die ("Short read.");
+       ($exe, $pc) = unpack("Z8i", $buf);
+
+       # p_name "mem" refers to executable "memory".
+       $exe =~ s/^mem/memory/;
+
+       # We can access the hash by pc because they are all in there.
+               if (!defined(${$exe."_hash"}{$pc})) {
+               print "ERROR: Undefined in symbol table indexes: ";
+               print "executable $exe  address $pc\n";
+               print "Did you include this executable in the configuration?\n";
+               return 1;
+       }
+       $res{$exe}{${$exe."_hash"}{$pc}} ++;
+  }
+
+  # We only need to continue with executables that had any hits.
+  my @actives = ();
+  foreach my $exe (@exes) {
+       $exe =~ s/^.*\///;
+       next if (!exists($res{$exe}));
+       push(@actives, $exe);
+  }
+
+  # Calculate number of samples for each executable and create aggregated hash.
+  %exe_hits = ();
+  foreach $exe (@actives) {
+       foreach my $hits (values %{$res{$exe}}) {
+               $exe_hits{$exe} += $hits;
+       }
+
+       foreach my $key (keys %{$res{$exe}}) {
+               $merged{sprintf("%8s %8s", $exe, $key)} = $res{$exe}{$key};
+       }
+  }
+
+  $total_system_perc = 0;
+  # Print the aggregated results.
+  process_hash("", \%merged);
+
+  # Print results for each executable in decreasing order.
+  foreach my $exe
+  (reverse sort { $exe_hits{$a} <=> $exe_hits{$b} } keys %exe_hits)
+  {
+       process_hash($exe, \%{$res{$exe}}) if
+               $exe_hits{$exe} >= $system_hits / 100 * $MINIMUM_PERC;
+  }
+
+  # Print total of processes <threshold.
+  printf "----------------------------------------";
+  printf "----------------------------------------\n";
+  printf("%-47s %5.1f%% of system process samples\n", 
+       "processes <$MINIMUM_PERC% (not showing functions)",
+       100 - $total_system_perc);
+  printf "----------------------------------------";
+  printf "----------------------------------------\n";
+  printf("%-47s 100.0%%\n\n", "total");
+
+  close(FILE);
+  return 0;
+}
+
+
+sub process_hash
+{
+  my $exe = shift;
+  my $ref = shift;
+  %hash = %{$ref};
+  my $aggr = $exe eq "";
+
+  # Print a header.
+  printf "----------------------------------------";
+  printf "----------------------------------------\n";
+  if ($aggr) {
+       $astr_max = 55;
+       $perc_hits = $system_hits / 100;
+       printf("Total system process time %46d samples\n", $system_hits);
+  } else {
+       $astr_max = 64;
+       $perc_hits = $exe_hits{$exe} / 100;
+       $total_system_perc += $exe_perc =
+               sprintf("%5.1f", $exe_hits{$exe} / $system_hits * 100);
+       printf("%-47s %5.1f%% of system process samples\n", $exe, $exe_perc);
+  }
+  printf "----------------------------------------";
+  printf "----------------------------------------\n";
+
+
+  # Delete functions <threshold.  Get percentage for all functions >threshold.
+  my $below_thres_hits;
+  my $total_exe_perc;
+  foreach my $func (keys %hash)
+  {
+       if ($hash{$func} < $perc_hits * $MINIMUM_PERC) {
+               $below_thres_hits += $hash{$func};
+               delete($hash{$func});
+       } else {
+               $total_exe_perc += sprintf("%3.1f", $hash{$func} / $perc_hits);
+       }
+  }
+
+  # Now print the hash entries in decreasing order.
+  @sorted = reverse sort { $hash{$a} <=> $hash{$b} } keys %hash;
+
+  $astr_hits = ($hash{@sorted->[0]} > $below_thres_hits ?
+       $hash{@sorted->[0]} : $below_thres_hits) / $astr_max;
+
+  foreach $func (@sorted) {
+       process_line($func, $hash{$func});
+  }
+
+  # Print <threshold hits.
+  my $below_thres;
+  if ($aggr) { $below_thres = "         "; }
+  $below_thres .= sprintf("%8s", "<" . $MINIMUM_PERC . "%");
+  process_line($below_thres, $below_thres_hits, 100 - $total_exe_perc);
+
+  # Print footer.
+  printf "----------------------------------------";
+  printf "----------------------------------------\n";
+  printf("%-73s 100.0%%\n\n", $aggr ? "total" : $exe);
+}
+
+
+sub process_line
+{
+  my $func = shift;
+  my $hits = shift;
+
+  my $perc = $hits / $perc_hits;
+  my $astr = $hits / $astr_hits;
+
+  if ($aggr) {
+       print "$func ";
+  } else {
+       printf("%8s ", $func);
+  }
+  for ($i = 0; $i < $astr_max; $i++) {
+       if ($i <= $astr) {
+               print "*";
+       } else {
+               print " ";
+       }
+  }
+  print " ";
+  if (my $rest = shift) {
+       printf("%5.1f%%\n", $rest);
+  } else {
+       printf("%5.1f%%\n", $perc);
+  }
+}
+
diff --git a/commands/profile/tools/profextr.pl b/commands/profile/tools/profextr.pl
new file mode 100755 (executable)
index 0000000..b81f0da
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/local/bin/perl
+
+$SAMPLE_SZ = 12;
+
+$file = shift;
+
+open (FILE, $file) or die ("Unable to open $file: $!");
+
+$_ = <FILE>;
+
+until (eof(FILE)) {                                 
+  read(FILE, $buf, $SAMPLE_SZ) == $SAMPLE_SZ  or die ("Short read.");
+  ($exe, $pc) = unpack("A8i", $buf);            
+
+  # System and clock task are in kernel image.  
+#  $exe =~ s/^system/kernel/;                    
+#  $exe =~ s/^clock/kernel/;                     
+
+  # Memory has p_name "mem" in kernel.          
+#  $exe =~ s/^mem/memory/;                       
+
+  $pcs{$pc}++ if ($exe eq "fs");
+}
+
+foreach $pc (sort { $a <=> $b } keys %pcs) {
+       print "$pc $pcs{$pc}\n";
+}
diff --git a/commands/profile/tools/proftsc.pl b/commands/profile/tools/proftsc.pl
new file mode 100755 (executable)
index 0000000..d4d1afa
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/local/bin/perl
+
+$SAMPLE_SZ = 8;
+
+$file = shift;
+
+open (FILE, $file) or die ("Unable to open $file: $!");
+
+$_ = <FILE>;
+
+until (eof(FILE)) {                                 
+  read(FILE, $buf, $SAMPLE_SZ) == $SAMPLE_SZ  or die ("Short read.");
+  ($high, $low) = unpack("II", $buf);            
+
+  if ($high - $prevhigh == 0) {
+       push (@res, $low - $prevlow);
+  }
+
+  $prevhigh = $high;
+  $prevlow = $low;
+
+  #print "$high $low\n";
+                                                                                   
+#  $pcs{$pc}++ if ($exe eq "kernel");
+}
+
+foreach $diff (sort { $a <=> $b } @res) {
+       print $diff."\n";
+}
+
+#foreach $pc (sort { $a <=> $b } keys %pcs) {
+#      print "$pc $pcs{$pc}\n";
+#}
index 738e75567faffe2f0cbf87d067027084b7ecfbcc..25c17e7a71c4b0be9b390ddacc309ac3069ce6b3 100644 (file)
@@ -13,7 +13,7 @@ p = ../libpci
 # programs, flags, etc.
 MAKE = exec make
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
 LIBS = -lsysutil -lsys -ltimers
 
@@ -25,7 +25,7 @@ LIBDRIVER = $d/libdriver/driver.o $d/libdriver/drvlib.o
 all build:     $(DRIVER)
 $(DRIVER):     $(OBJ) $(LIBDRIVER)
        $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBDRIVER) $(LIBS)
-       install -S 8k $(DRIVER)
+       install -S 32k $(DRIVER)
 
 $(LIBDRIVER): 
        cd $d/libdriver && $(MAKE) 
index ff0de5496abb883978c9669735eabf9045befdb0..56f193bc267a55e658e95be0a5eea1e4e61b2d6a 100644 (file)
@@ -12,7 +12,7 @@ d = ..
 # programs, flags, etc.
 MAKE = exec make
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
 LIBS = -lsysutil -lsys -ltimers
 
index ae345e2bca3f898837225de343de7aac4a036542..5366c41b53aae8c93e4ecc10808212bb5557e8de 100644 (file)
@@ -12,7 +12,7 @@ d = ..
 # programs, flags, etc.
 MAKE = exec make
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
 LIBS = -lsysutil -lsys
 
index de988339832eadba81f704a3f732b79b693a06be..6f7b06e15508b3b007c6f592e9791a356ff403a8 100644 (file)
@@ -11,7 +11,7 @@ d = ..
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i 
 LIBS = -lsysutil -lsys -ltimers
 
index cd6215d184d894b0451e442fe5bb198e2ea370e8..833962b689cdb601abba90c38958f3c7392caf5d 100644 (file)
@@ -1,29 +1,6 @@
 ##
 ##  Makefile for ISA ethernet drivers  May  02, 2000
 ##
-##  $Log$
-##  Revision 1.5  2006/08/02 22:51:46  beng
-##  At least 8k stack for all drivers so that malloc() works, for grants,
-##  for printf().
-##
-##  Revision 1.4  2006/07/10 12:43:38  philip
-##  Safecopy support in ethernet drivers.
-##
-##  Revision 1.3  2005/07/19 13:21:48  jnherder
-##  Renamed src/lib/utils to src/lib/sysutil --- because of new src/lib/util
-##
-##  Revision 1.2  2005/07/19 12:12:47  jnherder
-##  Changed Makefiles: drivers are now installed in /usr/sbin.
-##  TTY now gets SYS_EVENT message with sigset (e.g., SIGKMESS, SIGKSTOP).
-##
-##  Revision 1.1  2005/06/29 10:16:46  beng
-##  Import of dpeth 3c501/3c509b/.. ethernet driver by
-##  Giovanni Falzoni <fgalzoni@inwind.it>.
-##
-##  Revision 2.0  2005/06/26 16:16:46  lsodgf0
-##  Initial revision for Minix 3.0.6
-##
-##  $Id$
 
 ##  Programs, flags, etc.
 DRIVER = dpeth
@@ -32,8 +9,8 @@ debug  = 0
 
 CC     = exec cc
 LD     = $(CC)
-CPPFLAGS= -I.. -I/usr/include -Ddebug=$(debug)
-CFLAGS = $(CPPFLAGS)
+CPPFLAGS= -I.. -I/usr/include -Ddebug=$(debug) $(CPROFILE)
+CFLAGS = -ws $(CPPFLAGS)
 LDFLAGS        = -i -o $@
 
 SRCS   = 3c501.c 3c509.c 3c503.c ne.c wd.c 8390.c devio.c netbuff.c dp.c
index 700284b5deb5f5d446bb26924002ccc5425d46c3..db9bd0bd3a659c954b49d942d67ce22e852f61f0 100644 (file)
@@ -12,7 +12,7 @@ d = ..
 # programs, flags, etc.
 MAKE = exec make
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
 LIBS = -lsysutil  -lsys -ltimers
 
index 7ae75237c2d6ac653b5d72a1b9ecd4e37cb520f5..9cf6ba817e711ed10b5ec7abace853c1612c8c77 100644 (file)
@@ -11,7 +11,7 @@ d = ..
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i 
 LIBS = -lsysutil -lsys -ltimers
 
index 2e81959a2ede03b52ebccb5b524f1be32d3f1e9d..b6b7eef5166a86031bdda70a87c7a2bd2946435a 100644 (file)
@@ -11,7 +11,7 @@ d = ..
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i 
 LIBS = -lsysutil  -lsys
 #-lutils -ltimers
index b1a7c252d1e7aac4b2dc1f6b6fb6196edcf15a95..93bb1d7401f3c4b25740157ea6bee40e3e0520fe 100644 (file)
@@ -9,7 +9,7 @@ m = $i/minix
 
 # Programs, flags, etc.
 CC = exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
 LIBS = -lsysutil -lsys
 
index b929d882aa5ed2dafc85b0da32039ca33ebf6bd8..06f2f7d56411dfbebc5570c3dbe39adc676e19d8 100644 (file)
@@ -11,9 +11,9 @@ d = ..
 # programs, flags, etc.
 MAKE = exec make
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
-LIBS = -lsys -lsysutil
+LIBS = -lsysutil -lsys
 
 OBJ = log.o diag.o kputc.o
 LIBDRIVER = $d/libdriver/driver.o
index 38987d9bb105e95049338520cb78144cecc291b5..63a375d7cbff50c11ecfc1069946128d22c1aee2 100644 (file)
@@ -1,5 +1,5 @@
 boot 
-210 250
+280 310
 d--755 0 0
        bin d--755 0 0
                at_wini ---755 0 0 at_wini
index e24f056c288497e5cbb955a2a2ce9f4caabd5c0c..965a4bce5404f141776474a84a17bca3462c3bbd 100644 (file)
@@ -11,7 +11,7 @@ d = ..
 
 # programs, flags, etc.
 CC =   cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i 
 LIBS = -lsysutil  -lsys -ltimers
 
index 975fe054badab2bfe3b0e0f7a89dd36f5ee9332c..0d63d622e1d1e25291fd35cfd62af78f558fc051 100644 (file)
@@ -11,7 +11,7 @@ d = ..
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
 LIBS = -lsysutil  -lsys
 
index e1d7fc07432abbbd34b7dc1de3f4f8a793e80a6e..b535ceea8af6cc9374433fbdbf052231e2b86082 100644 (file)
@@ -12,7 +12,7 @@ d = ..
 # programs, flags, etc.
 MAKE = exec make
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
 LIBS = -lsysutil  -lsys
 
index 9389d8a6f6fbbe392090eaeb45f0f924124c9b3b..66cf545ca8baa807eea492d430fa9299f0695eda 100644 (file)
@@ -12,7 +12,7 @@ d = ..
 # programs, flags, etc.
 MAKE = exec make
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
 LIBS = -lsys -lsysutil
 
index 1890aa4447f8439301e2ed84c705d5f37d8090f8..d37ab9aaa6d6debf3cbdaf1c246795469107bd92 100644 (file)
@@ -12,7 +12,7 @@ d = ..
 # programs, flags, etc.
 MAKE = exec make
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
 LIBS = -lsysutil -lsys -ltimers
 
index ce978abb0dd989ba5b35179839ba1e9e71164a94..1241064deceaf4e08c42e33b5fa0398c967d3435 100644 (file)
@@ -10,7 +10,7 @@ d = ..
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
 LIBS = -lsysutil -lsys
 
index 77efdac0a8b465cec055feb254f068232814243e..e5529e678c241f0c3f52d823e0fc5ace33864cdd 100644 (file)
@@ -11,7 +11,7 @@ d = ..
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i 
 LIBS = -lsysutil  -lsys -ltimers
 
index f45468ec4142b60f3a64b743c5b37274f2903043..3661fa720d8bd38ca52c35d74577618dcf248cff 100644 (file)
@@ -12,7 +12,7 @@ d = ..
 # programs, flags, etc.
 MAKE = exec make
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i 
 LDFLAGS = -i
 LIBS = -lsysutil -lsys -ltimers
 
index 1b485fae94e3041278e5148b832a987d3a7e5689..bd82dec6ce4c046cfa037728b2354269bc5dce67 100644 (file)
@@ -5,7 +5,7 @@ LK =    /usr/lib/keymaps
 .SUFFIXES:     .src .map
 
 .src.map:
-       $(CC) -DKEYSRC=\"$<\" genmap.c
+       $(CC) -DKEYSRC=\"$<\" $(CPROFILE) genmap.c -lsysutil -lsys
        ./a.out > $@
        @rm -f a.out
 
index e163f64feb6534b7d6110149cd67cb38d906e377..53d452f80f4e521e1f9c23f13f26ef108a95fa32 100644 (file)
@@ -46,6 +46,7 @@
 #define XT_WINI_IRQ        5   /* xt winchester */
 #define FLOPPY_IRQ         6   /* floppy disk */
 #define PRINTER_IRQ        7
+#define CMOS_CLOCK_IRQ     8
 #define KBD_AUX_IRQ       12   /* AUX (PS/2 mouse) port in kbd controller */
 #define AT_WINI_0_IRQ     14   /* at winchester controller 0 */
 #define AT_WINI_1_IRQ     15   /* at winchester controller 1 */
index 6e045e91904c9a6118ebaba17be977f37d986498..c2c62f67cea3d2b8af47d32226b062bb27578a04 100755 (executable)
@@ -1,4 +1,4 @@
-#define NCALLS           98    /* number of system calls allowed */
+#define NCALLS          100    /* number of system calls allowed */
 
 #define EXIT              1 
 #define FORK              2 
@@ -78,6 +78,8 @@
 #define FCHMOD           95    /* to FS */
 #define FCHOWN           96    /* to FS */
 #define GETSYSINFO_UP    97    /* to PM or FS */
+#define SPROF             98    /* to PM */
+#define CPROF             99    /* to PM */
 
 /* Calls provided by PM and FS that are not part of the API */
 #define EXEC_NEWMEM    100     /* from FS or RS to PM: new memory map for
index 32f4305c500cb74158aeb1ad8b96391a01932827..978a0ffa0395fda339a1d4ac54229e20dc8766e7 100755 (executable)
 #  define SYS_SETGRANT   (KERNEL_CALL + 34)    /* sys_setgrant() */
 #  define SYS_READBIOS   (KERNEL_CALL + 35)    /* sys_readbios() */
 
-#define NR_SYS_CALLS   36      /* number of system calls */ 
+#  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 NR_SYS_CALLS   39      /* number of system calls */ 
 
 /* Pseudo call for use in kernel/table.c. */
 #define SYS_ALL_CALLS (NR_SYS_CALLS)
 #define SEL_ERRORFDS   m8_p3
 #define SEL_TIMEOUT    m8_p4
 
+/* Field names for SYS_SPROF, _CPROF, _PROFBUF. */
+#define PROF_ACTION    m7_i1    /* start/stop/reset/get */
+#define PROF_MEM_SIZE  m7_i2    /* available memory for data */ 
+#define PROF_FREQ      m7_i3    /* sample frequency */
+#define PROF_ENDPT     m7_i4    /* endpoint of caller */
+#define PROF_CTL_PTR   m7_p1    /* location of info struct */
+#define PROF_MEM_PTR   m7_p2    /* location of profiling data */
+
 /* Field names for GETSYSINFO_UP (PM). */
 #define SIU_WHAT       m2_i1
 #define SIU_LEN                m2_i2
index dcf60ccb236a338d6b88a4b0c3299a2968f91e6a..0d6df04297096f8e9b4205a1577e75e2dbb5bca2 100755 (executable)
 #define ASKDEV _ASKDEV
 #define FASTLOAD _FASTLOAD
 
+/* Enable or disable system profiling. */
+#define SPROFILE          0    /* statistical profiling */
+#define CPROFILE          0    /* call profiling */
+
 #endif /* _CONFIG_H */
diff --git a/include/minix/profile.h b/include/minix/profile.h
new file mode 100644 (file)
index 0000000..91193a4
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef _PROFILE_H
+#define _PROFILE_H
+
+#include <ansi.h>
+
+/*
+ * Types relating to system profiling.  Types are supplied for both
+ * statistical profiling and call profiling.
+ */
+
+#if SPROFILE
+
+#  define PROF_START       0    /* start statistical profiling */
+#  define PROF_STOP        1    /* stop statistical profiling */
+
+/* Info struct to be copied to from kernel to user program. */
+struct sprof_info_s {
+  int mem_used;
+  int total_samples;
+  int idle_samples;
+  int system_samples;
+  int user_samples;
+} sprof_info_inst;
+
+/* What a profiling sample looks like (used for sizeof()). */
+struct {
+  char name[8];
+  int pc;
+} sprof_sample;
+
+#endif /* SPROFILE */
+
+
+#if CPROFILE
+
+#include <sys/types.h>
+
+#  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. */
+_PROTOTYPE(int profile_get_tbl_size, (void)                            );
+/* Prototype for function called by procentry to get announce number. */
+_PROTOTYPE(int profile_get_announce, (void)                            );
+/* Prototype for function called by procentry to announce control struct
+ * and table locations to the kernel. */
+_PROTOTYPE(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;
+} cprof_info_inst;
+
+/* 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 */
+} cprof_ctl_inst;
+
+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 */
+} cprof_tbl_inst;
+
+#endif /* CPROFILE */
+
+_PROTOTYPE( int sprofile, (int action, int size, int freq, 
+                                       void *ctl_ptr, void *mem_ptr)   );
+
+_PROTOTYPE( int cprofile, (int action, int size, void *ctl_ptr,
+                                                       void *mem_ptr)  );
+
+#endif /* PROFILE_H */
+
index 4ae273c304c0a30aa3f1df87a93147af567ccfac..9eeb93a03fe473c7958f17c94de576bd3eb090cc 100755 (executable)
@@ -197,5 +197,13 @@ _PROTOTYPE( char *pci_dev_name, (U16_t vid, U16_t did)                     );
 _PROTOTYPE( char *pci_slot_name, (int devind)                          );
 _PROTOTYPE( int pci_set_acl, (struct rs_pci *rs_pci)                   );
 
+/* Profiling. */
+_PROTOTYPE( int sys_sprof, (int action, int size, int freq, int endpt,
+                                       void *ctl_ptr, void *mem_ptr)   );
+_PROTOTYPE( int sys_cprof, (int action, int size, int endpt,
+                                       void *ctl_ptr, void *mem_ptr)   );
+_PROTOTYPE( int sys_profbuf, (void *ctl_ptr, void *mem_ptr)            );
+
+
 #endif /* _SYSLIB_H */
 
index d7ec1e9f25a8c257c24a72f5ea80237c419cdeed..35de79fd83e92d1ad40762106f01a7bfd07d2595 100755 (executable)
@@ -10,14 +10,14 @@ s = system
 CC =   exec cc
 CPP =  $l/cpp
 LD =   $(CC) -.o
-CFLAGS = -I$i 
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i 
 
 HEAD = mpx.o
 OBJS = start.o protect.o klib.o table.o kprintf.o main.o proc.o \
-       i8259.o exception.o system.o clock.o utility.o debug.o
+       i8259.o exception.o system.o clock.o utility.o debug.o profile.o
 SYSTEM = system.a
-LIBS = -ltimers 
+LIBS = -ltimers -lsysutil
 
 
 # What to make.
index 37838801ba2757e2a236f874c191d339425bbb3c..7df4de501493db87691f9fb6f1a9e7e2740b2b98 100755 (executable)
@@ -29,6 +29,7 @@
 #include "proto.h"             /* function prototypes */
 #include "glo.h"               /* global variables */
 #include "ipc.h"               /* IPC constants */
+#include "profile.h"           /* system profiling */
 #include "debug.h"             /* debugging, MUST be last kernel header */
 
 #endif /* KERNEL_H */
index 14d27ed5fcbe21c97525b16e4a6eb46eff181008..dd2100b8008165bef52908fe0ef0bdb7e2e2d7fc 100755 (executable)
@@ -181,6 +181,13 @@ PUBLIC void main()
   }
 #endif
 
+#if SPROFILE
+  sprofiling = 0;      /* we're not profiling until instructed to */
+#endif /* SPROFILE */
+#if CPROFILE
+  cprof_procs_no = 0;  /* init nr of hash table slots used */
+#endif /* CPROFILE */
+
   /* MINIX is now ready. All boot image processes are on the ready queue.
    * Return to the assembly code to start running the current process. 
    */
diff --git a/kernel/profile.c b/kernel/profile.c
new file mode 100644 (file)
index 0000000..ce4f50a
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * This file contains several functions and variables used for system
+ * profiling.
+ *
+ * Statistical Profiling:
+ *   The interrupt handler and control functions for the CMOS 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.
+ *
+ * Changes:
+ *   14 Aug, 2006   Created, (Rogier Meurs)
+ */
+
+#include <minix/config.h>
+
+#if SPROFILE || CPROFILE
+
+#include <minix/profile.h>
+#include "kernel.h"
+#include "profile.h"
+#include "proc.h"
+
+#endif
+
+#if SPROFILE
+
+#include <string.h>
+#include <ibm/cmos.h>
+
+/* Function prototype for the CMOS clock handler. */ 
+FORWARD _PROTOTYPE( int cmos_clock_handler, (irq_hook_t *hook) );
+
+/* A hook for the CMOS clock interrupt handler. */
+PRIVATE irq_hook_t cmos_clock_hook;
+
+/*===========================================================================*
+ *                             init_cmos_clock                              *
+ *===========================================================================*/
+PUBLIC void init_cmos_clock(unsigned freq)
+{
+  int r;
+  /* Register interrupt handler for statistical system profiling.
+   * This uses the CMOS timer.
+   */
+  cmos_clock_hook.proc_nr_e = CLOCK;
+  put_irq_handler(&cmos_clock_hook, CMOS_CLOCK_IRQ, cmos_clock_handler);
+  enable_irq(&cmos_clock_hook);
+
+  intr_disable();
+
+  /* Set CMOS timer frequency. */
+  outb(RTC_INDEX, RTC_REG_A);
+  outb(RTC_IO, RTC_A_DV_OK | freq);
+  /* Enable CMOS timer interrupts. */
+  outb(RTC_INDEX, RTC_REG_B);
+  r = inb(RTC_IO);
+  outb(RTC_INDEX, RTC_REG_B);
+  outb(RTC_IO, r | RTC_B_PIE);
+  /* Mandatory read of CMOS register to enable timer interrupts. */
+  outb(RTC_INDEX, RTC_REG_C);
+  inb(RTC_IO);
+
+  intr_enable();
+}
+
+/*===========================================================================*
+ *                             cmos_clock_stop                              *
+ *===========================================================================*/
+PUBLIC void stop_cmos_clock()
+{
+  int r;
+
+  intr_disable();
+
+  /* Disable CMOS timer interrupts. */
+  outb(RTC_INDEX, RTC_REG_B);
+  r = inb(RTC_IO);
+  outb(RTC_INDEX, RTC_REG_B);
+  outb(RTC_IO, r & !RTC_B_PIE);
+
+  intr_enable();
+
+  /* Unregister interrupt handler. */
+  disable_irq(&cmos_clock_hook);
+  rm_irq_handler(&cmos_clock_hook);
+}
+
+/*===========================================================================*
+ *                             cmos_clock_handler                           *
+ *===========================================================================*/
+PRIVATE int cmos_clock_handler(hook)
+irq_hook_t *hook;
+{
+/* This executes on every tick of the CMOS timer. */
+
+  /* Are we profiling, and profiling memory not full? */
+  if (!sprofiling || sprof_info.mem_used == -1) return (1);
+
+  /* Check if enough memory available before writing sample. */
+  if (sprof_info.mem_used + sizeof(sprof_info) > sprof_mem_size) {
+       sprof_info.mem_used = -1;
+       return(1);
+  }
+
+  /* All is OK */
+
+  /* Idle process? */
+  if (priv(proc_ptr)->s_proc_nr == IDLE) {
+       sprof_info.idle_samples++;
+  } else
+  /* Runnable system process? */
+  if (priv(proc_ptr)->s_flags & SYS_PROC && !proc_ptr->p_rts_flags) {
+       /* Note: k_reenter is always 0 here. */
+
+       /* Store sample (process name and program counter). */
+       phys_copy(vir2phys(proc_ptr->p_name),
+               (phys_bytes) (sprof_data_addr + sprof_info.mem_used),
+               (phys_bytes) strlen(proc_ptr->p_name));
+
+       phys_copy(vir2phys(&proc_ptr->p_reg.pc),
+               (phys_bytes) (sprof_data_addr+sprof_info.mem_used +
+                                       sizeof(proc_ptr->p_name)),
+               (phys_bytes) sizeof(proc_ptr->p_reg.pc));
+
+       sprof_info.mem_used += sizeof(sprof_sample);
+
+       sprof_info.system_samples++;
+  } else {
+       /* User process. */
+       sprof_info.user_samples++;
+  }
+  
+  sprof_info.total_samples++;
+
+  /* Mandatory read of CMOS register to re-enable timer interrupts. */
+  outb(RTC_INDEX, RTC_REG_C);
+  inb(RTC_IO);
+
+  return(1);                                    /* reenable interrupts */
+}
+
+#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. */
+PUBLIC int profile_get_tbl_size(void)
+{
+  return CPROF_TABLE_SIZE_KERNEL;
+}
+
+/* Function that returns on which execution of procentry to announce. */
+PUBLIC int profile_get_announce(void)
+{
+  return CPROF_ACCOUNCE_KERNEL;
+}
+
+/*
+ * The kernel "announces" its control struct and table locations
+ * to itself through this function.
+ */
+PUBLIC void profile_register(ctl_ptr, tbl_ptr)
+void *ctl_ptr;
+void *tbl_ptr;
+{
+  int len, proc_nr;
+  vir_bytes vir_dst;
+  struct proc *rp;                          
+
+  /* Store process name, control struct, table locations. */
+  proc_nr = KERNEL;
+  rp = proc_addr(proc_nr);
+
+  cprof_proc_info[cprof_procs_no].endpt = rp->p_endpoint;
+  cprof_proc_info[cprof_procs_no].name = rp->p_name;
+
+  len = (phys_bytes) sizeof (void *);
+
+  vir_dst = (vir_bytes) ctl_ptr;
+  cprof_proc_info[cprof_procs_no].ctl =
+         numap_local(proc_nr, vir_dst, len);
+
+  vir_dst = (vir_bytes) tbl_ptr;
+  cprof_proc_info[cprof_procs_no].buf =
+         numap_local(proc_nr, vir_dst, len);
+
+  cprof_procs_no++;
+}
+
+#endif /* CPROFILE */
+
diff --git a/kernel/profile.h b/kernel/profile.h
new file mode 100644 (file)
index 0000000..c8f54d8
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef PROFILE_H
+#define PROFILE_H
+
+#if SPROFILE || CPROFILE
+#include <minix/profile.h>
+#endif
+
+#if SPROFILE   /* statistical profiling */
+
+_PROTOTYPE( void init_cmos_clock, (unsigned freq)                       );
+_PROTOTYPE( void stop_cmos_clock, (void)                                );
+
+EXTERN int sprofiling;                 /* whether profiling is running */
+EXTERN int sprof_mem_size;             /* available user memory for data */
+EXTERN struct sprof_info_s sprof_info; /* profiling info for user program */
+EXTERN phys_bytes sprof_data_addr;     /* user address to write data */
+EXTERN phys_bytes sprof_info_addr;     /* user address to write info struct */
+
+#endif /* SPROFILE */
+
+
+#if CPROFILE   /* call profiling */
+
+EXTERN int cprof_mem_size;             /* available user memory for data */
+EXTERN struct cprof_info_s cprof_info; /* profiling info for user program */
+EXTERN phys_bytes cprof_data_addr;     /* user address to write data */
+EXTERN phys_bytes cprof_info_addr;     /* user address to write info struct */
+EXTERN int cprof_procs_no;             /* number of profiled processes */
+EXTERN struct cprof_proc_info_s {      /* info about profiled process */
+       int endpt;                      /* endpoint */
+       char *name;                     /* name */
+       phys_bytes ctl;                 /* location of control struct */
+       phys_bytes buf;                 /* 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 /* CPROFILE */
+
+#endif /* PROFILE_H */
+
index 1968e6b8d04b6c1de22ba5e77600c2fed19e4f31..c0151ac4e8ca5b81347b06ced0134426f6e393a0 100755 (executable)
@@ -190,6 +190,11 @@ PRIVATE void initialize(void)
   map(SYS_ABORT, do_abort);            /* abort MINIX */
   map(SYS_GETINFO, do_getinfo);        /* request system information */ 
   map(SYS_IOPENABLE, do_iopenable);    /* Enable I/O */
+
+  /* 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 */
 }
 
 /*===========================================================================*
index 857689f7fa721853bcacadcd2aa03cd02de8b1e1..c3ff6a838c882533bcce9fafd3428cdb7d8e9d94 100644 (file)
@@ -179,5 +179,20 @@ _PROTOTYPE( int do_iopenable, (message *m_ptr) );
 _PROTOTYPE( int do_setgrant, (message *m_ptr) );       
 _PROTOTYPE( int do_readbios, (message *m_ptr) );       
 
+_PROTOTYPE( int do_sprofile, (message *m_ptr) );
+#if ! SPROFILE
+#define do_sprofile do_unused
+#endif
+
+_PROTOTYPE( int do_cprofile, (message *m_ptr) );
+#if ! CPROFILE
+#define do_cprofile do_unused
+#endif
+
+_PROTOTYPE( int do_profbuf, (message *m_ptr) );
+#if ! CPROFILE
+#define do_profbuf do_unused
+#endif
+
 #endif /* SYSTEM_H */
 
index f94a4d46a1016440198069eda91663a6b56b2be9..7916a24dedb4d27f02825a8aaae24924636c8013 100644 (file)
@@ -6,9 +6,11 @@ i = $u/include
 
 # Programs, flags, etc.
 CC =   exec cc $(CFLAGS) -c
+CCNOPROF =      exec cc $(CFLAGSNOPROF) -c      # no call profiling for these
 CPP =  $l/cpp
 LD =   $(CC) -.o
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
+CFLAGSNOPROF = -I$i
 LDFLAGS = -i
 
 SYSTEM = ../system.a
@@ -50,6 +52,9 @@ OBJECTS       = \
        $(SYSTEM)(do_iopenable.o) \
        $(SYSTEM)(do_vm.o) \
        $(SYSTEM)(do_vm_setbuf.o) \
+       $(SYSTEM)(do_sprofile.o) \
+       $(SYSTEM)(do_cprofile.o) \
+       $(SYSTEM)(do_profbuf.o)
 
 $(SYSTEM):     $(OBJECTS)
        aal cr $@ *.o
@@ -163,3 +168,12 @@ do_vm.o:   do_vm.c
 
 $(SYSTEM)(do_vm_setbuf.o):     do_vm_setbuf.c
        $(CC) do_vm_setbuf.c
+
+$(SYSTEM)(do_sprofile.o):       do_sprofile.c
+       $(CC) do_sprofile.c
+
+$(SYSTEM)(do_cprofile.o):       do_cprofile.c
+       $(CC) do_cprofile.c
+
+$(SYSTEM)(do_profbuf.o):        do_profbuf.c
+       $(CC) do_profbuf.c
diff --git a/kernel/system/do_cprofile.c b/kernel/system/do_cprofile.c
new file mode 100644 (file)
index 0000000..5063730
--- /dev/null
@@ -0,0 +1,160 @@
+/* The kernel call that is implemented in this file:
+ *   m_type:    SYS_CPROFILE
+ *
+ * The parameters for this kernel call are:
+ *    m7_i1:    PROF_ACTION       (get/reset profiling data)
+ *    m7_i2:    PROF_MEM_SIZE     (available memory for data)
+ *    m7_i4:    PROF_ENDPT        (endpoint of caller)
+ *    m7_p1:    PROF_CTL_PTR      (location of info struct)
+ *    m7_p2:    PROF_MEM_PTR      (location of memory for data)
+ *
+ * Changes:
+ *   14 Aug, 2006   Created (Rogier Meurs)
+ */
+
+#include "../system.h"
+
+#if CPROFILE
+
+#include <string.h>
+
+/*===========================================================================*
+ *                             do_cprofile                                  *
+ *===========================================================================*/
+PUBLIC int do_cprofile(m_ptr)
+register message *m_ptr;    /* pointer to request message */
+{
+  int proc_nr, i, err = 0, k = 0;
+  vir_bytes vir_dst;
+  phys_bytes phys_src, phys_dst, len;
+
+  switch (m_ptr->PROF_ACTION) {
+
+  case PROF_RESET:
+
+       /* Reset profiling tables. */
+
+       cprof_ctl_inst.reset = 1;
+
+       kprintf("CPROFILE notice: resetting tables:");
+
+       for (i=0; i<cprof_procs_no; i++) {
+
+               kprintf(" %s", cprof_proc_info[i].name);
+
+               /* Test whether proc still alive. */
+               if (!isokendpt(cprof_proc_info[i].endpt, &proc_nr)) {
+                       kprintf("endpt not valid %u (%s)\n",
+                       cprof_proc_info[i].endpt, cprof_proc_info[i].name);
+                       continue;
+               }
+
+               /* Set reset flag. */
+               phys_src = vir2phys((vir_bytes) &cprof_ctl_inst.reset);
+               phys_dst = (phys_bytes) cprof_proc_info[i].ctl;
+               len = (phys_bytes) sizeof(cprof_ctl_inst.reset);
+               phys_copy(phys_src, phys_dst, len);
+       }
+       kprintf("\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->PROF_ENDPT, &proc_nr))
+               return EINVAL;
+
+       vir_dst = (vir_bytes) m_ptr->PROF_CTL_PTR;
+       len = (phys_bytes) sizeof (int *);
+       cprof_info_addr = numap_local(proc_nr, vir_dst, len);
+
+       vir_dst = (vir_bytes) m_ptr->PROF_MEM_PTR;
+       len = (phys_bytes) sizeof (char *);
+       cprof_data_addr = numap_local(proc_nr, vir_dst, len);
+
+       cprof_mem_size = m_ptr->PROF_MEM_SIZE;
+
+       kprintf("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++) {
+
+               kprintf(" %s", cprof_proc_info[i].name);
+
+               /* Test whether proc still alive. */
+               if (!isokendpt(cprof_proc_info[i].endpt, &proc_nr)) {
+                       kprintf("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. */
+               phys_src = cprof_proc_info[i].ctl;
+               phys_dst = vir2phys((vir_bytes) &cprof_ctl_inst);
+               len = (phys_bytes) sizeof(cprof_ctl_inst);
+               phys_copy(phys_src, phys_dst, len);
+
+               /* 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;
+       }
+       kprintf("\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. */
+       phys_copy(vir2phys((vir_bytes) &cprof_info), cprof_info_addr,
+                                       (phys_bytes) 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. */
+       phys_dst = cprof_data_addr;
+       for (i=0; i<cprof_procs_no; i++) {
+               phys_src = vir2phys((vir_bytes) cprof_proc_info[i].name);
+               len = (phys_bytes) strlen(cprof_proc_info[i].name);
+               phys_copy(phys_src, phys_dst, len);
+               phys_dst += CPROF_PROCNAME_LEN;
+
+               phys_src = cprof_proc_info[i].ctl +
+                                               sizeof(cprof_ctl_inst.reset);
+               len = (phys_bytes) sizeof(cprof_ctl_inst.slots_used);
+               phys_copy(phys_src, phys_dst, len);
+               phys_dst += len;
+
+               phys_src = cprof_proc_info[i].buf;
+               len = (phys_bytes)
+               (sizeof(cprof_tbl_inst) * cprof_proc_info[i].slots_used);
+               phys_copy(phys_src, phys_dst, len);
+               phys_dst += len;
+       }
+
+       return OK;
+
+  default:
+       return EINVAL;
+  }
+}
+
+#endif /* CPROFILE */
+
index b9943e66be193d1f1f906bf4d6354403017b3bf8..50231a458c6e16729cf306c2cf3a265502084734 100644 (file)
@@ -8,6 +8,7 @@
 #include "../system.h"
 #include "../ipc.h"
 #include <signal.h>
+#include <string.h>
 
 #if USE_PRIVCTL
 
diff --git a/kernel/system/do_profbuf.c b/kernel/system/do_profbuf.c
new file mode 100644 (file)
index 0000000..7638e04
--- /dev/null
@@ -0,0 +1,55 @@
+/* The kernel call that is implemented in this file:
+ *   m_type:    SYS_PROFBUF
+ *
+ * The parameters for this kernel call are:
+ *    m7_p1:    PROF_CTL_PTR      (location of control struct)
+ *    m7_p2:    PROF_MEM_PTR      (location of profiling table)
+ *
+ * Changes:
+ *   14 Aug, 2006   Created (Rogier Meurs)
+ */
+
+#include "../system.h"
+
+#if CPROFILE
+
+/*===========================================================================*
+ *                             do_profbuf                                   *
+ *===========================================================================*/
+PUBLIC int do_profbuf(m_ptr)
+register message *m_ptr;    /* pointer to request message */
+{
+/* 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, len;
+  vir_bytes vir_dst;
+  struct proc *rp;                          
+
+  /* Store process name, control struct, table locations. */
+  isokendpt(m_ptr->m_source, &proc_nr);
+  rp = proc_addr(proc_nr);
+
+  cprof_proc_info[cprof_procs_no].endpt = who_e;
+  cprof_proc_info[cprof_procs_no].name = rp->p_name;
+
+  len = (phys_bytes) sizeof (void *);
+
+  vir_dst = (vir_bytes) m_ptr->PROF_CTL_PTR;
+  cprof_proc_info[cprof_procs_no].ctl =
+         numap_local(proc_nr, vir_dst, len);
+
+  vir_dst = (vir_bytes) m_ptr->PROF_MEM_PTR;
+  cprof_proc_info[cprof_procs_no].buf =
+         numap_local(proc_nr, vir_dst, len);
+
+  cprof_procs_no++;
+
+  return OK;
+}
+
+#endif /* CPROFILE */
+
diff --git a/kernel/system/do_sprofile.c b/kernel/system/do_sprofile.c
new file mode 100644 (file)
index 0000000..9803338
--- /dev/null
@@ -0,0 +1,94 @@
+/* The kernel call that is implemented in this file:
+ *   m_type:    SYS_SPROFILE
+ *
+ * The parameters for this kernel call are:
+ *    m7_i1:    PROF_ACTION       (start/stop profiling)
+ *    m7_i2:    PROF_MEM_SIZE     (available memory for data)
+ *    m7_i3:    PROF_FREQ         (requested sample frequency)
+ *    m7_i4:    PROF_ENDPT        (endpoint of caller)
+ *    m7_p1:    PROF_CTL_PTR      (location of info struct)
+ *    m7_p2:    PROF_MEM_PTR      (location of memory for data)
+ *
+ * Changes:
+ *   14 Aug, 2006   Created (Rogier Meurs)
+ */
+
+#include "../system.h"
+
+#if SPROFILE
+
+/*===========================================================================*
+ *                             do_sprofile                                  *
+ *===========================================================================*/
+PUBLIC int do_sprofile(m_ptr)
+register message *m_ptr;    /* pointer to request message */
+{
+  int proc_nr, i;
+  vir_bytes vir_dst;
+  phys_bytes length;
+
+  switch(m_ptr->PROF_ACTION) {
+
+  case PROF_START:
+       /* Starting profiling.
+        *
+        * Check if profiling is not already running.  Calculate physical
+        * addresses of user pointers.  Reset counters.  Start CMOS timer.
+        * Turn on profiling.
+        */
+       if (sprofiling) {
+               kprintf("SYSTEM: start s-profiling: already started\n");
+               return EBUSY;
+       }
+
+       isokendpt(m_ptr->PROF_ENDPT, &proc_nr);
+
+       vir_dst = (vir_bytes) m_ptr->PROF_CTL_PTR;
+       length = (phys_bytes) sizeof (int *);
+       sprof_info_addr = numap_local(proc_nr, vir_dst, length);
+
+       vir_dst = (vir_bytes) m_ptr->PROF_MEM_PTR;
+       length = (phys_bytes) sizeof (char *);
+       sprof_data_addr = numap_local(proc_nr, vir_dst, length);
+
+       sprof_info.mem_used = 0;
+       sprof_info.total_samples = 0;
+       sprof_info.idle_samples = 0;
+       sprof_info.system_samples = 0;
+       sprof_info.user_samples = 0;
+
+       sprof_mem_size = m_ptr->PROF_MEM_SIZE;
+
+       init_cmos_clock(m_ptr->PROF_FREQ);
+       
+       sprofiling = 1;
+
+       return OK;
+
+  case PROF_STOP:
+       /* Stopping profiling.
+        *
+        * Check if profiling is indeed running.  Turn off profiling.
+        * Stop CMOS timer.  Copy info struct to user process.
+        */
+       if (!sprofiling) {
+               kprintf("SYSTEM: stop s-profiling: not started\n");
+               return EBUSY;
+       }
+
+       sprofiling = 0;
+
+       stop_cmos_clock();
+
+       phys_copy(vir2phys((vir_bytes) &sprof_info),
+               sprof_info_addr, (phys_bytes) sizeof(sprof_info));
+
+       return OK;
+
+  default:
+       return EINVAL;
+  }
+}
+
+#endif /* SPROFILE */
+
index 3af05c4e18a0329402517152f1b7bc4512dd2a74..9626fcdebc6172491a0172658de4ccd08493d946 100755 (executable)
@@ -82,9 +82,9 @@ PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)];
  */
 #define FS_C SYS_KILL, SYS_VIRCOPY, SYS_SAFECOPYFROM, SYS_SAFECOPYTO, \
     SYS_VIRVCOPY, SYS_UMAP, SYS_GETINFO, SYS_EXIT, SYS_TIMES, SYS_SETALARM, \
-    SYS_PRIVCTL, SYS_TRACE , SYS_SETGRANT
+    SYS_PRIVCTL, SYS_TRACE , SYS_SETGRANT, SYS_PROFBUF
 #define DRV_C  FS_C, SYS_SEGCTL, SYS_IRQCTL, SYS_INT86, SYS_DEVIO, \
-       SYS_SDEVIO, SYS_VDEVIO, SYS_SETGRANT
+       SYS_SDEVIO, SYS_VDEVIO, SYS_SETGRANT, SYS_PROFBUF
 
 PRIVATE int
   fs_c[] = { FS_C },
index 8f99cff13b16c3ecbc8471e4bf03090c847a968e..675661ac4d68aa795caa62e9d5ef8769e4d6f4e8 100644 (file)
@@ -7,6 +7,7 @@ LIBRARIES=libc
 libc_FILES=" \
        _brk.c \
        _sbrk.c \
+       _cprofile.c \
        _devctl.c \
        __pm_findproc.c \
        _getnpid.c \
@@ -18,6 +19,7 @@ libc_FILES=" \
        _reboot.c \
        _seekdir.c \
        _sysuname.c \
+       _sprofile.c \
        _svrctl.c \
        asynchio.c \
        basename.c \
diff --git a/lib/other/_cprofile.c b/lib/other/_cprofile.c
new file mode 100644 (file)
index 0000000..8d0f69e
--- /dev/null
@@ -0,0 +1,16 @@
+#include <lib.h>
+
+#define cprofile _cprofile
+
+PUBLIC int cprofile(int action, int size, char *ctl_ptr, int *mem_ptr)
+{
+  message m;
+
+  m.PROF_ACTION         = action;
+  m.PROF_MEM_SIZE       = size;
+  m.PROF_CTL_PTR        = (void *) ctl_ptr;
+  m.PROF_MEM_PTR        = (void *) mem_ptr;
+
+  return _syscall(MM, CPROF, &m);
+}
+
diff --git a/lib/other/_sprofile.c b/lib/other/_sprofile.c
new file mode 100644 (file)
index 0000000..7ae532a
--- /dev/null
@@ -0,0 +1,17 @@
+#include <lib.h>
+
+#define sprofile _sprofile
+
+PUBLIC int sprofile(int action, int size, int freq, char *ctl_ptr, int *mem_ptr)
+{
+  message m;
+
+  m.PROF_ACTION         = action;
+  m.PROF_MEM_SIZE       = size;
+  m.PROF_FREQ           = freq;
+  m.PROF_CTL_PTR        = (void *) ctl_ptr;
+  m.PROF_MEM_PTR        = (void *) mem_ptr;
+
+  return _syscall(MM, SPROF, &m);
+}
+
index debbe200274792239af3d07f0824e715f993d005..82094ba48f7a663dee81b4d115fb8ec03d8a0a96 100644 (file)
@@ -18,6 +18,7 @@ libc_FILES=" \
        chroot.s \
        close.s \
        closedir.s \
+       cprofile.s \
        creat.s \
        devctl.s \
        dup.s \
@@ -92,6 +93,7 @@ libc_FILES=" \
        sigreturn.s \
        sigsuspend.s \
        sleep.s \
+       sprofile.s \
        stat.s \
        stime.s \
        svrctl.s \
diff --git a/lib/syscall/cprofile.s b/lib/syscall/cprofile.s
new file mode 100755 (executable)
index 0000000..99d7a86
--- /dev/null
@@ -0,0 +1,7 @@
+.sect .text
+.extern        __cprofile
+.define        _cprofile
+.align 2
+
+_cprofile:
+       jmp     __cprofile
diff --git a/lib/syscall/sprofile.s b/lib/syscall/sprofile.s
new file mode 100755 (executable)
index 0000000..61ff1c6
--- /dev/null
@@ -0,0 +1,7 @@
+.sect .text
+.extern        __sprofile
+.define        _sprofile
+.align 2
+
+_sprofile:
+       jmp     __sprofile
index 48aeb2ae3d510b1c55da3c2ca1c109dc2d44ace4..bcefd8804cbd3c90b42d037c26e733c6de65d4a4 100644 (file)
@@ -26,6 +26,7 @@ libsys_FILES=" \
        pci_slot_name.c \
        safecopies.c \
        sys_abort.c \
+       sys_cprof.c \
        sys_endsig.c \
        sys_eniop.c \
        sys_exec.c \
@@ -45,6 +46,7 @@ libsys_FILES=" \
        sys_readbios.c \
        sys_safecopy.c \
        sys_vsafecopy.c \
+       sys_profbuf.c \
        sys_sdevio.c \
        sys_segctl.c \
        sys_setalarm.c \
@@ -52,6 +54,7 @@ libsys_FILES=" \
        sys_sigsend.c \
        sys_privctl.c \
        sys_setgrant.c \
+       sys_sprof.c \
        sys_times.c \
        sys_trace.c \
        sys_umap.c \
diff --git a/lib/syslib/sys_cprof.c b/lib/syslib/sys_cprof.c
new file mode 100644 (file)
index 0000000..2930305
--- /dev/null
@@ -0,0 +1,27 @@
+#include "syslib.h"
+
+#if CPROFILE
+
+/*===========================================================================*
+ *                                sys_cprof                                 *
+ *===========================================================================*/
+PUBLIC int sys_cprof(action, size, endpt, ctl_ptr, mem_ptr)
+int action;                            /* get/reset profiling tables */
+int size;                              /* size of allocated memory */
+int endpt;                             /* caller endpoint */
+void *ctl_ptr;                         /* location of info struct */
+void *mem_ptr;                         /* location of allocated memory */
+{
+  message m;
+
+  m.PROF_ACTION         = action;
+  m.PROF_MEM_SIZE       = size;
+  m.PROF_ENDPT         = endpt;
+  m.PROF_CTL_PTR        = ctl_ptr;
+  m.PROF_MEM_PTR        = mem_ptr;
+
+  return(_taskcall(SYSTASK, SYS_CPROF, &m));
+}
+
+#endif
+
diff --git a/lib/syslib/sys_profbuf.c b/lib/syslib/sys_profbuf.c
new file mode 100644 (file)
index 0000000..9c9bf36
--- /dev/null
@@ -0,0 +1,23 @@
+#include "syslib.h"
+
+#include <minix/config.h>
+
+#if CPROFILE
+
+/*===========================================================================*
+ *                                sys_profbuf                               *
+ *===========================================================================*/
+PUBLIC int sys_profbuf(ctl_ptr, mem_ptr)
+void *ctl_ptr;                         /* pointer to control structure */
+void *mem_ptr;                         /* pointer to profiling table */
+{
+  message m;
+
+  m.PROF_CTL_PTR       = ctl_ptr;
+  m.PROF_MEM_PTR       = mem_ptr;
+
+  return(_taskcall(SYSTASK, SYS_PROFBUF, &m));
+}
+
+#endif
+
diff --git a/lib/syslib/sys_sprof.c b/lib/syslib/sys_sprof.c
new file mode 100644 (file)
index 0000000..1553e89
--- /dev/null
@@ -0,0 +1,29 @@
+#include "syslib.h"
+
+#if SPROFILE
+
+/*===========================================================================*
+ *                                sys_sprof                                 *
+ *===========================================================================*/
+PUBLIC int sys_sprof(action, size, freq, endpt, ctl_ptr, mem_ptr)
+int action;                            /* start/stop profiling */
+int size;                              /* available profiling memory */
+int freq;                              /* sample frequency */
+int endpt;                             /* caller endpoint */
+void *ctl_ptr;                         /* location of info struct */
+void *mem_ptr;                         /* location of profiling memory */
+{
+  message m;
+
+  m.PROF_ACTION         = action;
+  m.PROF_MEM_SIZE       = size;
+  m.PROF_FREQ           = freq;
+  m.PROF_ENDPT         = endpt;
+  m.PROF_CTL_PTR        = ctl_ptr;
+  m.PROF_MEM_PTR        = mem_ptr;
+
+  return(_taskcall(SYSTASK, SYS_SPROF, &m));
+}
+
+#endif
+
index 06cd6d32fd88195edc5b1033d2e7bcd9e08e3a1b..c80adaa6d94395f4bc236c9d09dd3caa7555c5d5 100644 (file)
@@ -16,6 +16,9 @@ libsysutil_FILES=" \
        env_prefix.c \
        fkey_ctl.c \
        report.c \
-       taskcall.c"
+       taskcall.c \
+       read_tsc.s \
+       profile_extern.c \
+       profile.c"
 
 TYPE=both
diff --git a/lib/sysutil/profile.c b/lib/sysutil/profile.c
new file mode 100644 (file)
index 0000000..179de03
--- /dev/null
@@ -0,0 +1,289 @@
+/* 
+ * 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>
+
+#if CPROFILE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <minix/profile.h>
+#include <minix/syslib.h>
+#include <minix/u64.h>
+#include "read_tsc.h"
+
+#define U64_LO 0
+#define U64_HI 1
+
+PRIVATE char cpath[CPROF_CPATH_MAX_LEN];       /* current call path string */
+PRIVATE int cpath_len;                         /* current call path len */
+PRIVATE struct cprof_tbl_s *cprof_slot;                /* slot of current function */
+PRIVATE 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 */
+};
+PRIVATE struct stack_s cprof_stk[CPROF_STACK_SIZE];    /* stack */
+PRIVATE int cprof_stk_top;                             /* top of stack */
+EXTERN struct cprof_tbl_s cprof_tbl[];                 /* hash table */
+PRIVATE int cprof_tbl_size;                            /* nr of slots */
+PRIVATE struct cprof_tbl_s *idx[CPROF_INDEX_SIZE];     /* index to table */
+PRIVATE struct cprof_ctl_s control;            /* for comms with kernel */
+PRIVATE int cprof_announce;                    /* announce on n-th execution
+                                                * of procentry */
+PRIVATE int cprof_locked;                      /* for reentrancy */
+
+_PROTOTYPE(void procentry, (char *name) );
+_PROTOTYPE(void procexit, (char *name) );
+
+FORWARD _PROTOTYPE(void cprof_init, (void) );
+FORWARD _PROTOTYPE(void reset, (void) );
+FORWARD _PROTOTYPE(void clear_tbl, (void) );
+
+
+PUBLIC void procentry (name)
+char *name;
+{
+  static int init = 0;
+  unsigned hash = 0, i = 0, x = 0;
+  unsigned long hi, lo;
+  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(&start._[U64_HI], &start._[U64_LO]);
+
+  /* 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._[U64_HI] = start._[U64_HI];
+  cprof_stk[cprof_stk_top].start_1._[U64_LO] = start._[U64_LO];
+
+  /* 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++];
+       strcpy(cprof_slot->cpath, 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(&cprof_stk[cprof_stk_top].start_2._[U64_HI],
+               &cprof_stk[cprof_stk_top].start_2._[U64_LO]);
+  cprof_locked = 0;
+}
+
+
+PUBLIC void procexit (name)
+char *name;
+{
+  u64_t stop, spent;
+
+  /* Procexit is not reentrant. */
+  if (cprof_locked) return; else cprof_locked = 1;
+
+  /* First thing: read CPU cycle count into local variable. */
+  read_tsc(&stop._[U64_HI], &stop._[U64_LO]);
+
+  /* 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 = sub64(stop, cprof_stk[cprof_stk_top].start_2);
+  cprof_stk[cprof_stk_top].slot->cycles =
+       add64(cprof_stk[cprof_stk_top].slot->cycles, 
+               sub64(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_LO] = 0;
+  cprof_stk[cprof_stk_top].spent_deeper._[U64_HI] = 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(&stop._[U64_HI], &stop._[U64_LO]);
+
+  /* Calculate "big" difference. */
+  spent = sub64(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 =
+               add64(cprof_stk[cprof_stk_top].spent_deeper, spent);
+  cprof_locked = 0;
+}
+
+
+PRIVATE void cprof_init() {
+  message m;
+  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_LO] = 0;
+       cprof_stk[i].start_1._[U64_HI] = 0;
+       cprof_stk[i].start_2._[U64_LO] = 0;
+       cprof_stk[i].start_2._[U64_HI] = 0;
+       cprof_stk[i].spent_deeper._[U64_LO] = 0;
+       cprof_stk[i].spent_deeper._[U64_HI] = 0;
+  }
+}
+
+
+PRIVATE void reset()
+{
+  clear_tbl();
+  control.reset = 0;
+}
+
+
+PRIVATE void clear_tbl()
+{
+  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._[U64_LO] = 0;
+       cprof_tbl[i].cycles._[U64_HI] = 0;
+  }
+}
+
+#endif /* CPROFILE */
+
diff --git a/lib/sysutil/profile_extern.c b/lib/sysutil/profile_extern.c
new file mode 100644 (file)
index 0000000..928a328
--- /dev/null
@@ -0,0 +1,48 @@
+/* 
+ * 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>
+
+#if CPROFILE
+
+#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. */
+PUBLIC int profile_get_tbl_size(void)
+{
+  return CPROF_TABLE_SIZE_OTHER;
+}
+
+/* Function that returns on which execution of procentry to announce. */
+PUBLIC int profile_get_announce(void)
+{
+  return CPROF_ANNOUNCE_OTHER;
+}
+
+/*
+ * Userspace processes announce their control struct and table locations
+ * to the kernel through this function.
+ */
+PUBLIC void profile_register(ctl_ptr, tbl_ptr)
+void *ctl_ptr;
+void *tbl_ptr;
+{
+  sys_profbuf(ctl_ptr, tbl_ptr);
+}
+
+#endif /* CPROFILE */
+
diff --git a/lib/sysutil/read_tsc.h b/lib/sysutil/read_tsc.h
new file mode 100644 (file)
index 0000000..ff72854
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef READ_TSC_H
+#define READ_TSC_H
+
+_PROTOTYPE(void read_tsc, (unsigned long *hi, unsigned long *lo) );
+
+#endif /* READ_TSC_H */
+
diff --git a/lib/sysutil/read_tsc.s b/lib/sysutil/read_tsc.s
new file mode 100644 (file)
index 0000000..5d45b09
--- /dev/null
@@ -0,0 +1,23 @@
+# 
+! sections
+
+.sect .text; .sect .rom; .sect .data; .sect .bss
+
+.define        _read_tsc       ! read the cycle counter (Pentium and up)
+
+.sect .text
+!*===========================================================================*
+! PUBLIC void read_tsc(unsigned long *high, unsigned long *low);
+! Read the cycle counter of the CPU. Pentium and up. 
+.align 16
+_read_tsc:
+.data1 0x0f            ! this is the RDTSC instruction 
+.data1 0x31            ! it places the TSC in EDX:EAX
+       push ebp
+       mov ebp, 8(esp)
+       mov (ebp), edx
+       mov ebp, 12(esp)
+       mov (ebp), eax
+       pop ebp
+       ret
+
index 0e6f405598af7ff8b39da5127ad5f1f0894ba1f2..a44864b57c472df46e103e27f31738d8caf85f9d 100644 (file)
@@ -12,6 +12,6 @@ install::
        chown -R bin $(MAN)
        chgrp -R operator $(MAN)
        @rm -f $(MAN)/Makefile
-       find /usr/man -type f | xargs chmod 644
-       find /usr/man -type d | xargs chmod 755
+       find /usr/man -type f | xargs -n 20 chmod 644
+       find /usr/man -type d | xargs -n 20 chmod 755
        makewhatis $(MAN)
diff --git a/man/man1/profile.1 b/man/man1/profile.1
new file mode 100644 (file)
index 0000000..32ab70a
--- /dev/null
@@ -0,0 +1,73 @@
+.TH PROFILE 1
+.SH NAME
+profile \- MINIX system profiling control command
+.SH SYNOPSIS
+Statistical profiling:
+.PP
+.B "profile start"
+[
+.B -m 
+.I memsize
+]
+[
+.B "-o" 
+.I outfile
+]
+[
+.B -f
+.I frequency
+] 
+.br
+.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.
+.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.
+.IP "-o outfile"
+output file.
+.IP "-f frequency"
+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.
+.SH AUTHOR
+Rogier Meurs
index 5ceffb4acc5b5ce5347589cf5b0bd8be136933c7..5f4897320cbc6658e939c5e6906216b37d45df28 100644 (file)
@@ -13,9 +13,9 @@ f = $u/src/servers/fs
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
-LIBS = -lsysutil  -lsys
+LIBS = -lsysutil -lsys
 
 OBJ = main.o store.o 
 
index 3ca6f771df8b274a43d8db8f93ae4fb14218b41d..995428357f5251459501ee92a2e77ebad78492ad 100644 (file)
@@ -6,9 +6,9 @@ g = generic
 # Programs, flags, and libraries
 CC =           cc
 CPPFLAGS =     -I. -D_MINIX
-CFLAGS =       $(OPT) $(CPPFLAGS)
+CFLAGS =       $(OPT) $(CPPFLAGS) $(CPROFILE)
 LDFLAGS =
-LIBS =          -lsysutil -lsys
+LIBS =          -lsysutil -lsys
 
 .c.o:
        $(CC) $(CFLAGS) -o $@ -c $<
index 8c7963014e059de7378337d0ccce830781b4bab0..9c3c9cbf1d699984d599613a20142369bae0b6a9 100644 (file)
@@ -13,9 +13,9 @@ f = $u/src/servers/fs
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
-LIBS =  -lsysutil  -lsys
+LIBS = -lsysutil -lsys
 
 OBJ = main.o dmp.o dmp_kernel.o dmp_pm.o dmp_fs.o dmp_rs.o dmp_ds.o 
 
index 8ed054eb39a772abbdf4efd14354a8b257d57da6..4cb8d35db86570bc70ba1370d4cd871b4f12f663 100644 (file)
@@ -9,9 +9,9 @@ h = $i/minix
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i $(EXTRA_OPTS)
+CFLAGS = -I$i $(EXTRA_OPTS) $(CPROFILE)
 LDFLAGS = -i
-LIBS = -lsys -lsysutil -ltimers
+LIBS = -lsysutil  -lsys -ltimers
 
 OBJ =  cache.o device.o link.o \
        mount.o misc.o open.o pipe.o protect.o read.o \
@@ -19,10 +19,13 @@ OBJ =       cache.o device.o link.o \
        write.o inode.o main.o path.o super.o
 
 # build local binary 
-install all build:     $(SERVER)
+all build:     $(SERVER)
 $(SERVER):     $(OBJ)
        $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
-       install -S 16k $@ /sbin
+       install -S 64k $(SERVER)
+
+install: $(SERVER)
+       install $(SERVER) /sbin/$(SERVER)
 
 # clean up local files
 clean:
index 7940dde29029bb178c808981e684389dc228f536..5a8662a209dd81e675f78c29ad4801bf99430df0 100644 (file)
@@ -125,7 +125,7 @@ off_t *pos;
                             v[j].iov_addr, v[j].iov_size,
                             *op == DEV_GATHER_S ? CPF_WRITE : CPF_READ);
                           if(!GRANT_VALID(gids[j])) {
-                               panic(__FILE__, "grant to iovec buf failed",
+                               panic(__FILE__, "mfs: grant to iovec buf failed",
                                 NO_NUM);
                           }
                           new_iovec[j].iov_size = v[j].iov_size;
index 2904d09b909091802c472a6e83be5d2ce7b66133..17d52f216cf310bc88c176badb9b45563377b35d 100644 (file)
@@ -10,11 +10,12 @@ k = $u/src/kernel
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
 
 OBJ =  main.o forkexit.o break.o exec.o time.o timers.o \
-       signal.o alloc.o utility.o table.o trace.o getset.o misc.o
+       signal.o alloc.o utility.o table.o trace.o getset.o misc.o \
+       profile.o
 
 # build local binary
 all build:     $(SERVER)
diff --git a/servers/pm/profile.c b/servers/pm/profile.c
new file mode 100644 (file)
index 0000000..471bf76
--- /dev/null
@@ -0,0 +1,114 @@
+/* This file implements entry points for system profiling.
+ *
+ * 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)
+ */
+
+#include <minix/config.h>
+#include <minix/profile.h>
+#include "pm.h"
+#include <sys/wait.h>
+#include <minix/callnr.h>
+#include <minix/com.h>
+#include <signal.h>
+#include "mproc.h"
+#include "param.h"
+
+#if SPROFILE || CPROFILE
+FORWARD _PROTOTYPE( int check_addrs, (int info_size)               );
+#endif
+
+/*===========================================================================*
+ *                             do_sprofile                                  *
+ *===========================================================================*/
+PUBLIC int do_sprofile(void)
+{
+#if SPROFILE
+
+  int r;
+
+  switch(m_in.PROF_ACTION) {
+
+  case PROF_START:
+       if (r = check_addrs(sizeof(sprof_info_inst))) /* check user pointers */
+               return r;
+
+       return sys_sprof(PROF_START, m_in.PROF_MEM_SIZE, m_in.PROF_FREQ,
+                       who_e, m_in.PROF_CTL_PTR, m_in.PROF_MEM_PTR);
+
+  case PROF_STOP:
+       return sys_sprof(PROF_STOP,0,0,0,0,0);
+
+  default:
+       return EINVAL;
+  }
+
+#else
+       return ENOSYS;
+#endif
+}
+
+
+/*===========================================================================*
+ *                             do_cprofile                                  *
+ *===========================================================================*/
+PUBLIC int do_cprofile(void)
+{
+#if CPROFILE
+
+  int r;
+
+  switch(m_in.PROF_ACTION) {
+
+  case PROF_GET:
+       if (r = check_addrs(sizeof(cprof_info_inst))) /* check user pointers */
+               return r;
+
+       return sys_cprof(PROF_GET, m_in.PROF_MEM_SIZE, who_e,
+               m_in.PROF_CTL_PTR, m_in.PROF_MEM_PTR);
+
+  case PROF_RESET:
+       return sys_cprof(PROF_RESET,0,0,0,0);
+
+  default:
+       return EINVAL;
+  }
+
+#else
+       return ENOSYS;
+#endif
+}
+
+
+#if SPROFILE || CPROFILE
+
+/*===========================================================================*
+ *                             check_addrs                                  *
+ *===========================================================================*/
+PRIVATE int check_addrs(info_size)
+int info_size;
+{
+  int r;
+  phys_bytes p;
+
+  /* Check if supplied pointers point into user process. */
+  if ((r = sys_umap(who_e, D, (vir_bytes) m_in.PROF_CTL_PTR,
+                                                info_size, &p)) != OK) {
+       printf("PM: PROFILE: umap failed for process %d\n", who_e);
+       return r;                                    
+  }  
+
+  if ((r =sys_umap(who_e, D, (vir_bytes) m_in.PROF_MEM_PTR,
+                                        m_in.PROF_MEM_SIZE, &p)) != OK) {
+       printf("PM: PROFILE: umap failed for process %d\n", who_e);
+       return r;                                    
+  }  
+  return 0;
+}
+
+#endif
+
index 518f7650ceafbbc6e1221eaeada36ded2f0e3e73..9b9436a911aac00936cf974a1ecf1de558c163c5 100644 (file)
@@ -80,6 +80,10 @@ _PROTOTYPE( phys_clicks start_click, (void)                          );
 
 _PROTOTYPE( void setreply, (int proc_nr, int result)                   );
 
+/* profile.c */
+_PROTOTYPE( int do_sprofile, (void)                                    );
+_PROTOTYPE( int do_cprofile, (void)                                    );
+
 /* signal.c */
 _PROTOTYPE( int do_alarm, (void)                                       );
 _PROTOTYPE( int do_kill, (void)                                                );
index a130221b37508a71c50892e28716e62772ab1f9d..d1aaecf3e29ea7b029820d6b94c6922dae58ae93 100644 (file)
@@ -113,6 +113,8 @@ _PROTOTYPE (int (*call_vec[NCALLS]), (void) ) = {
        no_sys,         /* 95 = (fchmod) */
        no_sys,         /* 96 = (fchown) */
        do_getsysinfo_up,/* 97 = getsysinfo_up */
+       do_sprofile,    /* 98 = sprofile */
+       do_cprofile,    /* 99 = cprofile */
 };
 /* This should not fail with "array size is negative": */
 extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
index a1e998a0e87b805e03a17c22d5574159ebb2fa57..04bb1ace84ad311920f1d97e359aed51f4c361ea 100644 (file)
@@ -11,10 +11,10 @@ b = $i/ibm
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
-UTIL_LIBS = -lsys 
-LIBS =  -lsysutil  -lsys
+UTIL_LIBS = -lsysutil  -lsys 
+LIBS = -lsysutil -lsys
 
 UTIL_OBJ = service.o
 OBJ = exec.o main.o manager.o 
index 3258319d659e8b59be59faae791eb46b01d1e1e4..3fa3184ba40be144d0e4b98a07a9792cc0c14e31 100644 (file)
@@ -11,7 +11,7 @@ b = $i/ibm
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i
+CFLAGS = -I$i $(CPROFILE)
 LDFLAGS = -i
 UTIL_LIBS = -lsys 
 LIBS = -lsys -lsysutil 
index 9d80d14d428e2c7aec65e771a2667765bcaa814c..837d9626d725cdbef4d405fd848e917a3cad6ebc 100644 (file)
@@ -9,9 +9,9 @@ h = $i/minix
 
 # programs, flags, etc.
 CC =   exec cc
-CFLAGS = -I$i $(EXTRA_OPTS)
+CFLAGS = -I$i $(EXTRA_OPTS) $(CPROFILE)
 LDFLAGS = -i
-LIBS = -lsys -lsysutil -ltimers
+LIBS = -lsysutil -lsys -ltimers
 
 OBJ =  main.o open.o read.o write.o pipe.o dmap.o \
        path.o device.o mount.o link.o exec.o \
@@ -21,6 +21,7 @@ OBJ = main.o open.o read.o write.o pipe.o dmap.o \
 
 # build local binary 
 install all build:     $(SERVER)
+
 $(SERVER):     $(OBJ)
        $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
        install -S 16k $@
index f347ac3356c978dd8b92f19b5cb1d7a62b2f955d..aada1f9520c9f85c76b2d5afc7bf26d526ccf87b 100644 (file)
@@ -116,6 +116,8 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
        do_chmod,       /* 95 = fchmod */
        do_chown,       /* 96 = fchown */
        no_sys,         /* 97 = getsysinfo_up */
+       no_sys,         /* 98 = (sprofile) */
+       no_sys,         /* 99 = (cprofile) */
 };
 /* This should not fail with "array size is negative": */
 extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];