1*433d6423SLionel Sambuc /* profile - profile operating system 2*433d6423SLionel Sambuc * 3*433d6423SLionel Sambuc * The profile command is used to control Statistical and Call Profiling. 4*433d6423SLionel Sambuc * It writes the profiling data collected by the kernel to a file. 5*433d6423SLionel Sambuc * 6*433d6423SLionel Sambuc * Changes: 7*433d6423SLionel Sambuc * 14 Aug, 2006 Created (Rogier Meurs) 8*433d6423SLionel Sambuc */ 9*433d6423SLionel Sambuc 10*433d6423SLionel Sambuc #include <errno.h> 11*433d6423SLionel Sambuc #include <fcntl.h> 12*433d6423SLionel Sambuc #include <stdio.h> 13*433d6423SLionel Sambuc #include <stdlib.h> 14*433d6423SLionel Sambuc #include <string.h> 15*433d6423SLionel Sambuc #include <unistd.h> 16*433d6423SLionel Sambuc #include <sys/stat.h> 17*433d6423SLionel Sambuc #undef SPROFILE 18*433d6423SLionel Sambuc #define SPROFILE 1 19*433d6423SLionel Sambuc #include <minix/profile.h> 20*433d6423SLionel Sambuc 21*433d6423SLionel Sambuc #define EHELP 1 22*433d6423SLionel Sambuc #define ESYNTAX 2 23*433d6423SLionel Sambuc #define EMEM 3 24*433d6423SLionel Sambuc #define EOUTFILE 4 25*433d6423SLionel Sambuc #define EFREQ 5 26*433d6423SLionel Sambuc #define EACTION 6 27*433d6423SLionel Sambuc 28*433d6423SLionel Sambuc #define START 1 29*433d6423SLionel Sambuc #define STOP 2 30*433d6423SLionel Sambuc #define GET 3 31*433d6423SLionel Sambuc #define RESET 4 32*433d6423SLionel Sambuc 33*433d6423SLionel Sambuc #define SPROF (action==START||action==STOP) 34*433d6423SLionel Sambuc #define CPROF (!SPROF) 35*433d6423SLionel Sambuc #define DEF_OUTFILE_S "profile.stat.out" 36*433d6423SLionel Sambuc #define DEF_OUTFILE_C "profile.call.out" 37*433d6423SLionel Sambuc #define DEF_OUTFILE (SPROF?DEF_OUTFILE_S:DEF_OUTFILE_C) 38*433d6423SLionel Sambuc #define NPIPE "/tmp/profile.npipe" 39*433d6423SLionel Sambuc #define MIN_MEMSIZE 1 40*433d6423SLionel Sambuc #define DEF_MEMSIZE 64 41*433d6423SLionel Sambuc #define MIN_FREQ 3 42*433d6423SLionel Sambuc #define MAX_FREQ 15 43*433d6423SLionel Sambuc #define DEF_FREQ 6 44*433d6423SLionel Sambuc #define BUFSIZE 1024 45*433d6423SLionel Sambuc #define MB (1024*1024) 46*433d6423SLionel Sambuc #define SYNCING "SYNC" 47*433d6423SLionel Sambuc #define DEV_LOG "/dev/log" 48*433d6423SLionel Sambuc 49*433d6423SLionel Sambuc int action = 0; 50*433d6423SLionel Sambuc int mem_size = 0; 51*433d6423SLionel Sambuc int mem_used = 0; 52*433d6423SLionel Sambuc int freq = 0; 53*433d6423SLionel Sambuc int intr_type = PROF_RTC; 54*433d6423SLionel Sambuc char *outfile = ""; 55*433d6423SLionel Sambuc char *mem_ptr; 56*433d6423SLionel Sambuc int outfile_fd, npipe_fd; 57*433d6423SLionel Sambuc struct sprof_info_s sprof_info; 58*433d6423SLionel Sambuc struct cprof_info_s cprof_info; 59*433d6423SLionel Sambuc 60*433d6423SLionel Sambuc #define HASH_MOD 128 61*433d6423SLionel Sambuc struct sproc { 62*433d6423SLionel Sambuc endpoint_t ep; 63*433d6423SLionel Sambuc char name[8]; 64*433d6423SLionel Sambuc struct sproc * next; 65*433d6423SLionel Sambuc }; 66*433d6423SLionel Sambuc 67*433d6423SLionel Sambuc static struct sproc * proc_hash[HASH_MOD]; 68*433d6423SLionel Sambuc 69*433d6423SLionel Sambuc int handle_args(int argc, char *argv[]); 70*433d6423SLionel Sambuc int start(void); 71*433d6423SLionel Sambuc int stop(void); 72*433d6423SLionel Sambuc int get(void); 73*433d6423SLionel Sambuc int reset(void); 74*433d6423SLionel Sambuc int create_named_pipe(void); 75*433d6423SLionel Sambuc int alloc_mem(void); 76*433d6423SLionel Sambuc int init_outfile(void); 77*433d6423SLionel Sambuc int write_outfile(void); 78*433d6423SLionel Sambuc int write_outfile_cprof(void); 79*433d6423SLionel Sambuc int write_outfile_sprof(void); 80*433d6423SLionel Sambuc void detach(void); 81*433d6423SLionel Sambuc 82*433d6423SLionel Sambuc int main(int argc, char *argv[]) 83*433d6423SLionel Sambuc { 84*433d6423SLionel Sambuc int res; 85*433d6423SLionel Sambuc 86*433d6423SLionel Sambuc if ((res = handle_args(argc, argv))) { 87*433d6423SLionel Sambuc switch(res) { 88*433d6423SLionel Sambuc case ESYNTAX: 89*433d6423SLionel Sambuc printf("Error in parameters.\n"); 90*433d6423SLionel Sambuc return 1; 91*433d6423SLionel Sambuc break; 92*433d6423SLionel Sambuc case EACTION: 93*433d6423SLionel Sambuc printf("Specify one of start|stop|get|reset.\n"); 94*433d6423SLionel Sambuc return 1; 95*433d6423SLionel Sambuc break; 96*433d6423SLionel Sambuc case EMEM: 97*433d6423SLionel Sambuc printf("Incorrect memory size.\n"); 98*433d6423SLionel Sambuc return 1; 99*433d6423SLionel Sambuc break; 100*433d6423SLionel Sambuc case EFREQ: 101*433d6423SLionel Sambuc printf("Incorrect frequency.\n"); 102*433d6423SLionel Sambuc return 1; 103*433d6423SLionel Sambuc break; 104*433d6423SLionel Sambuc case EOUTFILE: 105*433d6423SLionel Sambuc printf("Output filename missing.\n"); 106*433d6423SLionel Sambuc return 1; 107*433d6423SLionel Sambuc break; 108*433d6423SLionel Sambuc default: 109*433d6423SLionel Sambuc break; 110*433d6423SLionel Sambuc } 111*433d6423SLionel Sambuc 112*433d6423SLionel Sambuc /* 113*433d6423SLionel Sambuc * Check the frequency when we know the intr type. Only selected values 114*433d6423SLionel Sambuc * are correct for RTC 115*433d6423SLionel Sambuc */ 116*433d6423SLionel Sambuc if (action == START && intr_type == PROF_RTC && 117*433d6423SLionel Sambuc (freq < MIN_FREQ || freq > MAX_FREQ)) { 118*433d6423SLionel Sambuc printf("Incorrect frequency.\n"); 119*433d6423SLionel Sambuc return 1; 120*433d6423SLionel Sambuc } 121*433d6423SLionel Sambuc 122*433d6423SLionel Sambuc printf("Statistical Profiling:\n"); 123*433d6423SLionel Sambuc printf(" profile start [--rtc | --nmi] " 124*433d6423SLionel Sambuc "[-m memsize] [-o outfile] [-f frequency]\n"); 125*433d6423SLionel Sambuc printf(" profile stop\n\n"); 126*433d6423SLionel Sambuc printf(" --rtc is default, --nmi allows kernel profiling\n"); 127*433d6423SLionel Sambuc printf("Call Profiling:\n"); 128*433d6423SLionel Sambuc printf(" profile get [-m memsize] [-o outfile]\n"); 129*433d6423SLionel Sambuc printf(" profile reset\n\n"); 130*433d6423SLionel Sambuc printf(" - memsize in MB, default: %u\n", DEF_MEMSIZE); 131*433d6423SLionel Sambuc printf(" - default output file: profile.{stat|call}.out\n"); 132*433d6423SLionel Sambuc printf( " - sample frequencies for --rtc (default: %u):\n", DEF_FREQ); 133*433d6423SLionel Sambuc printf(" 3 8192 Hz 10 64 Hz\n"); 134*433d6423SLionel Sambuc printf(" 4 4096 Hz 11 32 Hz\n"); 135*433d6423SLionel Sambuc printf(" 5 2048 Hz 12 16 Hz\n"); 136*433d6423SLionel Sambuc printf(" 6 1024 Hz 13 8 Hz\n"); 137*433d6423SLionel Sambuc printf(" 7 512 Hz 14 4 Hz\n"); 138*433d6423SLionel Sambuc printf(" 8 256 Hz 15 2 Hz\n"); 139*433d6423SLionel Sambuc printf(" 9 128 Hz\n\n"); 140*433d6423SLionel Sambuc printf("Use [sc]profalyze.pl to analyze output file.\n"); 141*433d6423SLionel Sambuc return 1; 142*433d6423SLionel Sambuc } 143*433d6423SLionel Sambuc 144*433d6423SLionel Sambuc switch(action) { 145*433d6423SLionel Sambuc case START: 146*433d6423SLionel Sambuc if (start()) return 1; 147*433d6423SLionel Sambuc break; 148*433d6423SLionel Sambuc case STOP: 149*433d6423SLionel Sambuc if (stop()) return 1; 150*433d6423SLionel Sambuc break; 151*433d6423SLionel Sambuc case GET: 152*433d6423SLionel Sambuc if (get()) return 1; 153*433d6423SLionel Sambuc break; 154*433d6423SLionel Sambuc case RESET: 155*433d6423SLionel Sambuc if (reset()) return 1; 156*433d6423SLionel Sambuc break; 157*433d6423SLionel Sambuc default: 158*433d6423SLionel Sambuc break; 159*433d6423SLionel Sambuc } 160*433d6423SLionel Sambuc return 0; 161*433d6423SLionel Sambuc } 162*433d6423SLionel Sambuc 163*433d6423SLionel Sambuc 164*433d6423SLionel Sambuc int handle_args(int argc, char *argv[]) 165*433d6423SLionel Sambuc { 166*433d6423SLionel Sambuc while (--argc) { 167*433d6423SLionel Sambuc ++argv; 168*433d6423SLionel Sambuc 169*433d6423SLionel Sambuc if (strcmp(*argv, "-h") == 0 || strcmp(*argv, "help") == 0 || 170*433d6423SLionel Sambuc strcmp(*argv, "--help") == 0) { 171*433d6423SLionel Sambuc return EHELP; 172*433d6423SLionel Sambuc } else 173*433d6423SLionel Sambuc if (strcmp(*argv, "-m") == 0) { 174*433d6423SLionel Sambuc if (--argc == 0) return ESYNTAX; 175*433d6423SLionel Sambuc if (sscanf(*++argv, "%u", &mem_size) != 1 || 176*433d6423SLionel Sambuc mem_size < MIN_MEMSIZE ) return EMEM; 177*433d6423SLionel Sambuc } else 178*433d6423SLionel Sambuc if (strcmp(*argv, "-f") == 0) { 179*433d6423SLionel Sambuc if (--argc == 0) return ESYNTAX; 180*433d6423SLionel Sambuc if (sscanf(*++argv, "%u", &freq) != 1) 181*433d6423SLionel Sambuc return EFREQ; 182*433d6423SLionel Sambuc } else 183*433d6423SLionel Sambuc if (strcmp(*argv, "-o") == 0) { 184*433d6423SLionel Sambuc if (--argc == 0) return ESYNTAX; 185*433d6423SLionel Sambuc outfile = *++argv; 186*433d6423SLionel Sambuc } else 187*433d6423SLionel Sambuc if (strcmp(*argv, "--rtc") == 0) { 188*433d6423SLionel Sambuc intr_type = PROF_RTC; 189*433d6423SLionel Sambuc } else 190*433d6423SLionel Sambuc if (strcmp(*argv, "--nmi") == 0) { 191*433d6423SLionel Sambuc intr_type = PROF_NMI; 192*433d6423SLionel Sambuc } else 193*433d6423SLionel Sambuc if (strcmp(*argv, "start") == 0) { 194*433d6423SLionel Sambuc if (action) return EACTION; 195*433d6423SLionel Sambuc action = START; 196*433d6423SLionel Sambuc } else 197*433d6423SLionel Sambuc if (strcmp(*argv, "stop") == 0) { 198*433d6423SLionel Sambuc if (action) return EACTION; 199*433d6423SLionel Sambuc action = STOP; 200*433d6423SLionel Sambuc } else 201*433d6423SLionel Sambuc if (strcmp(*argv, "get") == 0) { 202*433d6423SLionel Sambuc if (action) return EACTION; 203*433d6423SLionel Sambuc action = GET; 204*433d6423SLionel Sambuc } else 205*433d6423SLionel Sambuc if (strcmp(*argv, "reset") == 0) { 206*433d6423SLionel Sambuc if (action) return EACTION; 207*433d6423SLionel Sambuc action = RESET; 208*433d6423SLionel Sambuc } 209*433d6423SLionel Sambuc } 210*433d6423SLionel Sambuc 211*433d6423SLionel Sambuc /* No action specified. */ 212*433d6423SLionel Sambuc if (!action) return EHELP; 213*433d6423SLionel Sambuc 214*433d6423SLionel Sambuc /* Init unspecified parameters. */ 215*433d6423SLionel Sambuc if (action == START || action == GET) { 216*433d6423SLionel Sambuc if (strcmp(outfile, "") == 0) outfile = DEF_OUTFILE; 217*433d6423SLionel Sambuc if (mem_size == 0) mem_size = DEF_MEMSIZE; 218*433d6423SLionel Sambuc mem_size *= MB; /* mem_size in bytes */ 219*433d6423SLionel Sambuc } 220*433d6423SLionel Sambuc if (action == START) { 221*433d6423SLionel Sambuc mem_size -= mem_size % sizeof(struct sprof_sample); /* align to sample size */ 222*433d6423SLionel Sambuc if (freq == 0) freq = DEF_FREQ; /* default frequency */ 223*433d6423SLionel Sambuc } 224*433d6423SLionel Sambuc return 0; 225*433d6423SLionel Sambuc } 226*433d6423SLionel Sambuc 227*433d6423SLionel Sambuc 228*433d6423SLionel Sambuc int start() 229*433d6423SLionel Sambuc { 230*433d6423SLionel Sambuc /* This is the "starter process" for statistical profiling. 231*433d6423SLionel Sambuc * 232*433d6423SLionel Sambuc * Create output file for profiling data. Create named pipe to 233*433d6423SLionel Sambuc * synchronize with stopper process. Fork so the parent can exit. 234*433d6423SLionel Sambuc * Allocate memory for profiling data. Start profiling in kernel. 235*433d6423SLionel Sambuc * Complete detachment from terminal. Write known string to named 236*433d6423SLionel Sambuc * pipe, which blocks until read by stopper process. Redirect 237*433d6423SLionel Sambuc * stdout/stderr to the named pipe. Write profiling data to file. 238*433d6423SLionel Sambuc * Clean up. 239*433d6423SLionel Sambuc */ 240*433d6423SLionel Sambuc int log_fd; 241*433d6423SLionel Sambuc 242*433d6423SLionel Sambuc if (init_outfile() || create_named_pipe()) return 1; 243*433d6423SLionel Sambuc 244*433d6423SLionel Sambuc printf("Starting statistical profiling.\n"); 245*433d6423SLionel Sambuc 246*433d6423SLionel Sambuc if (fork() != 0) exit(0); 247*433d6423SLionel Sambuc 248*433d6423SLionel Sambuc if (alloc_mem()) return 1; 249*433d6423SLionel Sambuc 250*433d6423SLionel Sambuc if (sprofile(PROF_START, mem_size, freq, intr_type, &sprof_info, mem_ptr)) { 251*433d6423SLionel Sambuc perror("sprofile"); 252*433d6423SLionel Sambuc fprintf(stderr, "Error starting profiling.\n"); 253*433d6423SLionel Sambuc return 1; 254*433d6423SLionel Sambuc } 255*433d6423SLionel Sambuc 256*433d6423SLionel Sambuc detach(); 257*433d6423SLionel Sambuc 258*433d6423SLionel Sambuc /* Temporarily redirect to system log to catch errors. */ 259*433d6423SLionel Sambuc log_fd = open(DEV_LOG, O_WRONLY); 260*433d6423SLionel Sambuc dup2(log_fd, 1); 261*433d6423SLionel Sambuc dup2(log_fd, 2); 262*433d6423SLionel Sambuc 263*433d6423SLionel Sambuc if ((npipe_fd = open(NPIPE, O_WRONLY)) < 0) { 264*433d6423SLionel Sambuc fprintf(stderr, "Unable to open named pipe %s.\n", NPIPE); 265*433d6423SLionel Sambuc return 1; 266*433d6423SLionel Sambuc } else 267*433d6423SLionel Sambuc /* Synchronize with stopper process. */ 268*433d6423SLionel Sambuc write(npipe_fd, SYNCING, strlen(SYNCING)); 269*433d6423SLionel Sambuc 270*433d6423SLionel Sambuc /* Now redirect to named pipe. */ 271*433d6423SLionel Sambuc dup2(npipe_fd, 1); 272*433d6423SLionel Sambuc dup2(npipe_fd, 2); 273*433d6423SLionel Sambuc 274*433d6423SLionel Sambuc mem_used = sprof_info.mem_used; 275*433d6423SLionel Sambuc 276*433d6423SLionel Sambuc if (mem_used == -1) { 277*433d6423SLionel Sambuc fprintf(stderr, "WARNING: Profiling was stopped prematurely due to "); 278*433d6423SLionel Sambuc fprintf(stderr, "insufficient memory.\n"); 279*433d6423SLionel Sambuc fprintf(stderr, "Try increasing available memory using the -m switch.\n"); 280*433d6423SLionel Sambuc } 281*433d6423SLionel Sambuc 282*433d6423SLionel Sambuc if (write_outfile()) return 1; 283*433d6423SLionel Sambuc 284*433d6423SLionel Sambuc close(log_fd); 285*433d6423SLionel Sambuc close(npipe_fd); 286*433d6423SLionel Sambuc unlink(NPIPE); 287*433d6423SLionel Sambuc close(outfile_fd); 288*433d6423SLionel Sambuc free(mem_ptr); 289*433d6423SLionel Sambuc 290*433d6423SLionel Sambuc return 0; 291*433d6423SLionel Sambuc } 292*433d6423SLionel Sambuc 293*433d6423SLionel Sambuc 294*433d6423SLionel Sambuc int stop() 295*433d6423SLionel Sambuc { 296*433d6423SLionel Sambuc /* This is the "stopper" process for statistical profiling. 297*433d6423SLionel Sambuc * 298*433d6423SLionel Sambuc * Stop profiling in kernel. Read known string from named pipe 299*433d6423SLionel Sambuc * to synchronize with starter proces. Read named pipe until EOF 300*433d6423SLionel Sambuc * and write to stdout, this allows feedback from started process 301*433d6423SLionel Sambuc * to be printed. 302*433d6423SLionel Sambuc */ 303*433d6423SLionel Sambuc int n; 304*433d6423SLionel Sambuc char buf[BUFSIZE]; 305*433d6423SLionel Sambuc 306*433d6423SLionel Sambuc if (sprofile(PROF_STOP, 0, 0, 0, 0, 0)) { 307*433d6423SLionel Sambuc perror("sprofile"); 308*433d6423SLionel Sambuc fprintf(stderr, "Error stopping profiling.\n"); 309*433d6423SLionel Sambuc return 1; 310*433d6423SLionel Sambuc } else printf("Statistical profiling stopped.\n"); 311*433d6423SLionel Sambuc 312*433d6423SLionel Sambuc if ((npipe_fd = open(NPIPE, O_RDONLY)) < 0) { 313*433d6423SLionel Sambuc fprintf(stderr, "Unable to open named pipe %s.\n", NPIPE); 314*433d6423SLionel Sambuc return 1; 315*433d6423SLionel Sambuc } else 316*433d6423SLionel Sambuc /* Synchronize with starter process. */ 317*433d6423SLionel Sambuc read(npipe_fd, buf, strlen(SYNCING)); 318*433d6423SLionel Sambuc 319*433d6423SLionel Sambuc while ((n = read(npipe_fd, buf, BUFSIZE)) > 0) 320*433d6423SLionel Sambuc write(1, buf, n); 321*433d6423SLionel Sambuc 322*433d6423SLionel Sambuc close(npipe_fd); 323*433d6423SLionel Sambuc 324*433d6423SLionel Sambuc return 0; 325*433d6423SLionel Sambuc } 326*433d6423SLionel Sambuc 327*433d6423SLionel Sambuc 328*433d6423SLionel Sambuc int get() 329*433d6423SLionel Sambuc { 330*433d6423SLionel Sambuc /* Get function for call profiling. 331*433d6423SLionel Sambuc * 332*433d6423SLionel Sambuc * Create output file. Allocate memory. Perform system call to get 333*433d6423SLionel Sambuc * profiling table and write it to file. Clean up. 334*433d6423SLionel Sambuc */ 335*433d6423SLionel Sambuc if (init_outfile()) return 1; 336*433d6423SLionel Sambuc 337*433d6423SLionel Sambuc printf("Getting call profiling data.\n"); 338*433d6423SLionel Sambuc 339*433d6423SLionel Sambuc if (alloc_mem()) return 1; 340*433d6423SLionel Sambuc 341*433d6423SLionel Sambuc if (cprofile(PROF_GET, mem_size, &cprof_info, mem_ptr)) { 342*433d6423SLionel Sambuc perror("cprofile"); 343*433d6423SLionel Sambuc fprintf(stderr, "Error getting data.\n"); 344*433d6423SLionel Sambuc return 1; 345*433d6423SLionel Sambuc } 346*433d6423SLionel Sambuc 347*433d6423SLionel Sambuc mem_used = cprof_info.mem_used; 348*433d6423SLionel Sambuc 349*433d6423SLionel Sambuc if (mem_used == -1) { 350*433d6423SLionel Sambuc fprintf(stderr, "ERROR: unable to get data due to insufficient memory.\n"); 351*433d6423SLionel Sambuc fprintf(stderr, "Try increasing available memory using the -m switch.\n"); 352*433d6423SLionel Sambuc } else 353*433d6423SLionel Sambuc if (cprof_info.err) { 354*433d6423SLionel Sambuc fprintf(stderr, "ERROR: the following error(s) happened during profiling:\n"); 355*433d6423SLionel Sambuc if (cprof_info.err & CPROF_CPATH_OVERRUN) 356*433d6423SLionel Sambuc fprintf(stderr, " call path overrun\n"); 357*433d6423SLionel Sambuc if (cprof_info.err & CPROF_STACK_OVERRUN) 358*433d6423SLionel Sambuc fprintf(stderr, " call stack overrun\n"); 359*433d6423SLionel Sambuc if (cprof_info.err & CPROF_TABLE_OVERRUN) 360*433d6423SLionel Sambuc fprintf(stderr, " hash table overrun\n"); 361*433d6423SLionel Sambuc fprintf(stderr, "Try changing values in /usr/src/include/minix/profile.h "); 362*433d6423SLionel Sambuc fprintf(stderr, "and then rebuild the system.\n"); 363*433d6423SLionel Sambuc } else 364*433d6423SLionel Sambuc if (write_outfile()) return 1; 365*433d6423SLionel Sambuc 366*433d6423SLionel Sambuc close(outfile_fd); 367*433d6423SLionel Sambuc free(mem_ptr); 368*433d6423SLionel Sambuc 369*433d6423SLionel Sambuc return 0; 370*433d6423SLionel Sambuc } 371*433d6423SLionel Sambuc 372*433d6423SLionel Sambuc 373*433d6423SLionel Sambuc int reset() 374*433d6423SLionel Sambuc { 375*433d6423SLionel Sambuc /* Reset function for call profiling. 376*433d6423SLionel Sambuc * 377*433d6423SLionel Sambuc * Perform system call to reset profiling table. 378*433d6423SLionel Sambuc */ 379*433d6423SLionel Sambuc printf("Resetting call profiling data.\n"); 380*433d6423SLionel Sambuc 381*433d6423SLionel Sambuc if (cprofile(PROF_RESET, 0, 0, 0)) { 382*433d6423SLionel Sambuc perror("cprofile"); 383*433d6423SLionel Sambuc fprintf(stderr, "Error resetting data.\n"); 384*433d6423SLionel Sambuc return 1; 385*433d6423SLionel Sambuc } 386*433d6423SLionel Sambuc 387*433d6423SLionel Sambuc return 0; 388*433d6423SLionel Sambuc } 389*433d6423SLionel Sambuc 390*433d6423SLionel Sambuc 391*433d6423SLionel Sambuc int alloc_mem() 392*433d6423SLionel Sambuc { 393*433d6423SLionel Sambuc if ((mem_ptr = malloc(mem_size)) == 0) { 394*433d6423SLionel Sambuc fprintf(stderr, "Unable to allocate memory.\n"); 395*433d6423SLionel Sambuc fprintf(stderr, "Used chmem to increase available proces memory?\n"); 396*433d6423SLionel Sambuc return 1; 397*433d6423SLionel Sambuc } else memset(mem_ptr, '\0', mem_size); 398*433d6423SLionel Sambuc 399*433d6423SLionel Sambuc return 0; 400*433d6423SLionel Sambuc } 401*433d6423SLionel Sambuc 402*433d6423SLionel Sambuc 403*433d6423SLionel Sambuc int init_outfile() 404*433d6423SLionel Sambuc { 405*433d6423SLionel Sambuc if ((outfile_fd = open(outfile, O_CREAT | O_TRUNC | O_WRONLY)) <= 0) { 406*433d6423SLionel Sambuc fprintf(stderr, "Unable to create outfile %s.\n", outfile); 407*433d6423SLionel Sambuc return 1; 408*433d6423SLionel Sambuc } else chmod(outfile, S_IRUSR | S_IWUSR); 409*433d6423SLionel Sambuc 410*433d6423SLionel Sambuc return 0; 411*433d6423SLionel Sambuc } 412*433d6423SLionel Sambuc 413*433d6423SLionel Sambuc 414*433d6423SLionel Sambuc int create_named_pipe() 415*433d6423SLionel Sambuc { 416*433d6423SLionel Sambuc if ((mkfifo(NPIPE, S_IRUSR | S_IWUSR) == -1) && (errno != EEXIST)) { 417*433d6423SLionel Sambuc fprintf(stderr, "Unable to create named pipe %s.\n", NPIPE); 418*433d6423SLionel Sambuc return 1; 419*433d6423SLionel Sambuc } else 420*433d6423SLionel Sambuc return 0; 421*433d6423SLionel Sambuc } 422*433d6423SLionel Sambuc 423*433d6423SLionel Sambuc 424*433d6423SLionel Sambuc void detach() 425*433d6423SLionel Sambuc { 426*433d6423SLionel Sambuc setsid(); 427*433d6423SLionel Sambuc (void) chdir("/"); 428*433d6423SLionel Sambuc close(0); 429*433d6423SLionel Sambuc close(1); 430*433d6423SLionel Sambuc close(2); 431*433d6423SLionel Sambuc } 432*433d6423SLionel Sambuc 433*433d6423SLionel Sambuc static void add_proc(struct sprof_proc * p) 434*433d6423SLionel Sambuc { 435*433d6423SLionel Sambuc struct sproc * n; 436*433d6423SLionel Sambuc int slot = ((unsigned)(p->proc)) % HASH_MOD; 437*433d6423SLionel Sambuc 438*433d6423SLionel Sambuc n = malloc(sizeof(struct sproc)); 439*433d6423SLionel Sambuc if (!n) 440*433d6423SLionel Sambuc abort(); 441*433d6423SLionel Sambuc n->ep = p->proc; 442*433d6423SLionel Sambuc memcpy(n->name, p->name, 8); 443*433d6423SLionel Sambuc n->next = proc_hash[slot]; 444*433d6423SLionel Sambuc proc_hash[slot] = n; 445*433d6423SLionel Sambuc } 446*433d6423SLionel Sambuc 447*433d6423SLionel Sambuc static char * get_proc_name(endpoint_t ep) 448*433d6423SLionel Sambuc { 449*433d6423SLionel Sambuc struct sproc * p; 450*433d6423SLionel Sambuc 451*433d6423SLionel Sambuc for (p = proc_hash[((unsigned)ep) % HASH_MOD]; p; p = p->next) { 452*433d6423SLionel Sambuc if (p->ep == ep) 453*433d6423SLionel Sambuc return p->name; 454*433d6423SLionel Sambuc } 455*433d6423SLionel Sambuc 456*433d6423SLionel Sambuc return NULL; 457*433d6423SLionel Sambuc } 458*433d6423SLionel Sambuc 459*433d6423SLionel Sambuc int write_outfile() 460*433d6423SLionel Sambuc { 461*433d6423SLionel Sambuc ssize_t n; 462*433d6423SLionel Sambuc int written; 463*433d6423SLionel Sambuc char header[80]; 464*433d6423SLionel Sambuc 465*433d6423SLionel Sambuc printf("Writing to %s ...", outfile); 466*433d6423SLionel Sambuc 467*433d6423SLionel Sambuc /* Write header. */ 468*433d6423SLionel Sambuc if (SPROF) 469*433d6423SLionel Sambuc sprintf(header, "stat\n%u %u %u\n", sizeof(struct sprof_info_s), 470*433d6423SLionel Sambuc sizeof(struct sprof_sample), 471*433d6423SLionel Sambuc sizeof(struct sprof_proc)); 472*433d6423SLionel Sambuc else 473*433d6423SLionel Sambuc sprintf(header, "call\n%u %u\n", 474*433d6423SLionel Sambuc CPROF_CPATH_MAX_LEN, CPROF_PROCNAME_LEN); 475*433d6423SLionel Sambuc 476*433d6423SLionel Sambuc n = write(outfile_fd, header, strlen(header)); 477*433d6423SLionel Sambuc 478*433d6423SLionel Sambuc if (n < 0) { 479*433d6423SLionel Sambuc fprintf(stderr, "Error writing to outfile %s.\n", outfile); 480*433d6423SLionel Sambuc return 1; 481*433d6423SLionel Sambuc } 482*433d6423SLionel Sambuc 483*433d6423SLionel Sambuc /* for sprofile, raw data will do; cprofile is handled by a script that needs 484*433d6423SLionel Sambuc * some preprocessing to be done by us 485*433d6423SLionel Sambuc */ 486*433d6423SLionel Sambuc if (SPROF) { 487*433d6423SLionel Sambuc written = write_outfile_sprof(); 488*433d6423SLionel Sambuc } else { 489*433d6423SLionel Sambuc written = write_outfile_cprof(); 490*433d6423SLionel Sambuc } 491*433d6423SLionel Sambuc if (written < 0) return -1; 492*433d6423SLionel Sambuc 493*433d6423SLionel Sambuc printf(" header %d bytes, data %d bytes.\n", strlen(header), written); 494*433d6423SLionel Sambuc return 0; 495*433d6423SLionel Sambuc } 496*433d6423SLionel Sambuc 497*433d6423SLionel Sambuc int write_outfile_cprof() 498*433d6423SLionel Sambuc { 499*433d6423SLionel Sambuc int towrite, written = 0; 500*433d6423SLionel Sambuc struct sprof_sample *sample; 501*433d6423SLionel Sambuc 502*433d6423SLionel Sambuc /* Write data. */ 503*433d6423SLionel Sambuc towrite = mem_used == -1 ? mem_size : mem_used; 504*433d6423SLionel Sambuc 505*433d6423SLionel Sambuc sample = (struct sprof_sample *) mem_ptr; 506*433d6423SLionel Sambuc while (towrite > 0) { 507*433d6423SLionel Sambuc unsigned bytes; 508*433d6423SLionel Sambuc char entry[12]; 509*433d6423SLionel Sambuc char * name; 510*433d6423SLionel Sambuc 511*433d6423SLionel Sambuc name = get_proc_name(sample->proc); 512*433d6423SLionel Sambuc if (!name) { 513*433d6423SLionel Sambuc add_proc((struct sprof_proc *)sample); 514*433d6423SLionel Sambuc bytes = sizeof(struct sprof_proc); 515*433d6423SLionel Sambuc towrite -= bytes; 516*433d6423SLionel Sambuc sample = (struct sprof_sample *)(((char *) sample) + bytes); 517*433d6423SLionel Sambuc continue; 518*433d6423SLionel Sambuc } 519*433d6423SLionel Sambuc 520*433d6423SLionel Sambuc memset(entry, 0, 12); 521*433d6423SLionel Sambuc memcpy(entry, name, strlen(name)); 522*433d6423SLionel Sambuc memcpy(entry + 8, &sample->pc, 4); 523*433d6423SLionel Sambuc 524*433d6423SLionel Sambuc if (write(outfile_fd, entry, 12) != 12) { 525*433d6423SLionel Sambuc fprintf(stderr, "Error writing to outfile %s.\n", outfile); 526*433d6423SLionel Sambuc return -1; 527*433d6423SLionel Sambuc } 528*433d6423SLionel Sambuc towrite -= sizeof(struct sprof_sample); 529*433d6423SLionel Sambuc sample++; 530*433d6423SLionel Sambuc 531*433d6423SLionel Sambuc written += 12; 532*433d6423SLionel Sambuc } 533*433d6423SLionel Sambuc 534*433d6423SLionel Sambuc return written; 535*433d6423SLionel Sambuc } 536*433d6423SLionel Sambuc 537*433d6423SLionel Sambuc int write_outfile_sprof() 538*433d6423SLionel Sambuc { 539*433d6423SLionel Sambuc int towrite; 540*433d6423SLionel Sambuc ssize_t written, written_total = 0; 541*433d6423SLionel Sambuc 542*433d6423SLionel Sambuc /* write profiling totals */ 543*433d6423SLionel Sambuc written = write(outfile_fd, &sprof_info, sizeof(sprof_info)); 544*433d6423SLionel Sambuc if (written != sizeof(sprof_info)) goto error; 545*433d6423SLionel Sambuc written_total += written; 546*433d6423SLionel Sambuc 547*433d6423SLionel Sambuc /* write raw samples */ 548*433d6423SLionel Sambuc towrite = mem_used == -1 ? mem_size : mem_used; 549*433d6423SLionel Sambuc written = write(outfile_fd, mem_ptr, towrite); 550*433d6423SLionel Sambuc if (written != towrite) goto error; 551*433d6423SLionel Sambuc written_total += written; 552*433d6423SLionel Sambuc 553*433d6423SLionel Sambuc return written_total; 554*433d6423SLionel Sambuc 555*433d6423SLionel Sambuc error: 556*433d6423SLionel Sambuc fprintf(stderr, "Error writing to outfile %s.\n", outfile); 557*433d6423SLionel Sambuc return -1; 558*433d6423SLionel Sambuc } 559