|
| 1 | +--------------------------- |
| 2 | +:toolname:`GNATstack` Lab |
| 3 | +--------------------------- |
| 4 | + |
| 5 | +* We are going to perform stack analysis on some source code examples |
| 6 | + |
| 7 | + * Although this is called a lab, it's more like a walk-through! |
| 8 | + |
| 9 | +* Copy the :filename:`200_gnatstack` lab folder from the course materials location |
| 10 | + |
| 11 | +* Contents of the folder: |
| 12 | + |
| 13 | + * :filename:`simple` - folder containing a simple main procedure |
| 14 | + * :filename:`complicated` - folder containing multiple main procedures and some other packages |
| 15 | + |
| 16 | +.. note:: We use animation - if you don't know the answer, Page Down should give it to you |
| 17 | + |
| 18 | +--------------------------------------------- |
| 19 | +Getting Familiar with :toolname:`GNATstack` |
| 20 | +--------------------------------------------- |
| 21 | + |
| 22 | +1. Open a command prompt window and navigate into the folder :filename:`simple` |
| 23 | + |
| 24 | +2. Build the executable :ada:`main_unit`, making sure to generate call-graph information |
| 25 | + |
| 26 | + * Don't forget to use the light-tasking runtime (switch :command:`--RTS=light`) |
| 27 | + |
| 28 | +.. container:: animate 2- |
| 29 | + |
| 30 | + :command:`gprbuild --RTS=light main_unit.adb -cargs -fcallgraph-info=su` |
| 31 | + |
| 32 | +3. Perform the stack analysis |
| 33 | + |
| 34 | +.. container:: animate 3- |
| 35 | + |
| 36 | + :command:`gnatstack *.ci` |
| 37 | + |
| 38 | + :: |
| 39 | + |
| 40 | + main : total 224 bytes |
| 41 | + +-> main |
| 42 | + +-> main_unit |
| 43 | + +-> main_unit.inverse |
| 44 | + |
| 45 | + The numbers may be different, but the calls should match |
| 46 | + |
| 47 | +--------------------------- |
| 48 | +Adding Source Information |
| 49 | +--------------------------- |
| 50 | + |
| 51 | +To see where the total number of bytes comes from, run the analysis in :dfn:`verbose` mode |
| 52 | + |
| 53 | +.. container:: animate 2- |
| 54 | + |
| 55 | + :command:`gnatstack -v *.ci` |
| 56 | + |
| 57 | + :: |
| 58 | + |
| 59 | + +-> main at main:b__main_unit.adb:20:4 : 64 bytes |
| 60 | + +-> main_unit at Main_Unit:L:\\main_unit.adb:1:1, |
| 61 | + ada_main_program:b__main_unit.adb:17:14 : 96 bytes |
| 62 | + +-> main_unit.inverse at Inverse:L:\\main_unit.adb:4:4 : 64 bytes |
| 63 | + |
| 64 | +.. note:: Verbose mode also shows full path to the source |
| 65 | + |
| 66 | +----------------------------- |
| 67 | +Working with Multiple Mains |
| 68 | +----------------------------- |
| 69 | + |
| 70 | +1. Open a command prompt window and navigate into the folder :filename:`complicated` |
| 71 | + |
| 72 | +2. Examine the GNAT Project file and notice the following: |
| 73 | + |
| 74 | + * The :command:`-fcallgraph-info=su` switch is specified in the :ada:`Compiler` package |
| 75 | + * All main subprograma are specified using :ada:`for Main` |
| 76 | + |
| 77 | + * Otherwise :command:`gprbuild` does not know what executables to build |
| 78 | + |
| 79 | + * The runtime is specified using :ada:`for Runtime` |
| 80 | + |
| 81 | +3. Build all the executables using the included :filename:`default.gpr` |
| 82 | + |
| 83 | + :command:`gprbuild -P default.gpr` |
| 84 | + |
| 85 | +-------------------------- |
| 86 | +Recursive Calls (Cycles) |
| 87 | +-------------------------- |
| 88 | + |
| 89 | +.. code:: Ada |
| 90 | +
|
| 91 | + procedure Odd (Number : in out Integer) is |
| 92 | + begin |
| 93 | + Number := Number - 1; |
| 94 | + if Number > 0 then |
| 95 | + Cycles (Number); |
| 96 | + end if; |
| 97 | + end Odd; |
| 98 | +
|
| 99 | + procedure Even (Number : in out Integer) is |
| 100 | + begin |
| 101 | + Number := Number - 2; |
| 102 | + if Number > 0 then |
| 103 | + Cycles (Number); |
| 104 | + end if; |
| 105 | + end Even; |
| 106 | +
|
| 107 | + procedure Cycles (Number : in out Integer) is |
| 108 | + Half : constant Integer := Number / 2; |
| 109 | + begin |
| 110 | + if Half * 2 = Number then |
| 111 | + Even (Number); |
| 112 | + else |
| 113 | + Odd (Number); |
| 114 | + end if; |
| 115 | + end Cycles; |
| 116 | +
|
| 117 | +---------------------- |
| 118 | +Investigating Cycles |
| 119 | +---------------------- |
| 120 | + |
| 121 | +.. container:: animate 1- |
| 122 | + |
| 123 | + 1. Perform the stack analysis for :ada:`Cycles_Main` |
| 124 | + |
| 125 | +.. container:: animate 2- |
| 126 | + |
| 127 | + :command:`gnatstack -e cycles_main *.ci` |
| 128 | + |
| 129 | + :: |
| 130 | + |
| 131 | + Worst case analysis is *not* accurate because of cycles, external calls. Use -Wa for details. |
| 132 | + |
| 133 | + Accumulated stack usage information for entry points |
| 134 | + |
| 135 | + cycles_main : total 176+? bytes |
| 136 | + +-> cycles_main |
| 137 | + +-> cycles_example.cycles * |
| 138 | + +-> cycles_example.odd * |
| 139 | + +-> <__gnat_last_chance_handler> * |
| 140 | + |
| 141 | + 2. Notice the warning indicating to use :command:`-Wa` for details - try that. |
| 142 | + |
| 143 | +.. container:: animate 3- |
| 144 | + |
| 145 | + :command:`gnatstack -Wa -e cycles_main *.ci` |
| 146 | + |
| 147 | + Notice the added information |
| 148 | + |
| 149 | + :: |
| 150 | + |
| 151 | + List of reachable cycles: |
| 152 | + |
| 153 | + <c1> cycles_example.cycles |
| 154 | + +-> cycles_example.cycles |
| 155 | + +-> cycles_example.even |
| 156 | + +-> cycles_example.cycles |
| 157 | + |
| 158 | + <c2> cycles_example.cycles |
| 159 | + +-> cycles_example.cycles |
| 160 | + +-> cycles_example.odd |
| 161 | + +-> cycles_example.cycles |
| 162 | + |
| 163 | +-------------------------------------- |
| 164 | +Subprogram Pointers (Indirect Calls) |
| 165 | +-------------------------------------- |
| 166 | + |
| 167 | +.. code:: Ada |
| 168 | +
|
| 169 | + type Subprogram_Access_T is access procedure |
| 170 | + (A, B : Integer; |
| 171 | + C : out Boolean); |
| 172 | + procedure Procedure_One |
| 173 | + (A, B : Integer; |
| 174 | + C : out Boolean) is |
| 175 | + begin |
| 176 | + C := A > B; |
| 177 | + end Procedure_One; |
| 178 | +
|
| 179 | + procedure Procedure_Two |
| 180 | + (A, B : Integer; |
| 181 | + C : out Boolean) is |
| 182 | + begin |
| 183 | + C := A < B; |
| 184 | + end Procedure_Two; |
| 185 | +
|
| 186 | + Calls : array (Boolean) of Subprogram_Access_T := |
| 187 | + (Procedure_One'Access, |
| 188 | + Procedure_Two'Access); |
| 189 | +
|
| 190 | + procedure Test (Flag : in out Boolean) is |
| 191 | + begin |
| 192 | + Calls (Flag).all (1, 2, Flag); |
| 193 | + end Test; |
| 194 | +
|
| 195 | +------------------------------ |
| 196 | +Investigating Indirect Calls |
| 197 | +------------------------------ |
| 198 | + |
| 199 | +.. container:: animate 1- |
| 200 | + |
| 201 | + 1. Perform the stack analysis for :ada:`Indirect_Main` |
| 202 | + |
| 203 | +.. container:: animate 2- |
| 204 | + |
| 205 | + :command:`gnatstack -e indirect_main *.ci` |
| 206 | + |
| 207 | + :: |
| 208 | + |
| 209 | + Worst case analysis is *not* accurate because of external calls, indirect calls. Use -Wa for details. |
| 210 | + |
| 211 | + Accumulated stack usage information for entry points |
| 212 | + |
| 213 | + indirect_main : total 112+? bytes |
| 214 | + +-> indirect_main |
| 215 | + +-> indirect_example.test |
| 216 | + +-> indirect call * |
| 217 | + |
| 218 | + 2. Notice the warning indicating to use :command:`-Wa` for details - try that. |
| 219 | + |
| 220 | +.. container:: animate 3- |
| 221 | + |
| 222 | + :command:`gnatstack -Wa -e indirect_main *.ci` |
| 223 | + |
| 224 | + Notice the added information |
| 225 | + |
| 226 | + :: |
| 227 | + |
| 228 | + List of reachable external subprograms: |
| 229 | + |
| 230 | + <__gnat_last_chance_handler> |
| 231 | + |
| 232 | + List of reachable and unresolved indirect (including dispatching) calls: |
| 233 | + |
| 234 | + 1 indirect call in: indirect_example.test |
| 235 | + at L:\indirect_example.adb:26 |
| 236 | + |
| 237 | +---------------------- |
| 238 | +Using Other Switches |
| 239 | +---------------------- |
| 240 | + |
| 241 | +If you have time, experiment with some other switches |
| 242 | + |
| 243 | +.. container:: animate 1- |
| 244 | + |
| 245 | + * Show information for multiple main programs |
| 246 | + |
| 247 | +.. container:: animate 2- |
| 248 | + |
| 249 | + :command:`gnatstack -e indirect_main,cycles_main *.ci` |
| 250 | + |
| 251 | +.. container:: animate 1- |
| 252 | + |
| 253 | + * Show target for dispatching calls |
| 254 | + |
| 255 | +.. container:: animate 3- |
| 256 | + |
| 257 | + :command:`gnatstack -td -e dispatching_main *.ci` |
0 commit comments