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