OSDN Git Service

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