From db12229ce307900e3dbaf8384d68e50dc6e06635 Mon Sep 17 00:00:00 2001 From: Tomas Hruby Date: Thu, 23 Sep 2010 10:49:39 +0000 Subject: [PATCH] New profile protocol - when kernel profiles a process for the first time it saves an entry describing the process [endpoint|name] - every profile sample is only [endpoint|pc] - profile utility creates a table of endpoint <-> name relations and translates endpoints of samples into names and writing out the results to comply with the processing tools - "task" endpoints like KERNEL are negative thus we must cast it to unsigned when hashing --- commands/profile/profile.c | 72 +++++++++++++++++++++++++++++----- commands/profile/sprofalyze.pl | 1 - include/minix/profile.h | 14 +++++-- kernel/proc.h | 1 + kernel/profile.c | 60 ++++++++++++++++++---------- kernel/system/do_sprofile.c | 12 ++++++ 6 files changed, 124 insertions(+), 36 deletions(-) diff --git a/commands/profile/profile.c b/commands/profile/profile.c index a91538b5a..fe95fb352 100644 --- a/commands/profile/profile.c +++ b/commands/profile/profile.c @@ -54,6 +54,15 @@ int outfile_fd, npipe_fd; struct sprof_info_s sprof_info; struct cprof_info_s cprof_info; +#define HASH_MOD 128 +struct sproc { + endpoint_t ep; + char name[8]; + struct sproc * next; +}; + +static struct sproc * proc_hash[HASH_MOD]; + _PROTOTYPE(int handle_args, (int argc, char *argv[])); _PROTOTYPE(int start, (void)); _PROTOTYPE(int stop, (void)); @@ -186,7 +195,7 @@ int handle_args(int argc, char *argv[]) mem_size *= MB; /* mem_size in bytes */ } if (action == START) { - mem_size -= mem_size % sizeof(sprof_sample); /* align to sample size */ + mem_size -= mem_size % sizeof(struct sprof_sample); /* align to sample size */ if (freq == 0) freq = DEF_FREQ; /* default frequency */ } return 0; @@ -398,12 +407,38 @@ int detach() close(2); } +static void add_proc(struct sprof_proc * p) +{ + struct sproc * n; + int slot = ((unsigned)(p->proc)) % HASH_MOD; + + n = malloc(sizeof(struct sproc)); + if (!n) + abort(); + n->ep = p->proc; + memcpy(n->name, p->name, 8); + n->next = proc_hash[slot]; + proc_hash[slot] = n; +} + +static char * get_proc_name(endpoint_t ep) +{ + struct sproc * p; + + for (p = proc_hash[((unsigned)ep) % HASH_MOD]; p; p = p->next) { + if (p->ep == ep) + return p->name; + } + + return NULL; +} int write_outfile() { int n, towrite, written = 0; char *buf = mem_ptr; char header[80]; + struct sprof_sample *sample; printf("Writing to %s ...", outfile); @@ -424,16 +459,33 @@ int write_outfile() /* Write data. */ towrite = mem_used == -1 ? mem_size : mem_used; + sample = (struct sprof_sample *) mem_ptr; 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; + unsigned bytes; + char entry[12]; + char * name; + + name = get_proc_name(sample->proc); + if (!name) { + add_proc((struct sprof_proc *)sample); + bytes = sizeof(struct sprof_proc); + towrite -= bytes; + sample = (struct sprof_sample *)(((char *) sample) + bytes); + continue; + } + + memset(entry, 0, 12); + memcpy(entry, name, strlen(name)); + memcpy(entry + 8, &sample->pc, 4); + + if (write(outfile_fd, entry, 12) != 12) { + printf("Error writing to outfile %s.\n", outfile); + return 1; + } + towrite -= sizeof(struct sprof_sample); + sample++; + + written += 12; } printf(" header %d bytes, data %d bytes.\n", strlen(header), written); diff --git a/commands/profile/sprofalyze.pl b/commands/profile/sprofalyze.pl index f0dec85ee..a8861a77c 100755 --- a/commands/profile/sprofalyze.pl +++ b/commands/profile/sprofalyze.pl @@ -42,7 +42,6 @@ servers/sched/sched commands/service/service drivers/ahci/ahci -drivers/acpi/acpi drivers/amddev/amddev drivers/at_wini/at_wini drivers/atl2/atl2 diff --git a/include/minix/profile.h b/include/minix/profile.h index afeeec298..d78d1ec04 100644 --- a/include/minix/profile.h +++ b/include/minix/profile.h @@ -2,6 +2,7 @@ #define _PROFILE_H #include +#include /* * Types relating to system profiling. Types are supplied for both @@ -23,10 +24,15 @@ struct sprof_info_s { } sprof_info_inst; /* What a profiling sample looks like (used for sizeof()). */ -struct { - char name[8]; - int pc; -} sprof_sample; +struct sprof_sample { + endpoint_t proc; + void * pc; +}; + +struct sprof_proc { + endpoint_t proc; + char name[8]; +}i; #endif /* SPROFILE */ diff --git a/kernel/proc.h b/kernel/proc.h index d934674b8..3055a0821 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -241,6 +241,7 @@ struct proc { * regs are significant (initialized)*/ #define MF_SENDING_FROM_KERNEL 0x2000 /* message of this process is from kernel */ #define MF_CONTEXT_SET 0x4000 /* don't touch context */ +#define MF_SPROF_SEEN 0x8000 /* profiling has seen this process */ /* Magic process table addresses. */ #define BEG_PROC_ADDR (&proc[0]) diff --git a/kernel/profile.c b/kernel/profile.c index 070ed49a2..c1c3c653a 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -60,6 +60,36 @@ PUBLIC void stop_profile_clock() rm_irq_handler(&profile_clock_hook); } +PRIVATE sprof_save_sample(struct proc * p) +{ + struct sprof_sample s; + + s.proc = p->p_endpoint; + s.pc = (void *) p->p_reg.pc; + + /* Store sample (process name and program counter). */ + data_copy(KERNEL, (vir_bytes) &s, + sprof_ep, sprof_data_addr_vir + sprof_info.mem_used, + sizeof(s)); + + sprof_info.mem_used += sizeof(s); +} + +PRIVATE sprof_save_proc(struct proc * p) +{ + struct sprof_proc s; + + s.proc = p->p_endpoint; + memcpy(s.name, p->p_name, P_NAME_LEN); + + /* Store sample (process name and program counter). */ + data_copy(KERNEL, (vir_bytes) &s, + sprof_ep, sprof_data_addr_vir + sprof_info.mem_used, + sizeof(s)); + + sprof_info.mem_used += sizeof(s); +} + /*===========================================================================* * profile_clock_handler * *===========================================================================*/ @@ -79,29 +109,17 @@ PRIVATE int profile_clock_handler(irq_hook_t *hook) p = get_cpulocal_var(proc_ptr); - /* All is OK */ + if (!(p->p_misc_flags & MF_SPROF_SEEN)) { + p->p_misc_flags |= MF_SPROF_SEEN; + sprof_save_proc(p); + } - /* Idle process? */ - if (priv(p)->s_proc_nr == IDLE) { - sprof_info.idle_samples++; - } else /* Runnable system process? */ - if (priv(p)->s_flags & SYS_PROC && proc_is_runnable(p)) { - /* Note: k_reenter is always 0 here. */ - - /* Store sample (process name and program counter). */ - data_copy(KERNEL, (vir_bytes) p->p_name, - sprof_ep, sprof_data_addr_vir + sprof_info.mem_used, - strlen(p->p_name)); - - data_copy(KERNEL, (vir_bytes) &p->p_reg.pc, sprof_ep, - (vir_bytes) (sprof_data_addr_vir + sprof_info.mem_used + - sizeof(p->p_name)), - (vir_bytes) sizeof(p->p_reg.pc)); - - sprof_info.mem_used += sizeof(sprof_sample); - - sprof_info.system_samples++; + if (p->p_endpoint == IDLE) + sprof_info.idle_samples++; + else if (priv(p)->s_flags & SYS_PROC && proc_is_runnable(p)) { + sprof_save_sample(p); + sprof_info.system_samples++; } else { /* User process. */ sprof_info.user_samples++; diff --git a/kernel/system/do_sprofile.c b/kernel/system/do_sprofile.c index 629ee1dff..92a8b1518 100644 --- a/kernel/system/do_sprofile.c +++ b/kernel/system/do_sprofile.c @@ -20,6 +20,14 @@ /* user address to write info struct */ PRIVATE vir_bytes sprof_info_addr_vir; +PRIVATE clean_seen_flag(void) +{ + int i; + + for (i = 0; i < NR_TASKS + NR_PROCS; i++) + proc[i].p_misc_flags &= ~MF_SPROF_SEEN; +} + /*===========================================================================* * do_sprofile * *===========================================================================*/ @@ -62,6 +70,8 @@ PUBLIC int do_sprofile(struct proc * caller, message * m_ptr) sprofiling = 1; + clean_seen_flag(); + return OK; case PROF_STOP: @@ -82,6 +92,8 @@ PUBLIC int do_sprofile(struct proc * caller, message * m_ptr) data_copy(KERNEL, (vir_bytes) &sprof_info, sprof_ep, sprof_info_addr_vir, sizeof(sprof_info)); + clean_seen_flag(); + return OK; default: -- 2.44.0