Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/gmon/gmon.c
39476 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1983, 1992, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* 3. Neither the name of the University nor the names of its contributors
16
* may be used to endorse or promote products derived from this software
17
* without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGE.
30
*/
31
32
#include "namespace.h"
33
#include <sys/param.h>
34
#include <sys/time.h>
35
#include <sys/gmon.h>
36
#include <sys/mman.h>
37
#include <sys/sysctl.h>
38
39
#include <err.h>
40
#include <fcntl.h>
41
#include <inttypes.h>
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include <string.h>
45
#include <unistd.h>
46
#include "un-namespace.h"
47
48
#include "libc_private.h"
49
50
struct gmonparam _gmonparam = { GMON_PROF_OFF };
51
52
static int s_scale;
53
/* See profil(2) where this is described (incorrectly). */
54
#define SCALE_SHIFT 16
55
56
#define ERR(s) _write(2, s, sizeof(s))
57
58
void moncontrol(int);
59
static int hertz(void);
60
void _mcleanup(void);
61
62
void
63
monstartup(u_long lowpc, u_long highpc)
64
{
65
int o;
66
char *cp;
67
struct gmonparam *p = &_gmonparam;
68
69
/*
70
* round lowpc and highpc to multiples of the density we're using
71
* so the rest of the scaling (here and in gprof) stays in ints.
72
*/
73
p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
74
p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
75
p->textsize = p->highpc - p->lowpc;
76
p->kcountsize = p->textsize / HISTFRACTION;
77
p->hashfraction = HASHFRACTION;
78
p->fromssize = p->textsize / HASHFRACTION;
79
p->tolimit = p->textsize * ARCDENSITY / 100;
80
if (p->tolimit < MINARCS)
81
p->tolimit = MINARCS;
82
else if (p->tolimit > MAXARCS)
83
p->tolimit = MAXARCS;
84
p->tossize = p->tolimit * sizeof(struct tostruct);
85
86
cp = mmap(NULL, p->kcountsize + p->fromssize + p->tossize,
87
PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
88
if (cp == MAP_FAILED) {
89
ERR("monstartup: out of memory\n");
90
return;
91
}
92
#ifdef notdef
93
bzero(cp, p->kcountsize + p->fromssize + p->tossize);
94
#endif
95
p->tos = (struct tostruct *)cp;
96
cp += p->tossize;
97
p->kcount = (u_short *)cp;
98
cp += p->kcountsize;
99
p->froms = (u_short *)cp;
100
101
p->tos[0].link = 0;
102
103
o = p->highpc - p->lowpc;
104
s_scale = (p->kcountsize < o) ?
105
((uintmax_t)p->kcountsize << SCALE_SHIFT) / o : (1 << SCALE_SHIFT);
106
moncontrol(1);
107
}
108
109
void
110
_mcleanup(void)
111
{
112
int fd;
113
int fromindex;
114
int endfrom;
115
u_long frompc;
116
int toindex;
117
struct rawarc rawarc;
118
struct gmonparam *p = &_gmonparam;
119
struct gmonhdr gmonhdr, *hdr;
120
struct clockinfo clockinfo;
121
char outname[128];
122
int mib[2];
123
size_t size;
124
#ifdef DEBUG
125
int log, len;
126
char buf[200];
127
#endif
128
129
if (p->state == GMON_PROF_ERROR)
130
ERR("_mcleanup: tos overflow\n");
131
132
size = sizeof(clockinfo);
133
mib[0] = CTL_KERN;
134
mib[1] = KERN_CLOCKRATE;
135
if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
136
/*
137
* Best guess
138
*/
139
clockinfo.profhz = hertz();
140
} else if (clockinfo.profhz == 0) {
141
if (clockinfo.hz != 0)
142
clockinfo.profhz = clockinfo.hz;
143
else
144
clockinfo.profhz = hertz();
145
}
146
147
moncontrol(0);
148
if (getenv("PROFIL_USE_PID"))
149
snprintf(outname, sizeof(outname), "%s.%d.gmon",
150
_getprogname(), getpid());
151
else
152
snprintf(outname, sizeof(outname), "%s.gmon", _getprogname());
153
154
fd = _open(outname, O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, 0666);
155
if (fd < 0) {
156
_warn("_mcleanup: %s", outname);
157
return;
158
}
159
#ifdef DEBUG
160
log = _open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, 0664);
161
if (log < 0) {
162
_warn("_mcleanup: gmon.log");
163
return;
164
}
165
len = sprintf(buf, "[mcleanup1] kcount 0x%p ssiz %lu\n",
166
p->kcount, p->kcountsize);
167
_write(log, buf, len);
168
#endif
169
hdr = (struct gmonhdr *)&gmonhdr;
170
bzero(hdr, sizeof(*hdr));
171
hdr->lpc = p->lowpc;
172
hdr->hpc = p->highpc;
173
hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
174
hdr->version = GMONVERSION;
175
hdr->profrate = clockinfo.profhz;
176
_write(fd, (char *)hdr, sizeof *hdr);
177
_write(fd, p->kcount, p->kcountsize);
178
endfrom = p->fromssize / sizeof(*p->froms);
179
for (fromindex = 0; fromindex < endfrom; fromindex++) {
180
if (p->froms[fromindex] == 0)
181
continue;
182
183
frompc = p->lowpc;
184
frompc += fromindex * p->hashfraction * sizeof(*p->froms);
185
for (toindex = p->froms[fromindex]; toindex != 0;
186
toindex = p->tos[toindex].link) {
187
#ifdef DEBUG
188
len = sprintf(buf,
189
"[mcleanup2] frompc 0x%lx selfpc 0x%lx count %lu\n" ,
190
frompc, p->tos[toindex].selfpc,
191
p->tos[toindex].count);
192
_write(log, buf, len);
193
#endif
194
rawarc.raw_frompc = frompc;
195
rawarc.raw_selfpc = p->tos[toindex].selfpc;
196
rawarc.raw_count = p->tos[toindex].count;
197
_write(fd, &rawarc, sizeof rawarc);
198
}
199
}
200
_close(fd);
201
}
202
203
/*
204
* Control profiling
205
* profiling is what mcount checks to see if
206
* all the data structures are ready.
207
*/
208
void
209
moncontrol(int mode)
210
{
211
struct gmonparam *p = &_gmonparam;
212
213
if (mode) {
214
/* start */
215
profil((char *)p->kcount, p->kcountsize, p->lowpc, s_scale);
216
p->state = GMON_PROF_ON;
217
} else {
218
/* stop */
219
profil((char *)0, 0, 0, 0);
220
p->state = GMON_PROF_OFF;
221
}
222
}
223
224
/*
225
* discover the tick frequency of the machine
226
* if something goes wrong, we return 0, an impossible hertz.
227
*/
228
static int
229
hertz(void)
230
{
231
struct itimerval tim;
232
233
tim.it_interval.tv_sec = 0;
234
tim.it_interval.tv_usec = 1;
235
tim.it_value.tv_sec = 0;
236
tim.it_value.tv_usec = 0;
237
setitimer(ITIMER_REAL, &tim, 0);
238
setitimer(ITIMER_REAL, 0, &tim);
239
if (tim.it_interval.tv_usec < 2)
240
return(0);
241
return (1000000 / tim.it_interval.tv_usec);
242
}
243
244