OSDN Git Service

PR c++/27714
[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-2005, 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
38 package System.Stack_Usage is
39    pragma Preelaborate;
40
41    package SSE renames System.Storage_Elements;
42
43    Byte_Size : constant := 8;
44    Word_32_Size : constant := 4 * Byte_Size;
45
46    type Word_32 is mod 2 ** Word_32_Size;
47    for Word_32'Alignment use 4;
48
49    subtype Stack_Address is SSE.Integer_Address;
50    --  Address on the stack
51    --
52    --  Note: in this package, when comparing two addresses on the stack, the
53    --  comments use the terms "outer", "inner", "outermost" and "innermost"
54    --  instead of the ambigous "higher", "lower", "highest" and "lowest".
55    --  "inner" means "closer to the bottom of stack" and is the contrary of
56    --  "outer". "innermost" means "closest address to the bottom of stack". The
57    --  stack is growing from the inner to the outer.
58
59    --  Top/Bottom would be much better than inner and outer ???
60
61    function To_Stack_Address (Value : System.Address) return Stack_Address
62                               renames System.Storage_Elements.To_Integer;
63
64    type Stack_Analyzer is private;
65    --  Type of the stack analyzer tool. It is used to fill a portion of
66    --  the stack with Pattern, and to compute the stack used after some
67    --  execution.
68
69    --  Usage:
70
71    --  A typical use of the package is something like:
72
73    --  A : Stack_Analyzer;
74
75    --  task T is
76    --     pragma Storage_Size (A_Storage_Size);
77    --  end T;
78
79    --  [...]
80
81    --     Bottom_Of_Stack : aliased Integer;
82    --     --  Bottom_Of_Stack'Address will be used as an approximation of
83    --     --  the bottom of stack. A good practise is to avoid allocating
84    --     --  other local variables on this stack, as it would degrade
85    --     --  the quality of this approximation.
86
87    --  begin
88    --     Initialize_Analyzer (A,
89    --                          "Task t",
90    --                          A_Storage_Size - A_Guard,
91    --                          To_Stack_Address (Bottom_Of_Stack'Address));
92    --     Fill_Stack (A);
93    --     Some_User_Code;
94    --     Compute_Result (A);
95    --     Report_Result (A);
96    --  end T;
97
98    --  Errors:
99    --
100    --  We are instrumenting the code to measure the stack used by the user
101    --  code. This method has a number of systematic errors, but several
102    --  methods can be used to evaluate or reduce those errors. Here are
103    --  those errors and the strategy that we use to deal with them:
104
105    --  Bottom offset:
106
107    --     Description: The procedure used to fill the stack with a given
108    --       pattern will itself have a stack frame. The value of the stack
109    --       pointer in this procedure is, therefore, different from the value
110    --       before the call to the instrumentation procedure.
111
112    --     Strategy: The user of this package should measure the bottom of stack
113    --       before the call to Fill_Stack and pass it in parameter.
114
115    --  Instrumentation threshold at writing:
116
117    --     Description: The procedure used to fill the stack with a given
118    --       pattern will itself have a stack frame.  Therefore, it will
119    --       fill the stack after this stack frame. This part of the stack will
120    --       appear as used in the final measure.
121
122    --     Strategy: As the user passes the value of the bottom of stack to
123    --       the instrumentation to deal with the bottom offset error, and as as
124    --       the instrumentation procedure knows where the pattern filling start
125    --       on the stack, the difference between the two values is the minimum
126    --       stack usage that the method can measure. If, when the results are
127    --       computed, the pattern zone has been left untouched, we conclude
128    --       that the stack usage is inferior to this minimum stack usage.
129
130    --  Instrumentation threshold at reading:
131
132    --    Description: The procedure used to read the stack at the end of the
133    --      execution clobbers the stack by allocating its stack frame. If this
134    --      stack frame is bigger than the total stack used by the user code at
135    --      this point, it will increase the measured stack size.
136
137    --    Strategy: We could augment this stack frame and see if it changes the
138    --      measure. However, this error should be negligeable.
139
140    --   Pattern zone overflow:
141
142    --     Description: The stack grows outer than the outermost bound of the
143    --       pattern zone. In that case, the outermost region modified in the
144    --       pattern is not the maximum value of the stack pointer during the
145    --       execution.
146
147    --     Strategy: At the end of the execution, the difference between the
148    --       outermost memory region modified in the pattern zone and the
149    --       outermost bound of the pattern zone can be understood as the
150    --       biggest allocation that the method could have detect, provided
151    --       that there is no "Untouched allocated zone" error and no "Pattern
152    --       usage in user code" error. If no object in the user code is likely
153    --       to have this size, this is not likely to happen.
154
155    --   Pattern usage in user code:
156
157    --     Description: The pattern can be found in the object of the user code.
158    --       Therefore, the address space where this object has been allocated
159    --       will appear as untouched.
160
161    --     Strategy: Choose a pattern that is uncommon. 16#0000_0000# is the
162    --       worst choice; 16#DEAD_BEEF# can be a good one. A good choice is an
163    --       address which is not a multiple of 2, and which is not in the
164    --       target address space. You can also change the pattern to see if it
165    --       changes the measure. Note that this error *very* rarely influence
166    --       the measure of the total stack usage: to have some influence, the
167    --       pattern has to be used in the object that has been allocated on the
168    --       outermost address of the used stack.
169
170    --   Stack overflow:
171
172    --     Description: The pattern zone does not fit on the stack. This may
173    --       lead to an erroneous execution.
174
175    --    Strategy: Specify a storage size that is bigger than the size of the
176    --      pattern. 2 times bigger should be enough.
177
178    --   Augmentation of the user stack frames:
179
180    --     Description: The use of instrumentation object or procedure may
181    --       augment the stack frame of the caller.
182
183    --     Strategy: Do *not* inline the instrumentation procedures. Do *not*
184    --       allocate the Stack_Analyzer object on the stack.
185
186    --   Untouched allocated zone:
187
188    --     Description: The user code may allocate objects that it will never
189    --       touch. In that case, the pattern will not be changed.
190
191    --     Strategy: There are no way to detect this error. Fortunately, this
192    --       error is really rare, and it is most probably a bug in the user
193    --       code, e.g. some uninitialized variable. It is (most of the time)
194    --       harmless: it influences the measure only if the untouched allocated
195    --       zone happens to be located at the outermost value of the stack
196    --       pointer for the whole execution.
197
198    procedure Initialize (Buffer_Size : Natural);
199    pragma Export (C, Initialize, "__gnat_stack_usage_initialize");
200    --  Initializes the size of the buffer that stores the results. Only the
201    --  first Buffer_Size results are stored. Any results that do not fit in
202    --  this buffer will be displayed on the fly.
203
204    procedure Fill_Stack (Analyzer : in out Stack_Analyzer);
205    --  Fill an area of the stack with the pattern Analyzer.Pattern. The size
206    --  of this area is Analyzer.Size. After the call to this procedure,
207    --  the memory will look like that:
208    --
209    --                                                             Stack growing
210    --  ----------------------------------------------------------------------->
211    --  |<---------------------->|<----------------------------------->|
212    --  |  Stack frame           | Memory filled with Analyzer.Pattern |
213    --  |  of Fill_Stack         |                                     |
214    --  |  (deallocated at       |                                     |
215    --  |  the end of the call)  |                                     |
216    --  ^                        |                                     |
217    --  Analyzer.Bottom_Of_Stack ^                                     |
218    --                    Analyzer.Inner_Pattern_Mark                  ^
219    --                                            Analyzer.Outer_Pattern_Mark
220
221    procedure Initialize_Analyzer
222      (Analyzer  : in out Stack_Analyzer;
223       Task_Name : String;
224       Size      : Natural;
225       Bottom    : Stack_Address;
226       Pattern   : Word_32 := 16#DEAD_BEEF#);
227    --  Should be called before any use of a Stack_Analyzer, to initialize it.
228    --  Size is the size of the pattern zone. Bottom should be a close
229    --  approximation of the caller base frame address.
230
231    Is_Enabled : Boolean := False;
232    --  When this flag is true, then stack analysis is enabled
233
234    procedure Compute_Result (Analyzer : in out Stack_Analyzer);
235    --  Read the patern zone and deduce the stack usage. It should be called
236    --  from the same frame as Fill_Stack. If Analyzer.Probe is not null, an
237    --  array of Word_32 with Analyzer.Probe elements is allocated on
238    --  Compute_Result's stack frame. Probe can be used to detect  the error:
239    --  "instrumentation threshold at reading". See above. After the call
240    --  to this procedure, the memory will look like:
241    --
242    --                                                             Stack growing
243    --  ----------------------------------------------------------------------->
244    --  |<---------------------->|<-------------->|<--------->|<--------->|
245    --  |  Stack frame           | Array of       | used      |  Memory   |
246    --  |  of Compute_Result     | Analyzer.Probe | during    |   filled  |
247    --  |  (deallocated at       | elements       |  the      |    with   |
248    --  |  the end of the call)  |                | execution |  pattern  |
249    --  |                        ^                |           |           |
250    --  |                   Inner_Pattern_Mark    |           |           |
251    --  |                                                     |           |
252    --  |<---------------------------------------------------->           |
253    --                  Stack used                                        ^
254    --                                                     Outer_Pattern_Mark
255
256    procedure Report_Result (Analyzer : Stack_Analyzer);
257    --  Store the results of the computation in memory, at the address
258    --  corresponding to the symbol __gnat_stack_usage_results. This is not
259    --  done inside Compute_Resuls in order to use as less stack as possible
260    --  within a task.
261
262    procedure Output_Results;
263    --  Print the results computed so far on the standard output. Should be
264    --  called when all tasks are dead.
265
266    pragma Export (C, Output_Results, "__gnat_stack_usage_output_results");
267
268 private
269
270    Task_Name_Length : constant := 32;
271
272    package Word_32_Addr is
273      new System.Address_To_Access_Conversions (Word_32);
274
275    type Stack_Analyzer is record
276       Task_Name : String (1 .. Task_Name_Length);
277       --  Name of the task
278
279       Size : Natural;
280       --  Size of the pattern zone
281
282       Pattern : Word_32;
283       --  Pattern used to recognize untouched memory
284
285       Inner_Pattern_Mark : Stack_Address;
286       --  Innermost bound of the pattern area on the stack
287
288       Outer_Pattern_Mark : Stack_Address;
289       --  Outermost bound of the pattern area on the stack
290
291       Outermost_Touched_Mark : Stack_Address;
292       --  Outermost address of the pattern area whose value it is pointing
293       --  at has been modified during execution. If the systematic error are
294       --  compensated, it is the outermost value of the stack pointer during
295       --  the execution.
296
297       Bottom_Of_Stack : Stack_Address;
298       --  Address of the bottom of the stack, as given by the caller of
299       --  Initialize_Analyzer.
300
301       Array_Address : System.Address;
302       --  Address of the array of Word_32 that represents the pattern zone
303
304       First_Is_Outermost : Boolean;
305       --  Set to true if the first element of the array of Word_32 that
306       --  represents the pattern zone is at the outermost address of the
307       --  pattern zone; false if it is the innermost address.
308
309       Result_Id : Positive;
310       --  Id of the result. If less than value given to gnatbind -u corresponds
311       --  to the location in the result array of result for the current task.
312    end record;
313
314    Environment_Task_Analyzer : Stack_Analyzer;
315
316    Compute_Environment_Task  : Boolean;
317
318    type Task_Result is record
319       Task_Name : String (1 .. Task_Name_Length);
320       Measure   : Natural;
321       Max_Size  : Natural;
322    end record;
323
324    type Result_Array_Type is array (Positive range <>) of Task_Result;
325    type Result_Array_Ptr is access all Result_Array_Type;
326
327    Result_Array : Result_Array_Ptr;
328    pragma Export (C, Result_Array, "__gnat_stack_usage_results");
329    --  Exported in order to have an easy accessible symbol in when debugging
330
331    Next_Id : Positive := 1;
332    --  Id of the next stack analyzer
333
334    function Stack_Size
335      (SP_Low  : Stack_Address;
336       SP_High : Stack_Address) return Natural;
337    pragma Inline (Stack_Size);
338    --  Return the size of a portion of stack delimeted by SP_High and SP_Low
339    --  (), i.e. the difference between SP_High and SP_Low. The storage element
340    --  pointed by SP_Low is not included in the size. Inlined to reduce the
341    --  size of the stack used by the instrumentation code.
342
343 end System.Stack_Usage;