xref: /minix3/minix/kernel/profile.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1 /*
2  * This file contains several functions and variables used for system
3  * profiling.
4  *
5  * Statistical Profiling:
6  *   The interrupt handler for profiling clock.
7  *
8  * Call Profiling:
9  *   The table used for profiling data and a function to get its size.
10  *
11  *   The function used by kernelspace processes to register the locations
12  *   of their control struct and profiling table.
13  *
14  * Changes:
15  *   14 Aug, 2006   Created, (Rogier Meurs)
16  */
17 
18 #include <minix/config.h>
19 
20 #include "kernel/kernel.h"
21 
22 #include <minix/profile.h>
23 #include <minix/portio.h>
24 
25 #if SPROFILE
26 
27 #include <string.h>
28 #include "watchdog.h"
29 
30 char sprof_sample_buffer[SAMPLE_BUFFER_SIZE];
31 
32 /* Function prototype for the profiling clock handler. */
33 static int profile_clock_handler(irq_hook_t *hook);
34 
35 /* A hook for the profiling clock interrupt handler. */
36 static irq_hook_t profile_clock_hook;
37 
38 /*===========================================================================*
39  *			init_profile_clock				     *
40  *===========================================================================*/
41 void init_profile_clock(u32_t freq)
42 {
43   int irq;
44 
45   if((irq = arch_init_profile_clock(freq)) >= 0) {
46 	/* Register interrupt handler for statistical system profiling.  */
47 	profile_clock_hook.proc_nr_e = CLOCK;
48 	put_irq_handler(&profile_clock_hook, irq, profile_clock_handler);
49 	enable_irq(&profile_clock_hook);
50   }
51 }
52 
53 /*===========================================================================*
54  *			profile_clock_stop				     *
55  *===========================================================================*/
56 void stop_profile_clock()
57 {
58   arch_stop_profile_clock();
59 
60   /* Unregister interrupt handler. */
61   disable_irq(&profile_clock_hook);
62   rm_irq_handler(&profile_clock_hook);
63 }
64 
65 static void sprof_save_sample(struct proc * p, void * pc)
66 {
67 	struct sprof_sample *s;
68 
69 	s = (struct sprof_sample *) (sprof_sample_buffer + sprof_info.mem_used);
70 
71 	s->proc = p->p_endpoint;
72 	s->pc = pc;
73 
74 	sprof_info.mem_used += sizeof(struct sprof_sample);
75 }
76 
77 static void sprof_save_proc(struct proc * p)
78 {
79 	struct sprof_proc * s;
80 
81 	s = (struct sprof_proc *) (sprof_sample_buffer + sprof_info.mem_used);
82 
83 	s->proc = p->p_endpoint;
84 	strcpy(s->name, p->p_name);
85 
86 	sprof_info.mem_used += sizeof(struct sprof_proc);
87 }
88 
89 static void profile_sample(struct proc * p, void * pc)
90 {
91 /* This executes on every tick of the CMOS timer. */
92 
93   /* Are we profiling, and profiling memory not full? */
94   if (!sprofiling || sprof_info.mem_used == -1)
95 	  return;
96 
97   /* Check if enough memory available before writing sample. */
98   if (sprof_info.mem_used + sizeof(sprof_info) +
99 		  2*sizeof(struct sprof_sample) +
100 		  2*sizeof(struct sprof_sample) > sprof_mem_size) {
101 	sprof_info.mem_used = -1;
102 	return;
103   }
104 
105   /* Runnable system process? */
106   if (p->p_endpoint == IDLE)
107 	sprof_info.idle_samples++;
108   else if (p->p_endpoint == KERNEL ||
109 		(priv(p)->s_flags & SYS_PROC && proc_is_runnable(p))) {
110 
111 	if (!(p->p_misc_flags & MF_SPROF_SEEN)) {
112 		p->p_misc_flags |= MF_SPROF_SEEN;
113 		sprof_save_proc(p);
114 	}
115 
116 	sprof_save_sample(p, pc);
117 	sprof_info.system_samples++;
118   } else {
119 	/* User process. */
120 	sprof_info.user_samples++;
121   }
122 
123   sprof_info.total_samples++;
124 }
125 
126 /*===========================================================================*
127  *			profile_clock_handler                           *
128  *===========================================================================*/
129 static int profile_clock_handler(irq_hook_t *hook)
130 {
131   struct proc * p;
132   p = get_cpulocal_var(proc_ptr);
133 
134   profile_sample(p, (void *) p->p_reg.pc);
135 
136   /* Acknowledge interrupt if necessary. */
137   arch_ack_profile_clock();
138 
139   return(1);                                    /* reenable interrupts */
140 }
141 
142 void nmi_sprofile_handler(struct nmi_frame * frame)
143 {
144 	struct proc * p = get_cpulocal_var(proc_ptr);
145 	/*
146 	 * test if the kernel was interrupted. If so, save first a sample fo
147 	 * kernel and than for the current process, otherwise save just the
148 	 * process
149 	 */
150 	if (nmi_in_kernel(frame)) {
151 		struct proc *kern;
152 
153 		/*
154 		 * if we sample kernel, check if IDLE is scheduled. If so,
155 		 * account for idle time rather than taking kernel sample
156 		 */
157 		if (p->p_endpoint == IDLE) {
158 			sprof_info.idle_samples++;
159 			sprof_info.total_samples++;
160 			return;
161 		}
162 
163 		kern = proc_addr(KERNEL);
164 
165 		profile_sample(kern, (void *) frame->pc);
166 	}
167 	else
168 		profile_sample(p, (void *) frame->pc);
169 }
170 
171 #endif /* SPROFILE */
172 
173 #if CPROFILE
174 /*
175  * The following variables and functions are used by the procentry/
176  * procentry syslib functions when linked with kernelspace processes.
177  * For userspace processes, the same variables and function are defined
178  * elsewhere. This enables different functionality and variable sizes,
179  * which is needed is a few cases.
180  */
181 
182 /* A small table is declared for the kernelspace processes. */
183 struct cprof_tbl_s cprof_tbl[CPROF_TABLE_SIZE_KERNEL];
184 
185 /* Function that returns table size. */
186 int profile_get_tbl_size(void)
187 {
188   return CPROF_TABLE_SIZE_KERNEL;
189 }
190 
191 /* Function that returns on which execution of procentry to announce. */
192 int profile_get_announce(void)
193 {
194   return CPROF_ACCOUNCE_KERNEL;
195 }
196 
197 /*
198  * The kernel "announces" its control struct and table locations
199  * to itself through this function.
200  */
201 void profile_register(ctl_ptr, tbl_ptr)
202 void *ctl_ptr;
203 void *tbl_ptr;
204 {
205   int proc_nr;
206   vir_bytes vir_dst;
207   struct proc *rp;
208 
209   if(cprof_procs_no >= NR_SYS_PROCS)
210 	return;
211 
212   /* Store process name, control struct, table locations. */
213   rp = proc_addr(SYSTEM);
214 
215   cprof_proc_info[cprof_procs_no].endpt = rp->p_endpoint;
216   cprof_proc_info[cprof_procs_no].name = rp->p_name;
217   cprof_proc_info[cprof_procs_no].ctl_v = (vir_bytes) ctl_ptr;
218   cprof_proc_info[cprof_procs_no].buf_v = (vir_bytes) tbl_ptr;
219 
220   cprof_procs_no++;
221 }
222 
223 #endif
224