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