I was chatting with the home-brewer who built the wrap030 and he noted that he was experiencing excruciatingly long boot times, roughly 14 minutes from power on to login prompt. The wrap030 is a 25MHz 68030 system with a relatively constrained I/O subsystem: 8 16550 UARTs and a PIO-only ATA disk interface. The current incarnation of the machine has 16MB of DRAM.
He took some notes about what was taking a long time and a few things stood out: ldconfig and motd. ldconfig was addressed separately, but motd? That script doesn’t do much! Well, as it turns out, what he was really observing with motd was “there are lots of things run around the same time as motd that aren’t being used”. That is, their rc.d scripts were being run only for them no decide to not do any work because their service was not enabled. Some of the work they decided not to do was “report progress”, so it just looked like motd was taking a really long time. After instrumenting the rc.d script incovations, we discovered that the scripts that didn’t actually do anything were taking quite a bit of time as far as no-ops go… anywhere between 3 to 6 seconds each, sometimes more. Some of this was going into spawning sub-shells, some of it was going into reading the script, some of it was going into determing if the service was already running (which rc.subr does always for every rc.d script). All on a machine that is very I/O constrained. It was death by 1000 not-exactly-paper-cuts. I stewed on the problem for a little while and came up with a solution: Compute the set of scripts that will do actual work, cache that result, and then use that cached ordered list to run *only those* scripts at boot time. A quick proof-of-concept was thrown together and initial tests looked promising, so I worked on this proposed solution. Initial tests of this solution on the wrap030 were quite shocking. After the cached script was was computed, boot time dropped by nearly 50%, from ~13 minutes to ~7 minutes (!!). I decided to give it a whirl on my AlphaStation 200 4/233. It has faster I/O than the wrap030, and has a few heavy-hitters in the boot process (ntpd, sshd, IPv6 DAD, fontconfig cache, etc.) that take up quite a bit of time on their own, but even on that machine, “date-to-date” boot time dropped from 2min 20sec to 2min flat. These changes are essentially confined to just 2 files: /etc/rc.subr, which implements the meat of the “rcorder.cache” as a set of shell functions plus a default method to determine “this script does useful work”, and some small changes to /etc/rc to use the cache and update it, if appropriate. The cache is considered out-of-date if any of /etc/rc.d, /etc/rc.conf, /etc/defaults/rc.conf, or /etc/rc.conf.d/* are newer than the “rcorder.cache”, which is stored at /etc/rcorder.cache. Yes, I know, but the cache file has to be in /etc because it’s the only location guaranteed to be available. It has provisions for not throwing useless errors if a read-only root file system is employed, and has an /etc/rc.conf knob to disable it. There is an /etc/rc.d/rcorder_cache that does nothing at boot time, but can be used to query the in-use status of the cache (“status”) or rebuild the cache explicitly (“reload”). “But Jason, no one is complaining about boot time in retro-emulators!” I can hear some of you saying. And, for the most part you’re right. Emulators mask this problem in two ways: they are not typically cycle accurate (on a real machine, a memory read cycle from a DRAM location takes less than half the time of a memory read cycle from the ATA data port), and the disk I/O on an emulated machine is typically an “instantaenous” affair. These problems are best observed on actual machines, and I suspect 32-bit SPARC, VAX, practically all supported m68k systems, and othwise I/O constrained machines like Shark (or anything that has NFS root) to benefit most from these changes. The issue is captured here: https://gnats.netbsd.org/60607 The proposed changes, here: https://www.netbsd.org/~thorpej/rcorder-cache-diff-v2.txt Discutez-en, svp! -- thorpej
