]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/profile.cpp
update
[l4.git] / kernel / fiasco / src / kern / ia32 / profile.cpp
1 INTERFACE[profile]:
2
3 #include "types.h"
4
5 class Profile
6 {
7   static unsigned long ticks;
8   static bool exit;
9 };
10
11
12 INTERFACE[{ia32,amd64}-!profile]:
13
14 class Profile
15 {
16 };
17
18
19 IMPLEMENTATION[profile]:
20
21 #include <cstdlib>
22
23 #include "config.h"
24 #include "globals.h"
25 #include "gmon.h"
26 #include "idt.h"
27 #include "mem_layout.h"
28 #include "pic.h"
29 #include "pit.h"
30 #include "processor.h"
31 #include "unistd.h"             // pr_base, pr_off, pr_size, pr_scale
32 #include "thread.h"             // for stack checking
33
34 unsigned long Profile::ticks = 0;
35 bool          Profile::exit  = false;
36
37 static bool profile_active = false;
38
39 extern "C" void profile_interrupt_entry();
40
41 static void
42 dump_if_active()
43 {
44   if (profile_active)
45     _mcleanup();
46 }
47
48 // We assume that our member functions generally are called in cli
49 // mode.
50
51 // set up profiling and initialize profiling interrupt
52 PUBLIC static 
53 void
54 Profile::init()
55 {
56   atexit(dump_if_active);
57   Idt::set_entry (0x20 + Config::profile_irq,
58                   (unsigned) profile_interrupt_entry, false);
59 }
60
61 PUBLIC static 
62 void
63 Profile::start()
64 {
65   if (! profile_active)
66     {
67       monstartup((char*)&Mem_layout::start, (char*)&Mem_layout::end, 
68                  Config::profiling_rate);
69       profile_active = true;
70       Pit::init(Config::profiling_rate);
71       Pic::enable(Config::profile_irq);
72     }
73 }
74
75 PUBLIC static 
76 void
77 Profile::stop()
78 {
79   if (profile_active)
80     {
81       Pic::disable(Config::profile_irq);
82       moncontrol(0);
83       profile_active = false;
84     }
85 }
86
87 PUBLIC static 
88 void
89 Profile::stop_and_dump()
90 {
91   if (profile_active)
92     {
93       Pic::disable(Config::profile_irq);
94       _mcleanup();
95       profile_active = false;
96     }
97 }
98
99 // irq routine invoked by profile_interrupt_entry in entry.S
100
101 /*
102  * Scale is a fixed-point number with the binary point 16 bits
103  * into the value, and is <= 1.0.  pc is at most 32 bits, so the
104  * intermediate result is at most 48 bits.
105  */
106 #define PC_TO_INDEX(pc, off, scale)                             \
107         ((Address)(((unsigned long long)((pc) - (off)) *        \
108                 (unsigned long long)((scale))) >> 16) & ~1)
109
110 PUBLIC static inline NOEXPORT
111 void
112 Profile::handle_profile_interrupt(Address pc)
113 {
114   // runs with disabled irqs
115   Pic::disable_locked(Config::profile_irq);
116   Pic::acknowledge_locked(Config::profile_irq);
117   Pic::enable_locked(Config::profile_irq);
118
119   ticks++;
120
121   size_t i;
122
123   if (! pr_scale)
124     return;
125
126   if (pc < pr_off 
127       || (i = PC_TO_INDEX(pc, pr_off, pr_scale)) >= pr_size)
128     return;                     // out of range - ignore
129
130   *reinterpret_cast<unsigned short*>(pr_base + i) += 1;
131
132   if (exit)
133     ::exit(0);
134 }
135
136 extern "C" FIASCO_FASTCALL
137 void
138 profile_interrupt(Address pc)
139 {
140   Profile::handle_profile_interrupt(pc);
141 }
142
143 extern "C" 
144 void
145 profile_mcount_wrap(unsigned short *frompcindex, char *selfpc )
146 {
147   // For lack of a better place, so stack checking here:
148
149   static bool overrun = false;
150   if (! overrun)
151     {
152       Address sp = Proc::stack_pointer();
153       if (((Address)current()) + sizeof(Thread) + 0x20 > sp)
154         {
155           overrun = true;
156           panic("stack overrun: current=0x%x, esp=0x%x", 
157                 (Address)current(), sp);
158         }
159     }
160   
161   __mcount_internal (frompcindex, selfpc);
162 }
163
164 /* The GNU Glibc has this to say:
165
166    We need a special version of the `mcount' function since for ix86 it
167    must not clobber any register.  This has several reasons:
168      - there is a bug in gcc as of version 2.7.2.2 which prohibits the
169        use of profiling together with nested functions
170      - the ELF `fixup' function uses GCC's regparm feature
171      - some (future) systems might want to pass parameters in registers.  */
172
173 #define __STR(x) #x
174 #define STR(x) __STR(x)
175
176 asm(".p2align 4                 \n\t"
177     ".globl mcount              \n\t"
178 "mcount:                        \n\t"
179     "pushl %eax                 \n\t"
180     "pushl %ecx                 \n\t"
181     "pushl %edx                 \n\t"
182
183     "movl 12(%esp), %eax        \n\t"
184     "movl 4(%ebp), %ecx         \n\t"
185     "pushl %eax                 \n\t"
186     "pushl %ecx                 \n\t"
187
188     "call " STR(profile_mcount_wrap) "\n\t"
189     "addl $8,%esp               \n\t"
190
191     "popl %edx                  \n\t"
192     "popl %ecx                  \n\t"
193     "popl %eax                  \n\t"
194     "ret");
195
196
197 //---------------------------------------------------------------------------
198 IMPLEMENTATION[{ia32,amd64}-!profile]:
199
200 PUBLIC static inline void Profile::init() {}
201 PUBLIC static inline void Profile::start() {}
202 PUBLIC static inline void Profile::stop() {}
203 PUBLIC static inline void Profile::stop_and_dump() {}