Skip to content

Commit 325de82

Browse files
committed
Reworked gmon.out file writing
1 parent 52467ed commit 325de82

File tree

5 files changed

+315
-96
lines changed

5 files changed

+315
-96
lines changed

library/profile/_mcount.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22
* $Id: profile__mcount.c,v 1.0 2022-08-06 10:36:26 clib2devs Exp $
33
*/
44

5-
#include "profile_gmon.h"
5+
#include "gmon.h"
66
#include <exec/exec.h>
77
#include <proto/exec.h>
88
#include <stddef.h>
99

10-
1110
void __mcount(uint32 frompc, uint32 selfpc);
1211

1312
void

library/profile/gmon.c

+191-89
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,144 @@
1010
#include <proto/elf.h>
1111
#include <stdio.h>
1212
#include <unistd.h>
13+
#include <macros.h>
14+
#include <sys/uio.h>
1315

1416
#define SCALE_1_TO_1 0x10000L
1517
#define MIN_OS_VERSION 52
1618

17-
#include "profile_gmon.h"
19+
#include "gmon.h"
20+
#include "gmon_out.h"
1821

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")));
2124

2225
struct gmonparam _gmonparam = {
2326
state : kGmonProfOn
2427
};
2528

2629
static unsigned int s_scale;
2730

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+
}
32144

33145
void monstartup(uint32 low_pc, uint32 high_pc) {
34146
uint8 *cp;
35147
uint32 lowpc, highpc;
36148
struct gmonparam *p = &_gmonparam;
37149
dprintf("in monstartup)\n");
150+
38151
/*
39152
* If we don't get proper lowpc and highpc, then
40153
* we'll try to get them from the elf handle.
@@ -101,20 +214,33 @@ void monstartup(uint32 low_pc, uint32 high_pc) {
101214
p->tos[0].link = 0;
102215

103216
/* 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+
}
107230
else
108231
s_scale = SCALE_1_TO_1;
109232

110-
s_scale >>= 1;
111233
dprintf("Enabling monitor\n");
112234
moncontrol(1);
113235
}
114236

115237
void moncontrol(int mode) {
116238
struct gmonparam *p = &_gmonparam;
117239

240+
/* Don't change the state if we ran into an error. */
241+
if (p->state == kGmonProfError)
242+
return;
243+
118244
if (mode) {
119245
/* Start profiling. */
120246
profil((uint16 *) p->kcount, (size_t) p->kcountsize, p->lowpc, s_scale);
@@ -128,122 +254,98 @@ void moncontrol(int mode) {
128254

129255
void moncleanup(void) {
130256
BPTR fd;
131-
int fromindex;
132-
int endfrom;
133-
uint32 frompc;
134-
int toindex;
135-
struct rawarc rawarc;
136257
struct gmonparam *p = &_gmonparam;
137-
struct gmonhdr gmonhdr, *hdr;
138-
#ifdef DEBUG
139-
FILE *log;
140-
#endif
141258

142259
moncontrol(0);
143260

144261
if (p->state == kGmonProfError) {
145262
fprintf(stderr, "WARNING: Overflow during profiling\n");
146263
}
147264

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+
}
153271

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;
155279

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;
161282

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));
164287

165-
endfrom = p->fromssize / sizeof(*p->froms);
288+
/* write PC histogram: */
289+
write_hist(fd);
166290

167-
#ifdef DEBUG
168-
log = fopen("gmon.log", "w");
169-
#endif
291+
/* write call-graph: */
292+
write_call_graph(fd);
170293

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);
174296

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);
190298
}
191-
192-
#ifdef DEBUG
193-
if (log)
194-
fclose(log);
195-
#endif
196-
Close(fd);
197299
}
198300

199301
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;
202304
struct Process *self;
203305
BPTR seglist;
204-
Elf32_Handle elfHandle;
205306
uint32 i;
206307
Elf32_Shdr *shdr;
207308
uint32 numSections;
208309

209310
*lowpc = 0;
210311
*highpc = 0;
211312

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) {
216317
self = (struct Process *) FindTask(0);
217318
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+
}
231334
}
335+
CloseElfTags(elfHandle, CET_ReClose, TRUE, TAG_DONE);
232336
}
233-
234-
CloseElfTags(elfHandle, CET_ReClose, TRUE, TAG_DONE);
235337
}
236338
}
237339
}
238340
}
239341

240-
if (__IElf) {
241-
DropInterface((struct Interface *) __IElf);
242-
__IElf = NULL;
342+
if (IElf) {
343+
DropInterface((struct Interface *) IElf);
344+
IElf = NULL;
243345
}
244-
if (__ElfBase) {
245-
CloseLibrary(__ElfBase);
246-
__ElfBase = NULL;
346+
if (ElfBase) {
347+
CloseLibrary(ElfBase);
348+
ElfBase = NULL;
247349
}
248350
}
249351

0 commit comments

Comments
 (0)