1 /* 2 * This file contains several functions and variables used for statistical 3 * system profiling, in particular the interrupt handler for profiling clock. 4 * 5 * Changes: 6 * 14 Aug, 2006 Created, (Rogier Meurs) 7 */ 8 9 #include <minix/config.h> 10 11 #include "kernel/kernel.h" 12 13 #include <minix/profile.h> 14 #include <minix/portio.h> 15 16 #if SPROFILE 17 18 #include <string.h> 19 #include "watchdog.h" 20 21 char sprof_sample_buffer[SAMPLE_BUFFER_SIZE]; 22 23 /* Function prototype for the profiling clock handler. */ 24 static int profile_clock_handler(irq_hook_t *hook); 25 26 /* A hook for the profiling clock interrupt handler. */ 27 static irq_hook_t profile_clock_hook; 28 29 /*===========================================================================* 30 * init_profile_clock * 31 *===========================================================================*/ 32 void init_profile_clock(u32_t freq) 33 { 34 int irq; 35 36 if((irq = arch_init_profile_clock(freq)) >= 0) { 37 /* Register interrupt handler for statistical system profiling. */ 38 profile_clock_hook.proc_nr_e = CLOCK; 39 put_irq_handler(&profile_clock_hook, irq, profile_clock_handler); 40 enable_irq(&profile_clock_hook); 41 } 42 } 43 44 /*===========================================================================* 45 * profile_clock_stop * 46 *===========================================================================*/ 47 void stop_profile_clock(void) 48 { 49 arch_stop_profile_clock(); 50 51 /* Unregister interrupt handler. */ 52 disable_irq(&profile_clock_hook); 53 rm_irq_handler(&profile_clock_hook); 54 } 55 56 static void sprof_save_sample(struct proc * p, void * pc) 57 { 58 struct sprof_sample *s; 59 60 s = (struct sprof_sample *) (sprof_sample_buffer + sprof_info.mem_used); 61 62 s->proc = p->p_endpoint; 63 s->pc = pc; 64 65 sprof_info.mem_used += sizeof(struct sprof_sample); 66 } 67 68 static void sprof_save_proc(struct proc * p) 69 { 70 struct sprof_proc * s; 71 72 s = (struct sprof_proc *) (sprof_sample_buffer + sprof_info.mem_used); 73 74 s->proc = p->p_endpoint; 75 strcpy(s->name, p->p_name); 76 77 sprof_info.mem_used += sizeof(struct sprof_proc); 78 } 79 80 static void profile_sample(struct proc * p, void * pc) 81 { 82 /* This executes on every tick of the CMOS timer. */ 83 84 /* Are we profiling, and profiling memory not full? */ 85 if (!sprofiling || sprof_info.mem_used == -1) 86 return; 87 88 /* Check if enough memory available before writing sample. */ 89 if (sprof_info.mem_used + sizeof(sprof_info) + 90 2*sizeof(struct sprof_sample) + 91 2*sizeof(struct sprof_sample) > sprof_mem_size) { 92 sprof_info.mem_used = -1; 93 return; 94 } 95 96 /* Runnable system process? */ 97 if (p->p_endpoint == IDLE) 98 sprof_info.idle_samples++; 99 else if (p->p_endpoint == KERNEL || 100 (priv(p)->s_flags & SYS_PROC && proc_is_runnable(p))) { 101 102 if (!(p->p_misc_flags & MF_SPROF_SEEN)) { 103 p->p_misc_flags |= MF_SPROF_SEEN; 104 sprof_save_proc(p); 105 } 106 107 sprof_save_sample(p, pc); 108 sprof_info.system_samples++; 109 } else { 110 /* User process. */ 111 sprof_info.user_samples++; 112 } 113 114 sprof_info.total_samples++; 115 } 116 117 /*===========================================================================* 118 * profile_clock_handler * 119 *===========================================================================*/ 120 static int profile_clock_handler(irq_hook_t *hook) 121 { 122 struct proc * p; 123 p = get_cpulocal_var(proc_ptr); 124 125 profile_sample(p, (void *) p->p_reg.pc); 126 127 /* Acknowledge interrupt if necessary. */ 128 arch_ack_profile_clock(); 129 130 return(1); /* reenable interrupts */ 131 } 132 133 void nmi_sprofile_handler(struct nmi_frame * frame) 134 { 135 struct proc * p = get_cpulocal_var(proc_ptr); 136 /* 137 * test if the kernel was interrupted. If so, save first a sample fo 138 * kernel and than for the current process, otherwise save just the 139 * process 140 */ 141 if (nmi_in_kernel(frame)) { 142 struct proc *kern; 143 144 /* 145 * if we sample kernel, check if IDLE is scheduled. If so, 146 * account for idle time rather than taking kernel sample 147 */ 148 if (p->p_endpoint == IDLE) { 149 sprof_info.idle_samples++; 150 sprof_info.total_samples++; 151 return; 152 } 153 154 kern = proc_addr(KERNEL); 155 156 profile_sample(kern, (void *) frame->pc); 157 } 158 else 159 profile_sample(p, (void *) frame->pc); 160 } 161 162 #endif /* SPROFILE */ 163