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
This commit is contained in:
parent
123a968be3
commit
db12229ce3
6 changed files with 121 additions and 33 deletions
|
@ -54,6 +54,15 @@ int outfile_fd, npipe_fd;
|
||||||
struct sprof_info_s sprof_info;
|
struct sprof_info_s sprof_info;
|
||||||
struct cprof_info_s cprof_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 handle_args, (int argc, char *argv[]));
|
||||||
_PROTOTYPE(int start, (void));
|
_PROTOTYPE(int start, (void));
|
||||||
_PROTOTYPE(int stop, (void));
|
_PROTOTYPE(int stop, (void));
|
||||||
|
@ -186,7 +195,7 @@ int handle_args(int argc, char *argv[])
|
||||||
mem_size *= MB; /* mem_size in bytes */
|
mem_size *= MB; /* mem_size in bytes */
|
||||||
}
|
}
|
||||||
if (action == START) {
|
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 */
|
if (freq == 0) freq = DEF_FREQ; /* default frequency */
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -398,12 +407,38 @@ int detach()
|
||||||
close(2);
|
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 write_outfile()
|
||||||
{
|
{
|
||||||
int n, towrite, written = 0;
|
int n, towrite, written = 0;
|
||||||
char *buf = mem_ptr;
|
char *buf = mem_ptr;
|
||||||
char header[80];
|
char header[80];
|
||||||
|
struct sprof_sample *sample;
|
||||||
|
|
||||||
printf("Writing to %s ...", outfile);
|
printf("Writing to %s ...", outfile);
|
||||||
|
|
||||||
|
@ -424,16 +459,33 @@ int write_outfile()
|
||||||
/* Write data. */
|
/* Write data. */
|
||||||
towrite = mem_used == -1 ? mem_size : mem_used;
|
towrite = mem_used == -1 ? mem_size : mem_used;
|
||||||
|
|
||||||
|
sample = (struct sprof_sample *) mem_ptr;
|
||||||
while (towrite > 0) {
|
while (towrite > 0) {
|
||||||
|
unsigned bytes;
|
||||||
|
char entry[12];
|
||||||
|
char * name;
|
||||||
|
|
||||||
n = write(outfile_fd, buf, towrite);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if (n < 0)
|
memset(entry, 0, 12);
|
||||||
{ printf("Error writing to outfile %s.\n", outfile); return 1; }
|
memcpy(entry, name, strlen(name));
|
||||||
|
memcpy(entry + 8, &sample->pc, 4);
|
||||||
|
|
||||||
towrite -= n;
|
if (write(outfile_fd, entry, 12) != 12) {
|
||||||
buf += n;
|
printf("Error writing to outfile %s.\n", outfile);
|
||||||
written += n;
|
return 1;
|
||||||
|
}
|
||||||
|
towrite -= sizeof(struct sprof_sample);
|
||||||
|
sample++;
|
||||||
|
|
||||||
|
written += 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" header %d bytes, data %d bytes.\n", strlen(header), written);
|
printf(" header %d bytes, data %d bytes.\n", strlen(header), written);
|
||||||
|
|
|
@ -42,7 +42,6 @@ servers/sched/sched
|
||||||
commands/service/service
|
commands/service/service
|
||||||
|
|
||||||
drivers/ahci/ahci
|
drivers/ahci/ahci
|
||||||
drivers/acpi/acpi
|
|
||||||
drivers/amddev/amddev
|
drivers/amddev/amddev
|
||||||
drivers/at_wini/at_wini
|
drivers/at_wini/at_wini
|
||||||
drivers/atl2/atl2
|
drivers/atl2/atl2
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define _PROFILE_H
|
#define _PROFILE_H
|
||||||
|
|
||||||
#include <ansi.h>
|
#include <ansi.h>
|
||||||
|
#include <minix/type.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Types relating to system profiling. Types are supplied for both
|
* Types relating to system profiling. Types are supplied for both
|
||||||
|
@ -23,10 +24,15 @@ struct sprof_info_s {
|
||||||
} sprof_info_inst;
|
} sprof_info_inst;
|
||||||
|
|
||||||
/* What a profiling sample looks like (used for sizeof()). */
|
/* What a profiling sample looks like (used for sizeof()). */
|
||||||
struct {
|
struct sprof_sample {
|
||||||
char name[8];
|
endpoint_t proc;
|
||||||
int pc;
|
void * pc;
|
||||||
} sprof_sample;
|
};
|
||||||
|
|
||||||
|
struct sprof_proc {
|
||||||
|
endpoint_t proc;
|
||||||
|
char name[8];
|
||||||
|
}i;
|
||||||
|
|
||||||
#endif /* SPROFILE */
|
#endif /* SPROFILE */
|
||||||
|
|
||||||
|
|
|
@ -241,6 +241,7 @@ struct proc {
|
||||||
* regs are significant (initialized)*/
|
* regs are significant (initialized)*/
|
||||||
#define MF_SENDING_FROM_KERNEL 0x2000 /* message of this process is from kernel */
|
#define MF_SENDING_FROM_KERNEL 0x2000 /* message of this process is from kernel */
|
||||||
#define MF_CONTEXT_SET 0x4000 /* don't touch context */
|
#define MF_CONTEXT_SET 0x4000 /* don't touch context */
|
||||||
|
#define MF_SPROF_SEEN 0x8000 /* profiling has seen this process */
|
||||||
|
|
||||||
/* Magic process table addresses. */
|
/* Magic process table addresses. */
|
||||||
#define BEG_PROC_ADDR (&proc[0])
|
#define BEG_PROC_ADDR (&proc[0])
|
||||||
|
|
|
@ -60,6 +60,36 @@ PUBLIC void stop_profile_clock()
|
||||||
rm_irq_handler(&profile_clock_hook);
|
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 *
|
* profile_clock_handler *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -79,29 +109,17 @@ PRIVATE int profile_clock_handler(irq_hook_t *hook)
|
||||||
|
|
||||||
p = get_cpulocal_var(proc_ptr);
|
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? */
|
/* Runnable system process? */
|
||||||
if (priv(p)->s_flags & SYS_PROC && proc_is_runnable(p)) {
|
if (p->p_endpoint == IDLE)
|
||||||
/* Note: k_reenter is always 0 here. */
|
sprof_info.idle_samples++;
|
||||||
|
else if (priv(p)->s_flags & SYS_PROC && proc_is_runnable(p)) {
|
||||||
/* Store sample (process name and program counter). */
|
sprof_save_sample(p);
|
||||||
data_copy(KERNEL, (vir_bytes) p->p_name,
|
sprof_info.system_samples++;
|
||||||
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++;
|
|
||||||
} else {
|
} else {
|
||||||
/* User process. */
|
/* User process. */
|
||||||
sprof_info.user_samples++;
|
sprof_info.user_samples++;
|
||||||
|
|
|
@ -20,6 +20,14 @@
|
||||||
/* user address to write info struct */
|
/* user address to write info struct */
|
||||||
PRIVATE vir_bytes sprof_info_addr_vir;
|
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 *
|
* do_sprofile *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -62,6 +70,8 @@ PUBLIC int do_sprofile(struct proc * caller, message * m_ptr)
|
||||||
|
|
||||||
sprofiling = 1;
|
sprofiling = 1;
|
||||||
|
|
||||||
|
clean_seen_flag();
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
case PROF_STOP:
|
case PROF_STOP:
|
||||||
|
@ -82,6 +92,8 @@ PUBLIC int do_sprofile(struct proc * caller, message * m_ptr)
|
||||||
data_copy(KERNEL, (vir_bytes) &sprof_info,
|
data_copy(KERNEL, (vir_bytes) &sprof_info,
|
||||||
sprof_ep, sprof_info_addr_vir, sizeof(sprof_info));
|
sprof_ep, sprof_info_addr_vir, sizeof(sprof_info));
|
||||||
|
|
||||||
|
clean_seen_flag();
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in a new issue