On 2023/04/11 09:28:31 +0200, Sebastien Marie <sema...@online.fr> wrote: > Hi, > > After otto@ work on mallocdump using utrace(2), I started to look again at > profiling (see moncontrol(2)). > > The current implementation tries to write a gmon.out file at program exit(3) > time, which isn't compatible with pledge(2) or unveil(2). > > This diff changes the way the runtime profiling information is extracted by > using utrace(2) (which is permitted while pledged). > > The information is collected using ktrace(2), and the gmon.out file could be > recreated from ktrace.out file post-execution (so without unveil(2) > restriction).
This is really cool, it makes trivial to profile pledged/unveiled programs without any source modifications. > [...] > Feedback would be appreciated. I've used this to profile `gotadmin pack' a couple of times. got uses several "libexec helpers" to parse data on disk, so profiling usually gets awkward. You'd need to build only the program you're interested in (e.g. got-read-pack) with PROFILE=1 and collect the data. $PROFDIR doesn't work out-of-the-box due to unveil (PROFILE builds disable pledge but leave unveil and permit "gmon.out" rwc.) With gotd it gets a little more tricky since it's a single binary that gets fork+exec'd multiple times. The argument popped up recently on the mailing list: http://marc.gameoftrees.org/mail/1683051301.32966_0.html With this instead, I can do one single run and collect the data for all processes, and keep pledge/unveil in place. To test, I've rebuilt and installed libc (and libz, and libutil - probably wasn't needed), ran unifdef -m -UPROFILE on got and rebuild with PROFILE=1 (needed to get -pg -static and the various -l*_p.) I've uploaded the png obtained with `gprof2dot | dot -Tpng' here: https://ftp.omarpolo.com/tmp/ There are two directories: one for `gotadmin pack -a' in src.git and one in got.git. I've observed that not always the profile data seems fine. Each run, I have a few processes that report 100% on every function. At first I thought it was an issue in how PROFILE=1 builds are done, but then I noticed that "good" and "bad" data can be gathered for different run of the same executable. Compare for example https://ftp.omarpolo.com/tmp/pack-got/profile.got-read-pack.52583.png (bad) and https://ftp.omarpolo.com/tmp/pack-got/profile.got-read-pack.37417.png (good) both originating from the same run. I still have the gmon.out files if needed. One comment below > --- lib/libc/gmon/gmon.c > +++ lib/libc/gmon/gmon.c > @@ -51,6 +52,32 @@ void > PROTO_NORMAL(moncontrol); > PROTO_DEPRECATED(monstartup); > > +static void > +montrace(void *addr, size_t len) > +{ > + for (;;) { > + if (len < KTR_USER_MAXLEN) { should be len <= KTR_USER_MAXLEN ? > + if (utrace("gmon.out", addr, len) == -1) > + ERR("error on utrace(), truncated gmon.out"); > + return; > + } > + if (utrace("gmon.out", addr, KTR_USER_MAXLEN) == -1) > + ERR("error on utrace(), truncated gmon.out"); ERR expands to write(2, "..."), so I'd add a return here (very unlikely for utrace to fail, but if we check for failures we should also return IMHO) There's an another existing case of ERR used like this in the file. > + > + len -= KTR_USER_MAXLEN; > + addr += KTR_USER_MAXLEN; > + } > +} Thanks!