xref: /minix3/minix/kernel/profile.c (revision 9624407e7addfd8b88486acfe3a0e056e2b92ee3)
1433d6423SLionel Sambuc /*
21dcfbcd1SDavid van Moolenbroek  * This file contains several functions and variables used for statistical
31dcfbcd1SDavid van Moolenbroek  * system profiling, in particular the interrupt handler for profiling clock.
4433d6423SLionel Sambuc  *
5433d6423SLionel Sambuc  * Changes:
6433d6423SLionel Sambuc  *   14 Aug, 2006   Created, (Rogier Meurs)
7433d6423SLionel Sambuc  */
8433d6423SLionel Sambuc 
9433d6423SLionel Sambuc #include "kernel/kernel.h"
10433d6423SLionel Sambuc 
11433d6423SLionel Sambuc #if SPROFILE
12433d6423SLionel Sambuc 
13433d6423SLionel Sambuc #include <string.h>
14433d6423SLionel Sambuc #include "watchdog.h"
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc char sprof_sample_buffer[SAMPLE_BUFFER_SIZE];
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc /* Function prototype for the profiling clock handler. */
19433d6423SLionel Sambuc static int profile_clock_handler(irq_hook_t *hook);
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc /* A hook for the profiling clock interrupt handler. */
22433d6423SLionel Sambuc static irq_hook_t profile_clock_hook;
23433d6423SLionel Sambuc 
24433d6423SLionel Sambuc /*===========================================================================*
25433d6423SLionel Sambuc  *			init_profile_clock				     *
26433d6423SLionel Sambuc  *===========================================================================*/
init_profile_clock(u32_t freq)27433d6423SLionel Sambuc void init_profile_clock(u32_t freq)
28433d6423SLionel Sambuc {
29433d6423SLionel Sambuc   int irq;
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc   if((irq = arch_init_profile_clock(freq)) >= 0) {
32433d6423SLionel Sambuc 	/* Register interrupt handler for statistical system profiling.  */
33433d6423SLionel Sambuc 	profile_clock_hook.proc_nr_e = CLOCK;
34433d6423SLionel Sambuc 	put_irq_handler(&profile_clock_hook, irq, profile_clock_handler);
35433d6423SLionel Sambuc 	enable_irq(&profile_clock_hook);
36433d6423SLionel Sambuc   }
37433d6423SLionel Sambuc }
38433d6423SLionel Sambuc 
39433d6423SLionel Sambuc /*===========================================================================*
40433d6423SLionel Sambuc  *			profile_clock_stop				     *
41433d6423SLionel Sambuc  *===========================================================================*/
stop_profile_clock(void)42*6077d1adSDr. Florian Grätz void stop_profile_clock(void)
43433d6423SLionel Sambuc {
44433d6423SLionel Sambuc   arch_stop_profile_clock();
45433d6423SLionel Sambuc 
46433d6423SLionel Sambuc   /* Unregister interrupt handler. */
47433d6423SLionel Sambuc   disable_irq(&profile_clock_hook);
48433d6423SLionel Sambuc   rm_irq_handler(&profile_clock_hook);
49433d6423SLionel Sambuc }
50433d6423SLionel Sambuc 
sprof_save_sample(struct proc * p,void * pc)51433d6423SLionel Sambuc static void sprof_save_sample(struct proc * p, void * pc)
52433d6423SLionel Sambuc {
53433d6423SLionel Sambuc 	struct sprof_sample *s;
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc 	s = (struct sprof_sample *) (sprof_sample_buffer + sprof_info.mem_used);
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc 	s->proc = p->p_endpoint;
58433d6423SLionel Sambuc 	s->pc = pc;
59433d6423SLionel Sambuc 
60433d6423SLionel Sambuc 	sprof_info.mem_used += sizeof(struct sprof_sample);
61433d6423SLionel Sambuc }
62433d6423SLionel Sambuc 
sprof_save_proc(struct proc * p)63433d6423SLionel Sambuc static void sprof_save_proc(struct proc * p)
64433d6423SLionel Sambuc {
65433d6423SLionel Sambuc 	struct sprof_proc * s;
66433d6423SLionel Sambuc 
67433d6423SLionel Sambuc 	s = (struct sprof_proc *) (sprof_sample_buffer + sprof_info.mem_used);
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc 	s->proc = p->p_endpoint;
70433d6423SLionel Sambuc 	strcpy(s->name, p->p_name);
71433d6423SLionel Sambuc 
72433d6423SLionel Sambuc 	sprof_info.mem_used += sizeof(struct sprof_proc);
73433d6423SLionel Sambuc }
74433d6423SLionel Sambuc 
profile_sample(struct proc * p,void * pc)75433d6423SLionel Sambuc static void profile_sample(struct proc * p, void * pc)
76433d6423SLionel Sambuc {
77433d6423SLionel Sambuc /* This executes on every tick of the CMOS timer. */
78433d6423SLionel Sambuc 
79433d6423SLionel Sambuc   /* Are we profiling, and profiling memory not full? */
80433d6423SLionel Sambuc   if (!sprofiling || sprof_info.mem_used == -1)
81433d6423SLionel Sambuc 	  return;
82433d6423SLionel Sambuc 
83433d6423SLionel Sambuc   /* Check if enough memory available before writing sample. */
84433d6423SLionel Sambuc   if (sprof_info.mem_used + sizeof(sprof_info) +
85433d6423SLionel Sambuc 		  2*sizeof(struct sprof_sample) +
86433d6423SLionel Sambuc 		  2*sizeof(struct sprof_sample) > sprof_mem_size) {
87433d6423SLionel Sambuc 	sprof_info.mem_used = -1;
88433d6423SLionel Sambuc 	return;
89433d6423SLionel Sambuc   }
90433d6423SLionel Sambuc 
91433d6423SLionel Sambuc   /* Runnable system process? */
92433d6423SLionel Sambuc   if (p->p_endpoint == IDLE)
93433d6423SLionel Sambuc 	sprof_info.idle_samples++;
94433d6423SLionel Sambuc   else if (p->p_endpoint == KERNEL ||
95433d6423SLionel Sambuc 		(priv(p)->s_flags & SYS_PROC && proc_is_runnable(p))) {
96433d6423SLionel Sambuc 
97433d6423SLionel Sambuc 	if (!(p->p_misc_flags & MF_SPROF_SEEN)) {
98433d6423SLionel Sambuc 		p->p_misc_flags |= MF_SPROF_SEEN;
99433d6423SLionel Sambuc 		sprof_save_proc(p);
100433d6423SLionel Sambuc 	}
101433d6423SLionel Sambuc 
102433d6423SLionel Sambuc 	sprof_save_sample(p, pc);
103433d6423SLionel Sambuc 	sprof_info.system_samples++;
104433d6423SLionel Sambuc   } else {
105433d6423SLionel Sambuc 	/* User process. */
106433d6423SLionel Sambuc 	sprof_info.user_samples++;
107433d6423SLionel Sambuc   }
108433d6423SLionel Sambuc 
109433d6423SLionel Sambuc   sprof_info.total_samples++;
110433d6423SLionel Sambuc }
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc /*===========================================================================*
113433d6423SLionel Sambuc  *			profile_clock_handler                           *
114433d6423SLionel Sambuc  *===========================================================================*/
profile_clock_handler(irq_hook_t * hook)115433d6423SLionel Sambuc static int profile_clock_handler(irq_hook_t *hook)
116433d6423SLionel Sambuc {
117433d6423SLionel Sambuc   struct proc * p;
118433d6423SLionel Sambuc   p = get_cpulocal_var(proc_ptr);
119433d6423SLionel Sambuc 
120433d6423SLionel Sambuc   profile_sample(p, (void *) p->p_reg.pc);
121433d6423SLionel Sambuc 
122433d6423SLionel Sambuc   /* Acknowledge interrupt if necessary. */
123433d6423SLionel Sambuc   arch_ack_profile_clock();
124433d6423SLionel Sambuc 
125433d6423SLionel Sambuc   return(1);                                    /* reenable interrupts */
126433d6423SLionel Sambuc }
127433d6423SLionel Sambuc 
nmi_sprofile_handler(struct nmi_frame * frame)128433d6423SLionel Sambuc void nmi_sprofile_handler(struct nmi_frame * frame)
129433d6423SLionel Sambuc {
130433d6423SLionel Sambuc 	struct proc * p = get_cpulocal_var(proc_ptr);
131433d6423SLionel Sambuc 	/*
132433d6423SLionel Sambuc 	 * test if the kernel was interrupted. If so, save first a sample fo
133433d6423SLionel Sambuc 	 * kernel and than for the current process, otherwise save just the
134433d6423SLionel Sambuc 	 * process
135433d6423SLionel Sambuc 	 */
136433d6423SLionel Sambuc 	if (nmi_in_kernel(frame)) {
137433d6423SLionel Sambuc 		struct proc *kern;
138433d6423SLionel Sambuc 
139433d6423SLionel Sambuc 		/*
140433d6423SLionel Sambuc 		 * if we sample kernel, check if IDLE is scheduled. If so,
141433d6423SLionel Sambuc 		 * account for idle time rather than taking kernel sample
142433d6423SLionel Sambuc 		 */
143433d6423SLionel Sambuc 		if (p->p_endpoint == IDLE) {
144433d6423SLionel Sambuc 			sprof_info.idle_samples++;
145433d6423SLionel Sambuc 			sprof_info.total_samples++;
146433d6423SLionel Sambuc 			return;
147433d6423SLionel Sambuc 		}
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc 		kern = proc_addr(KERNEL);
150433d6423SLionel Sambuc 
151433d6423SLionel Sambuc 		profile_sample(kern, (void *) frame->pc);
152433d6423SLionel Sambuc 	}
153433d6423SLionel Sambuc 	else
154433d6423SLionel Sambuc 		profile_sample(p, (void *) frame->pc);
155433d6423SLionel Sambuc }
156433d6423SLionel Sambuc 
157433d6423SLionel Sambuc #endif /* SPROFILE */
158