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