1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
/*
* This file contains several functions and variables used for statistical
* system profiling, in particular the interrupt handler for profiling clock.
*
* Changes:
* 14 Aug, 2006 Created, (Rogier Meurs)
*/
#include "kernel/kernel.h"
#if SPROFILE
#include <string.h>
#include "watchdog.h"
char sprof_sample_buffer[SAMPLE_BUFFER_SIZE];
/* Function prototype for the profiling clock handler. */
static int profile_clock_handler(irq_hook_t *hook);
/* A hook for the profiling clock interrupt handler. */
static irq_hook_t profile_clock_hook;
/*===========================================================================*
* init_profile_clock *
*===========================================================================*/
void init_profile_clock(u32_t freq)
{
int irq;
if((irq = arch_init_profile_clock(freq)) >= 0) {
/* Register interrupt handler for statistical system profiling. */
profile_clock_hook.proc_nr_e = CLOCK;
put_irq_handler(&profile_clock_hook, irq, profile_clock_handler);
enable_irq(&profile_clock_hook);
}
}
/*===========================================================================*
* profile_clock_stop *
*===========================================================================*/
void stop_profile_clock(void)
{
arch_stop_profile_clock();
/* Unregister interrupt handler. */
disable_irq(&profile_clock_hook);
rm_irq_handler(&profile_clock_hook);
}
static void sprof_save_sample(struct proc * p, void * pc)
{
struct sprof_sample *s;
s = (struct sprof_sample *) (sprof_sample_buffer + sprof_info.mem_used);
s->proc = p->p_endpoint;
s->pc = pc;
sprof_info.mem_used += sizeof(struct sprof_sample);
}
static void sprof_save_proc(struct proc * p)
{
struct sprof_proc * s;
s = (struct sprof_proc *) (sprof_sample_buffer + sprof_info.mem_used);
s->proc = p->p_endpoint;
strcpy(s->name, p->p_name);
sprof_info.mem_used += sizeof(struct sprof_proc);
}
static void profile_sample(struct proc * p, void * pc)
{
/* This executes on every tick of the CMOS timer. */
/* Are we profiling, and profiling memory not full? */
if (!sprofiling || sprof_info.mem_used == -1)
return;
/* Check if enough memory available before writing sample. */
if (sprof_info.mem_used + sizeof(sprof_info) +
2*sizeof(struct sprof_sample) +
2*sizeof(struct sprof_sample) > sprof_mem_size) {
sprof_info.mem_used = -1;
return;
}
/* Runnable system process? */
if (p->p_endpoint == IDLE)
sprof_info.idle_samples++;
else if (p->p_endpoint == KERNEL ||
(priv(p)->s_flags & SYS_PROC && proc_is_runnable(p))) {
if (!(p->p_misc_flags & MF_SPROF_SEEN)) {
p->p_misc_flags |= MF_SPROF_SEEN;
sprof_save_proc(p);
}
sprof_save_sample(p, pc);
sprof_info.system_samples++;
} else {
/* User process. */
sprof_info.user_samples++;
}
sprof_info.total_samples++;
}
/*===========================================================================*
* profile_clock_handler *
*===========================================================================*/
static int profile_clock_handler(irq_hook_t *hook)
{
struct proc * p;
p = get_cpulocal_var(proc_ptr);
profile_sample(p, (void *) p->p_reg.pc);
/* Acknowledge interrupt if necessary. */
arch_ack_profile_clock();
return(1); /* reenable interrupts */
}
void nmi_sprofile_handler(struct nmi_frame * frame)
{
struct proc * p = get_cpulocal_var(proc_ptr);
/*
* test if the kernel was interrupted. If so, save first a sample fo
* kernel and than for the current process, otherwise save just the
* process
*/
if (nmi_in_kernel(frame)) {
struct proc *kern;
/*
* if we sample kernel, check if IDLE is scheduled. If so,
* account for idle time rather than taking kernel sample
*/
if (p->p_endpoint == IDLE) {
sprof_info.idle_samples++;
sprof_info.total_samples++;
return;
}
kern = proc_addr(KERNEL);
profile_sample(kern, (void *) frame->pc);
}
else
profile_sample(p, (void *) frame->pc);
}
#endif /* SPROFILE */
|