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