xref: /minix/minix/kernel/profile.c (revision 00b67f09)
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