10
10
#include <proto/elf.h>
11
11
#include <stdio.h>
12
12
#include <unistd.h>
13
+ #include <macros.h>
14
+ #include <sys/uio.h>
13
15
14
16
#define SCALE_1_TO_1 0x10000L
15
17
#define MIN_OS_VERSION 52
16
18
17
- #include "profile_gmon.h"
19
+ #include "gmon.h"
20
+ #include "gmon_out.h"
18
21
19
- #undef DebugPrintF
20
- #define dprintf ( format , args ...) (( struct ExecIFace *)((*(struct ExecBase **)4)->MainInterface))->DebugPrintF("[%s] " format, __PRETTY_FUNCTION__, ##args)
22
+ /* Head of basic-block list or NULL. */
23
+ struct __bb * __bb_head __attribute__ (( visibility ( "hidden" )));
21
24
22
25
struct gmonparam _gmonparam = {
23
26
state : kGmonProfOn
24
27
};
25
28
26
29
static unsigned int s_scale ;
27
30
28
- void moncontrol (int );
29
- void monstartup (uint32 , uint32 );
30
- void moncleanup (void );
31
- void mongetpcs (uint32 * lowpc , uint32 * highpc );
31
+ void
32
+ write_hist (int fd ) {
33
+ u_char tag = GMON_TAG_TIME_HIST ;
34
+
35
+ if (_gmonparam .kcountsize > 0 ) {
36
+ struct iovec iov [3 ] = {
37
+ { & tag , sizeof (tag ) },
38
+ { & thdr , sizeof (struct gmon_hist_hdr ) },
39
+ { _gmonparam .kcount , _gmonparam .kcountsize }
40
+ };
41
+
42
+ if (sizeof (thdr ) != sizeof (struct gmon_hist_hdr ) || (offsetof(struct real_gmon_hist_hdr , low_pc ) != offsetof(struct gmon_hist_hdr , low_pc )) || (offsetof(struct real_gmon_hist_hdr , high_pc ) != offsetof(struct gmon_hist_hdr , high_pc )) || (offsetof(struct real_gmon_hist_hdr , hist_size ) != offsetof(struct gmon_hist_hdr , hist_size )) || (offsetof(struct real_gmon_hist_hdr , prof_rate ) != offsetof(struct gmon_hist_hdr , prof_rate )) || (offsetof(struct real_gmon_hist_hdr , dimen ) != offsetof(struct gmon_hist_hdr , dimen )) || (offsetof(struct real_gmon_hist_hdr , dimen_abbrev ) != offsetof(struct gmon_hist_hdr , dimen_abbrev )))
43
+ return ;
44
+
45
+ thdr .low_pc = (char * )_gmonparam .lowpc ;
46
+ thdr .high_pc = (char * )_gmonparam .highpc ;
47
+ thdr .hist_size = _gmonparam .kcountsize / sizeof (HISTCOUNTER );
48
+ thdr .prof_rate = TICKS_PER_SECOND ;
49
+ strncpy (thdr .dimen , "seconds" , sizeof (thdr .dimen ));
50
+ thdr .dimen_abbrev = 's' ;
51
+
52
+ writev (fd , iov , 3 );
53
+ }
54
+ }
55
+
56
+ void
57
+ write_call_graph (int fd ) {
58
+ u_char tag = GMON_TAG_CG_ARC ;
59
+ struct gmon_cg_arc_record raw_arc [NARCS_PER_WRITEV ] __attribute__((aligned (__alignof__(char * ))));
60
+ ARCINDEX from_index , to_index ;
61
+ u_long from_len ;
62
+ u_long frompc ;
63
+ struct iovec iov [2 * NARCS_PER_WRITEV ];
64
+ int nfilled ;
65
+
66
+ for (nfilled = 0 ; nfilled < NARCS_PER_WRITEV ; ++ nfilled ) {
67
+ iov [2 * nfilled ].iov_base = & tag ;
68
+ iov [2 * nfilled ].iov_len = sizeof (tag );
69
+
70
+ iov [2 * nfilled + 1 ].iov_base = & raw_arc [nfilled ];
71
+ iov [2 * nfilled + 1 ].iov_len = sizeof (struct gmon_cg_arc_record );
72
+ }
73
+
74
+ nfilled = 0 ;
75
+ from_len = _gmonparam .fromssize / sizeof (* _gmonparam .froms );
76
+ for (from_index = 0 ; from_index < from_len ; ++ from_index ) {
77
+ if (_gmonparam .froms [from_index ] == 0 )
78
+ continue ;
79
+
80
+ frompc = _gmonparam .lowpc ;
81
+ frompc += (from_index * _gmonparam .hashfraction * sizeof (* _gmonparam .froms ));
82
+ for (to_index = _gmonparam .froms [from_index ];
83
+ to_index != 0 ;
84
+ to_index = _gmonparam .tos [to_index ].link ) {
85
+ struct arc {
86
+ char * frompc ;
87
+ char * selfpc ;
88
+ int32_t count ;
89
+ } arc ;
90
+
91
+ arc .frompc = (char * )frompc ;
92
+ arc .selfpc = (char * )_gmonparam .tos [to_index ].selfpc ;
93
+ arc .count = _gmonparam .tos [to_index ].count ;
94
+ memcpy (raw_arc + nfilled , & arc , sizeof (raw_arc [0 ]));
95
+
96
+ if (++ nfilled == NARCS_PER_WRITEV ) {
97
+ writev (fd , iov , 2 * nfilled );
98
+ nfilled = 0 ;
99
+ }
100
+ }
101
+ }
102
+ if (nfilled > 0 )
103
+ writev (fd , iov , 2 * nfilled );
104
+ }
105
+
106
+ void
107
+ write_bb_counts (int fd ) {
108
+ struct __bb * grp ;
109
+ u_char tag = GMON_TAG_BB_COUNT ;
110
+ size_t ncounts ;
111
+ size_t i ;
112
+
113
+ struct iovec bbhead [2 ] = {
114
+ {& tag , sizeof (tag )},
115
+ {& ncounts , sizeof (ncounts )}
116
+ };
117
+ struct iovec bbbody [8 ];
118
+ size_t nfilled ;
119
+
120
+ for (i = 0 ; i < (sizeof (bbbody ) / sizeof (bbbody [0 ])); i += 2 ) {
121
+ bbbody [i ].iov_len = sizeof (grp -> addresses [0 ]);
122
+ bbbody [i + 1 ].iov_len = sizeof (grp -> counts [0 ]);
123
+ }
124
+
125
+ /* Write each group of basic-block info (all basic-blocks in a
126
+ compilation unit form a single group). */
127
+
128
+ for (grp = __bb_head ; grp ; grp = grp -> next ) {
129
+ ncounts = grp -> ncounts ;
130
+ writev (fd , bbhead , 2 );
131
+ for (nfilled = i = 0 ; i < ncounts ; ++ i ) {
132
+ if (nfilled > (sizeof (bbbody ) / sizeof (bbbody [0 ])) - 2 ) {
133
+ writev (fd , bbbody , nfilled );
134
+ nfilled = 0 ;
135
+ }
136
+
137
+ bbbody [nfilled ++ ].iov_base = (char * )& grp -> addresses [i ];
138
+ bbbody [nfilled ++ ].iov_base = & grp -> counts [i ];
139
+ }
140
+ if (nfilled > 0 )
141
+ writev (fd , bbbody , nfilled );
142
+ }
143
+ }
32
144
33
145
void monstartup (uint32 low_pc , uint32 high_pc ) {
34
146
uint8 * cp ;
35
147
uint32 lowpc , highpc ;
36
148
struct gmonparam * p = & _gmonparam ;
37
149
dprintf ("in monstartup)\n" );
150
+
38
151
/*
39
152
* If we don't get proper lowpc and highpc, then
40
153
* we'll try to get them from the elf handle.
@@ -101,20 +214,33 @@ void monstartup(uint32 low_pc, uint32 high_pc) {
101
214
p -> tos [0 ].link = 0 ;
102
215
103
216
/* Verify granularity for sampling */
104
- if (p -> kcountsize < p -> textsize )
105
- /* FIXME Avoid floating point */
106
- s_scale = ((float ) p -> kcountsize / p -> textsize ) * SCALE_1_TO_1 ;
217
+ if (p -> kcountsize < p -> textsize ) {
218
+ /* avoid floating point operations */
219
+ int quot = p -> textsize / p -> kcountsize ;
220
+
221
+ if (quot >= 0x10000 )
222
+ s_scale = 1 ;
223
+ else if (quot >= 0x100 )
224
+ s_scale = 0x10000 / quot ;
225
+ else if (p -> textsize >= 0x800000 )
226
+ s_scale = 0x1000000 / (p -> textsize / (p -> kcountsize >> 8 ));
227
+ else
228
+ s_scale = 0x1000000 / ((p -> textsize << 8 ) / p -> kcountsize );
229
+ }
107
230
else
108
231
s_scale = SCALE_1_TO_1 ;
109
232
110
- s_scale >>= 1 ;
111
233
dprintf ("Enabling monitor\n" );
112
234
moncontrol (1 );
113
235
}
114
236
115
237
void moncontrol (int mode ) {
116
238
struct gmonparam * p = & _gmonparam ;
117
239
240
+ /* Don't change the state if we ran into an error. */
241
+ if (p -> state == kGmonProfError )
242
+ return ;
243
+
118
244
if (mode ) {
119
245
/* Start profiling. */
120
246
profil ((uint16 * ) p -> kcount , (size_t ) p -> kcountsize , p -> lowpc , s_scale );
@@ -128,122 +254,98 @@ void moncontrol(int mode) {
128
254
129
255
void moncleanup (void ) {
130
256
BPTR fd ;
131
- int fromindex ;
132
- int endfrom ;
133
- uint32 frompc ;
134
- int toindex ;
135
- struct rawarc rawarc ;
136
257
struct gmonparam * p = & _gmonparam ;
137
- struct gmonhdr gmonhdr , * hdr ;
138
- #ifdef DEBUG
139
- FILE * log ;
140
- #endif
141
258
142
259
moncontrol (0 );
143
260
144
261
if (p -> state == kGmonProfError ) {
145
262
fprintf (stderr , "WARNING: Overflow during profiling\n" );
146
263
}
147
264
148
- fd = Open ("gmon.out" , MODE_NEWFILE );
149
- if (!fd ) {
150
- fprintf (stderr , "ERROR: could not open gmon.out\n" );
151
- return ;
152
- }
265
+ if (_gmonparam .kcountsize > 0 ) {
266
+ fd = open ("gmon.out" , O_CREAT | O_TRUNC | O_WRONLY );
267
+ if (!fd ) {
268
+ fprintf (stderr , "ERROR: could not open gmon.out\n" );
269
+ return ;
270
+ }
153
271
154
- hdr = (struct gmonhdr * ) & gmonhdr ;
272
+ /* write gmon.out header: */
273
+ struct real_gmon_hdr
274
+ {
275
+ char cookie [4 ];
276
+ int32_t version ;
277
+ char spare [3 * 4 ];
278
+ } ghdr ;
155
279
156
- hdr -> lpc = 0 ; //p->lowpc;
157
- hdr -> hpc = p -> highpc - p -> lowpc ;
158
- hdr -> ncnt = (int ) p -> kcountsize + sizeof (gmonhdr );
159
- hdr -> version = GMONVERSION ;
160
- hdr -> profrate = 100 ; //FIXME:!!
280
+ if (sizeof (ghdr ) != sizeof (struct gmon_hdr ) || (offsetof(struct real_gmon_hdr , cookie ) != offsetof(struct gmon_hdr , cookie )) || (offsetof(struct real_gmon_hdr , version ) != offsetof(struct gmon_hdr , version )))
281
+ return ;
161
282
162
- Write (fd , hdr , sizeof (* hdr ));
163
- Write (fd , p -> kcount , p -> kcountsize );
283
+ memcpy (& ghdr .cookie [0 ], GMON_MAGIC , sizeof (ghdr .cookie ));
284
+ ghdr .version = GMON_VERSION ;
285
+ memset (ghdr .spare , '\0' , sizeof (ghdr .spare ));
286
+ write (fd , & ghdr , sizeof (struct gmon_hdr ));
164
287
165
- endfrom = p -> fromssize / sizeof (* p -> froms );
288
+ /* write PC histogram: */
289
+ write_hist (fd );
166
290
167
- #ifdef DEBUG
168
- log = fopen ("gmon.log" , "w" );
169
- #endif
291
+ /* write call-graph: */
292
+ write_call_graph (fd );
170
293
171
- for (fromindex = 0 ; fromindex < endfrom ; fromindex ++ ) {
172
- if (p -> froms [fromindex ] == 0 )
173
- continue ;
294
+ /* write basic-block execution counts: */
295
+ write_bb_counts (fd );
174
296
175
- frompc = 0 ; /* FIXME: was p->lowpc; needs to be 0 and assumes -Ttext=0 on compile. Better idea? */
176
- frompc += fromindex * p -> hashfraction * sizeof (* p -> froms );
177
- for (toindex = p -> froms [fromindex ]; toindex != 0 ;
178
- toindex = p -> tos [toindex ].link ) {
179
- #ifdef DEBUG
180
- if (log )
181
- fprintf (log , "%p called from %p: %d times\n" , frompc ,
182
- p -> tos [toindex ].selfpc ,
183
- p -> tos [toindex ].count );
184
- #endif
185
- rawarc .raw_frompc = frompc ;
186
- rawarc .raw_selfpc = p -> tos [toindex ].selfpc ;
187
- rawarc .raw_count = p -> tos [toindex ].count ;
188
- Write (fd , & rawarc , sizeof (rawarc ));
189
- }
297
+ close (fd );
190
298
}
191
-
192
- #ifdef DEBUG
193
- if (log )
194
- fclose (log );
195
- #endif
196
- Close (fd );
197
299
}
198
300
199
301
void mongetpcs (uint32 * lowpc , uint32 * highpc ) {
200
- struct Library * __ElfBase = NULL ;
201
- struct ElfIFace * __IElf = NULL ;
302
+ struct Library * ElfBase = NULL ;
303
+ struct ElfIFace * IElf = NULL ;
202
304
struct Process * self ;
203
305
BPTR seglist ;
204
- Elf32_Handle elfHandle ;
205
306
uint32 i ;
206
307
Elf32_Shdr * shdr ;
207
308
uint32 numSections ;
208
309
209
310
* lowpc = 0 ;
210
311
* highpc = 0 ;
211
312
212
- __ElfBase = OpenLibrary ("elf.library" , MIN_OS_VERSION );
213
- if (__ElfBase ) {
214
- __IElf = (struct ElfIFace * ) GetInterface (__ElfBase , "main" , 1 , NULL );
215
- if (__IElf ) {
313
+ ElfBase = OpenLibrary ("elf.library" , MIN_OS_VERSION );
314
+ if (ElfBase ) {
315
+ IElf = (struct ElfIFace * ) GetInterface (ElfBase , "main" , 1 , NULL );
316
+ if (IElf ) {
216
317
self = (struct Process * ) FindTask (0 );
217
318
seglist = GetProcSegList (self , GPSLF_CLI | GPSLF_SEG );
218
-
219
- if (GetSegListInfoTags (seglist , GSLI_ElfHandle , & elfHandle , TAG_DONE ) == 1 ) {
220
- elfHandle = OpenElfTags (OET_ElfHandle , elfHandle , TAG_DONE );
221
-
222
- if (elfHandle ) {
223
- GetElfAttrsTags (elfHandle , EAT_NumSections , & numSections , TAG_DONE );
224
- for (i = 0 ; i < numSections ; i ++ ) {
225
- shdr = GetSectionHeaderTags (elfHandle , GST_SectionIndex , i , TAG_DONE );
226
- if (shdr && (shdr -> sh_flags & SWF_EXECINSTR )) {
227
- uint32 base = (uint32 ) GetSectionTags (elfHandle , GST_SectionIndex , i , TAG_DONE );
228
- * lowpc = base ;
229
- * highpc = base + shdr -> sh_size ;
230
- break ;
319
+ if (seglist != BZERO ) {
320
+ Elf32_Handle elfHandle = NULL ;
321
+
322
+ if (GetSegListInfoTags (seglist , GSLI_ElfHandle , & elfHandle , TAG_DONE ) == 1 ) {
323
+ elfHandle = OpenElfTags (OET_ElfHandle , elfHandle , TAG_DONE );
324
+ if (elfHandle ) {
325
+ GetElfAttrsTags (elfHandle , EAT_NumSections , & numSections , TAG_DONE );
326
+ for (i = 0 ; i < numSections ; i ++ ) {
327
+ shdr = GetSectionHeaderTags (elfHandle , GST_SectionIndex , i , TAG_DONE );
328
+ if (shdr && (shdr -> sh_flags & SWF_EXECINSTR )) {
329
+ uint32 base = (uint32 ) GetSectionTags (elfHandle , GST_SectionIndex , i , TAG_DONE );
330
+ * lowpc = base ;
331
+ * highpc = base + shdr -> sh_size ;
332
+ break ;
333
+ }
231
334
}
335
+ CloseElfTags (elfHandle , CET_ReClose , TRUE, TAG_DONE );
232
336
}
233
-
234
- CloseElfTags (elfHandle , CET_ReClose , TRUE, TAG_DONE );
235
337
}
236
338
}
237
339
}
238
340
}
239
341
240
- if (__IElf ) {
241
- DropInterface ((struct Interface * ) __IElf );
242
- __IElf = NULL ;
342
+ if (IElf ) {
343
+ DropInterface ((struct Interface * ) IElf );
344
+ IElf = NULL ;
243
345
}
244
- if (__ElfBase ) {
245
- CloseLibrary (__ElfBase );
246
- __ElfBase = NULL ;
346
+ if (ElfBase ) {
347
+ CloseLibrary (ElfBase );
348
+ ElfBase = NULL ;
247
349
}
248
350
}
249
351
0 commit comments