OSDN Git Service

gcc/ada/
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-stausa.ads
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS               --
4 --                                                                          --
5 --                   S Y S T E M - S T A C K _ U S A G E                    --
6 --                                                                          --
7 --                                 S p e c                                  --
8 --                                                                          --
9 --         Copyright (C) 2004-2008, Free Software Foundation, Inc.          --
10 --                                                                          --
11 -- GNARL is free software; you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNARL; see file COPYING.  If not, write --
19 -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20 -- Boston, MA 02110-1301, USA.                                              --
21 --                                                                          --
22 -- As a special exception,  if other files  instantiate  generics from this --
23 -- unit, or you link  this unit with other files  to produce an executable, --
24 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
25 -- covered  by the  GNU  General  Public  License.  This exception does not --
26 -- however invalidate  any other reasons why  the executable file  might be --
27 -- covered by the  GNU Public License.                                      --
28 --                                                                          --
29 -- GNARL was developed by the GNARL team at Florida State University.       --
30 -- Extensive contributions were provided by Ada Core Technologies, Inc.     --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 with System;
35 with System.Storage_Elements;
36 with System.Address_To_Access_Conversions;
37 with Interfaces;
38
39 package System.Stack_Usage is
40    pragma Preelaborate;
41
42    package SSE renames System.Storage_Elements;
43
44    subtype Stack_Address is SSE.Integer_Address;
45    --  Address on the stack
46
47    function To_Stack_Address
48      (Value : System.Address) return Stack_Address
49       renames System.Storage_Elements.To_Integer;
50
51    type Stack_Analyzer is private;
52    --  Type of the stack analyzer tool. It is used to fill a portion of the
53    --  stack with Pattern, and to compute the stack used after some execution.
54
55    --  Usage:
56
57    --  A typical use of the package is something like:
58
59    --  A : Stack_Analyzer;
60
61    --  task T is
62    --     pragma Storage_Size (A_Storage_Size);
63    --  end T;
64
65    --  [...]
66
67    --     Bottom_Of_Stack : aliased Integer;
68    --     --  Bottom_Of_Stack'Address will be used as an approximation of
69    --     --  the bottom of stack. A good practise is to avoid allocating
70    --     --  other local variables on this stack, as it would degrade
71    --     --  the quality of this approximation.
72
73    --  begin
74    --     Initialize_Analyzer (A,
75    --                          "Task t",
76    --                          A_Storage_Size - A_Guard,
77    --                          A_Guard
78    --                          To_Stack_Address (Bottom_Of_Stack'Address));
79    --     Fill_Stack (A);
80    --     Some_User_Code;
81    --     Compute_Result (A);
82    --     Report_Result (A);
83    --  end T;
84
85    --  Errors:
86    --
87    --  We are instrumenting the code to measure the stack used by the user
88    --  code. This method has a number of systematic errors, but several methods
89    --  can be used to evaluate or reduce those errors. Here are those errors
90    --  and the strategy that we use to deal with them:
91
92    --  Bottom offset:
93
94    --     Description: The procedure used to fill the stack with a given
95    --       pattern will itself have a stack frame. The value of the stack
96    --       pointer in this procedure is, therefore, different from the value
97    --       before the call to the instrumentation procedure.
98
99    --     Strategy: The user of this package should measure the bottom of stack
100    --       before the call to Fill_Stack and pass it in parameter.
101
102    --  Instrumentation threshold at writing:
103
104    --     Description: The procedure used to fill the stack with a given
105    --       pattern will itself have a stack frame.  Therefore, it will
106    --       fill the stack after this stack frame. This part of the stack will
107    --       appear as used in the final measure.
108
109    --     Strategy: As the user passes the value of the bottom of stack to
110    --       the instrumentation to deal with the bottom offset error, and as
111    --       the instrumentation procedure knows where the pattern filling start
112    --       on the stack, the difference between the two values is the minimum
113    --       stack usage that the method can measure. If, when the results are
114    --       computed, the pattern zone has been left untouched, we conclude
115    --       that the stack usage is inferior to this minimum stack usage.
116
117    --  Instrumentation threshold at reading:
118
119    --    Description: The procedure used to read the stack at the end of the
120    --      execution clobbers the stack by allocating its stack frame. If this
121    --      stack frame is bigger than the total stack used by the user code at
122    --      this point, it will increase the measured stack size.
123
124    --    Strategy: We could augment this stack frame and see if it changes the
125    --      measure. However, this error should be negligible.
126
127    --   Pattern zone overflow:
128
129    --     Description: The stack grows outer than the topmost bound of the
130    --       pattern zone. In that case, the topmost region modified in the
131    --       pattern is not the maximum value of the stack pointer during the
132    --       execution.
133
134    --     Strategy: At the end of the execution, the difference between the
135    --       topmost memory region modified in the pattern zone and the
136    --       topmost bound of the pattern zone can be understood as the
137    --       biggest allocation that the method could have detect, provided
138    --       that there is no "Untouched allocated zone" error and no "Pattern
139    --       usage in user code" error. If no object in the user code is likely
140    --       to have this size, this is not likely to happen.
141
142    --   Pattern usage in user code:
143
144    --     Description: The pattern can be found in the object of the user code.
145    --       Therefore, the address space where this object has been allocated
146    --       will appear as untouched.
147
148    --     Strategy: Choose a pattern that is uncommon. 16#0000_0000# is the
149    --       worst choice; 16#DEAD_BEEF# can be a good one. A good choice is an
150    --       address which is not a multiple of 2, and which is not in the
151    --       target address space. You can also change the pattern to see if it
152    --       changes the measure. Note that this error *very* rarely influence
153    --       the measure of the total stack usage: to have some influence, the
154    --       pattern has to be used in the object that has been allocated on the
155    --       topmost address of the used stack.
156
157    --   Stack overflow:
158
159    --     Description: The pattern zone does not fit on the stack. This may
160    --       lead to an erroneous execution.
161
162    --     Strategy: Specify a storage size that is bigger than the size of the
163    --       pattern. 2 times bigger should be enough.
164
165    --   Augmentation of the user stack frames:
166
167    --     Description: The use of instrumentation object or procedure may
168    --       augment the stack frame of the caller.
169
170    --     Strategy: Do *not* inline the instrumentation procedures. Do *not*
171    --       allocate the Stack_Analyzer object on the stack.
172
173    --   Untouched allocated zone:
174
175    --     Description: The user code may allocate objects that it will never
176    --       touch. In that case, the pattern will not be changed.
177
178    --     Strategy: There are no way to detect this error. Fortunately, this
179    --       error is really rare, and it is most probably a bug in the user
180    --       code, e.g. some uninitialized variable. It is (most of the time)
181    --       harmless: it influences the measure only if the untouched allocated
182    --       zone happens to be located at the topmost value of the stack
183    --       pointer for the whole execution.
184
185    procedure Initialize (Buffer_Size : Natural);
186    pragma Export (C, Initialize, "__gnat_stack_usage_initialize");
187    --  Initializes the size of the buffer that stores the results. Only the
188    --  first Buffer_Size results are stored. Any results that do not fit in
189    --  this buffer will be displayed on the fly.
190
191    procedure Fill_Stack (Analyzer : in out Stack_Analyzer);
192    --  Fill an area of the stack with the pattern Analyzer.Pattern. The size
193    --  of this area is Analyzer.Size. After the call to this procedure,
194    --  the memory will look like that:
195    --
196    --                                                             Stack growing
197    --  ----------------------------------------------------------------------->
198    --  |<---------------------->|<----------------------------------->|
199    --  |  Stack frame           | Memory filled with Analyzer.Pattern |
200    --  |  of Fill_Stack         |                                     |
201    --  |  (deallocated at       |                                     |
202    --  |  the end of the call)  |                                     |
203    --  ^                        |                                     |
204    --  Analyzer.Bottom_Of_Stack ^                                     |
205    --                    Analyzer.Bottom_Pattern_Mark                 ^
206    --                                            Analyzer.Top_Pattern_Mark
207
208    procedure Initialize_Analyzer
209      (Analyzer         : in out Stack_Analyzer;
210       Task_Name        : String;
211       Stack_Size       : Natural;
212       Max_Pattern_Size : Natural;
213       Bottom           : Stack_Address;
214       Pattern          : Interfaces.Unsigned_32 := 16#DEAD_BEEF#);
215    --  Should be called before any use of a Stack_Analyzer, to initialize it.
216    --  Max_Pattern_Size is the size of the pattern zone, might be smaller than
217    --  the full stack size in order to take into account e.g. the secondary
218    --  stack and a guard against overflow. The actual size taken will be
219    --  readjusted with data already used at the time the stack is actually
220    --  filled.
221
222    Is_Enabled : Boolean := False;
223    --  When this flag is true, then stack analysis is enabled
224
225    procedure Compute_Result (Analyzer : in out Stack_Analyzer);
226    --  Read the pattern zone and deduce the stack usage. It should be called
227    --  from the same frame as Fill_Stack. If Analyzer.Probe is not null, an
228    --  array of Unsigned_32 with Analyzer.Probe elements is allocated on
229    --  Compute_Result's stack frame. Probe can be used to detect  the error:
230    --  "instrumentation threshold at reading". See above. After the call
231    --  to this procedure, the memory will look like:
232    --
233    --                                                             Stack growing
234    --  ----------------------------------------------------------------------->
235    --  |<---------------------->|<-------------->|<--------->|<--------->|
236    --  |  Stack frame           | Array of       | used      |  Memory   |
237    --  |  of Compute_Result     | Analyzer.Probe | during    |   filled  |
238    --  |  (deallocated at       | elements       |  the      |    with   |
239    --  |  the end of the call)  |                | execution |  pattern  |
240    --  |                        ^                |           |           |
241    --  |                   Bottom_Pattern_Mark   |           |           |
242    --  |                                                     |           |
243    --  |<---------------------------------------------------->           |
244    --                  Stack used                                        ^
245    --                                                     Top_Pattern_Mark
246
247    procedure Report_Result (Analyzer : Stack_Analyzer);
248    --  Store the results of the computation in memory, at the address
249    --  corresponding to the symbol __gnat_stack_usage_results. This is not
250    --  done inside Compute_Result in order to use as less stack as possible
251    --  within a task.
252
253    procedure Output_Results;
254    --  Print the results computed so far on the standard output. Should be
255    --  called when all tasks are dead.
256
257    pragma Export (C, Output_Results, "__gnat_stack_usage_output_results");
258
259 private
260
261    Task_Name_Length : constant := 32;
262    --  The maximum length of task name displayed.
263    --  ??? Consider merging this variable with Max_Task_Image_Length.
264
265    package Unsigned_32_Addr is
266      new System.Address_To_Access_Conversions (Interfaces.Unsigned_32);
267
268    subtype Pattern_Type is Interfaces.Unsigned_32;
269    Bytes_Per_Pattern : constant := Pattern_Type'Object_Size / Storage_Unit;
270
271    type Stack_Analyzer is record
272       Task_Name : String (1 .. Task_Name_Length);
273       --  Name of the task
274
275       Stack_Size : Natural;
276       --  Entire size of the analyzed stack
277
278       Pattern_Size : Natural;
279       --  Size of the pattern zone
280
281       Pattern : Pattern_Type;
282       --  Pattern used to recognize untouched memory
283
284       Bottom_Pattern_Mark : Stack_Address;
285       --  Bound of the pattern area on the stack closest to the bottom
286
287       Top_Pattern_Mark : Stack_Address;
288       --  Topmost bound of the pattern area on the stack
289
290       Topmost_Touched_Mark : Stack_Address;
291       --  Topmost address of the pattern area whose value it is pointing
292       --  at has been modified during execution. If the systematic error are
293       --  compensated, it is the topmost value of the stack pointer during
294       --  the execution.
295
296       Bottom_Of_Stack : Stack_Address;
297       --  Address of the bottom of the stack, as given by the caller of
298       --  Initialize_Analyzer.
299
300       Stack_Overlay_Address : System.Address;
301       --  Address of the stack abstraction object we overlay over a
302       --  task's real stack, typically a pattern-initialized array.
303
304       Result_Id : Positive;
305       --  Id of the result. If less than value given to gnatbind -u corresponds
306       --  to the location in the result array of result for the current task.
307    end record;
308
309    Environment_Task_Analyzer : Stack_Analyzer;
310
311    Compute_Environment_Task  : Boolean;
312
313    type Task_Result is record
314       Task_Name : String (1 .. Task_Name_Length);
315
316       Min_Measure : Natural;
317       --  Minimum value for the measure
318
319       Max_Measure : Natural;
320       --  Maximum value for the measure, taking into account the actual size
321       --  of the pattern filled.
322
323       Max_Size : Natural;
324    end record;
325
326    type Result_Array_Type is array (Positive range <>) of Task_Result;
327    type Result_Array_Ptr is access all Result_Array_Type;
328
329    Result_Array : Result_Array_Ptr;
330    pragma Export (C, Result_Array, "__gnat_stack_usage_results");
331    --  Exported in order to have an easy accessible symbol in when debugging
332
333    Next_Id : Positive := 1;
334    --  Id of the next stack analyzer
335
336    function Stack_Size
337      (SP_Low  : Stack_Address;
338       SP_High : Stack_Address) return Natural;
339    pragma Inline (Stack_Size);
340    --  Return the size of a portion of stack delimited by SP_High and SP_Low
341    --  (), i.e. the difference between SP_High and SP_Low. The storage element
342    --  pointed by SP_Low is not included in the size. Inlined to reduce the
343    --  size of the stack used by the instrumentation code.
344
345 end System.Stack_Usage;