From owner-freebsd-arch@FreeBSD.ORG Tue Nov 25 12:16:02 2014 Return-Path: Delivered-To: arch@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id EBDC081C; Tue, 25 Nov 2014 12:16:02 +0000 (UTC) Received: from smtp.des.no (smtp.des.no [194.63.250.102]) by mx1.freebsd.org (Postfix) with ESMTP id 4EEFFFAE; Tue, 25 Nov 2014 12:16:01 +0000 (UTC) Received: from nine.des.no (smtp.des.no [194.63.250.102]) by smtp-int.des.no (Postfix) with ESMTP id 3099AAD8F; Tue, 25 Nov 2014 12:16:01 +0000 (UTC) Received: by nine.des.no (Postfix, from userid 1001) id A6EC712B1; Tue, 25 Nov 2014 13:15:54 +0100 (CET) From: =?utf-8?Q?Dag-Erling_Sm=C3=B8rgrav?= To: Ian Lepore Subject: Re: svn commit: r274739 - head/sys/mips/conf References: <201411200552.sAK5qnXP063073@svn.freebsd.org> <20141120084832.GE24601@funkthat.com> <20141121092245.GI99957@funkthat.com> <1416582989.1147.250.camel@revolution.hippie.lan> <026FEB8A-CA8C-472F-A8E4-DA3D0AC44B34@grondar.org> <1416596266.1147.290.camel@revolution.hippie.lan> <1416598889.1147.297.camel@revolution.hippie.lan> <86egsvueqk.fsf@nine.des.no> <1416691274.1147.339.camel@revolution.hippie.lan> <398A380D-49AF-480C-8842-8835F81EF641@grondar.org> <1416806894.1147.362.camel@revolution.hippie.lan> <18B8A926-59C0-49B4-ADA3-A11688609852@grondar.org> <1416841268.1147.386.camel@revolution.hippie.lan> <86wq6k9okk.fsf@nine.des.no> <8661e3wtk6.fsf@nine.des.no> <86oarvvaet.fsf@nine.des.no> Date: Tue, 25 Nov 2014 13:15:54 +0100 In-Reply-To: <86oarvvaet.fsf@nine.des.no> ("Dag-Erling =?utf-8?Q?Sm=C3=B8r?= =?utf-8?Q?grav=22's?= message of "Tue, 25 Nov 2014 11:31:38 +0100") Message-ID: <86egsrxypx.fsf@nine.des.no> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (berkeley-unix) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Cc: arch@freebsd.org, Mark R V Murray X-BeenThere: freebsd-arch@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: Discussion related to FreeBSD architecture List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 25 Nov 2014 12:16:03 -0000 --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Ian, please try the attached patch. The way this is intended to be used is that you set up a system with an /etc/rc that does nothing else than mount the root file system and append the output from "sysctl -b hw.attachtimes" to a log file, then reboot. You let it run for as long as you wish, then copy the log file to another machine and run the attachtimes utility (source code below) on the log file to extract the data and display either the raw numbers or a histogram showing the distribution. See freefall:~des/software/attachtimes.tgz for an example of how to set this up. All you need is the loader and kernel, a minimal /etc, and the tools required by /etc/rc (sh, fsck, mount, df, sysctl, halt, reboot). The example contains quite a bit more than that because I wanted to be able to boot it in single-user mode for debugging. The patch can easily be modified to record the actual timestamps instead of just the delta, but remember to modify the utility as well, or the output will be complete nonsense. DES --=20 Dag-Erling Sm=C3=B8rgrav - des@des.no --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=attachtimes-20141125.diff Index: sys/kern/subr_bus.c =================================================================== --- sys/kern/subr_bus.c (revision 275022) +++ sys/kern/subr_bus.c (working copy) @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -66,6 +67,16 @@ SYSCTL_NODE(_hw, OID_AUTO, bus, CTLFLAG_RW, NULL, NULL); SYSCTL_ROOT_NODE(OID_AUTO, dev, CTLFLAG_RW, NULL, NULL); +#define MAXNATTACHTIMES 128 +static struct attachtime { + char name[24]; + uint64_t delta; +} attachtimes[MAXNATTACHTIMES]; +static int nattachtimes; +SYSCTL_OPAQUE(_hw, OID_AUTO, attachtimes, CTLFLAG_RD, + &attachtimes, sizeof(attachtimes), "S,attachtimes", + "time spent in device_attach()"); + /* * Used to attach drivers to devclasses. */ @@ -2801,6 +2812,19 @@ return error; } +static void +device_harvest_random(device_t dev, uint64_t attachtime) +{ + + if (nattachtimes < MAXNATTACHTIMES) { + strlcpy(attachtimes[nattachtimes].name, dev->nameunit, + sizeof(attachtimes[nattachtimes])); + attachtimes[nattachtimes].delta = htobe64(attachtime); + ++nattachtimes; + } + random_harvest(&attachtime, sizeof(attachtime), 4, RANDOM_ATTACH); +} + /** * @brief Attach a device driver to a device * @@ -2849,17 +2873,7 @@ dev->state = DS_NOTPRESENT; return (error); } - attachtime = get_cyclecount() - attachtime; - /* - * 4 bits per device is a reasonable value for desktop and server - * hardware with good get_cyclecount() implementations, but may - * need to be adjusted on other platforms. - */ -#ifdef RANDOM_DEBUG - printf("random: %s(): feeding %d bit(s) of entropy from %s%d\n", - __func__, 4, dev->driver->name, dev->unit); -#endif - random_harvest(&attachtime, sizeof(attachtime), 4, RANDOM_ATTACH); + device_harvest_random(dev, get_cyclecount() - attachtime); device_sysctl_update(dev); if (dev->busy) dev->state = DS_BUSY; --=-=-= Content-Type: text/plain; charset=utf-8 Content-Disposition: attachment; filename=attachtimes.c Content-Transfer-Encoding: quoted-printable /*- * Copyright (c) 2012 Dag-Erling Sm=C3=B8rgrav * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPO= SE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTI= AL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRI= CT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ */ #include #include #include #include #include #include #include #include #include static int opt_c; /* clobber */ static int opt_h; /* create histogram */ static int opt_v; /* verbose mode */ struct attachtime { char name[24]; uint64_t delta; }; // typedef struct at_entry at_entry; struct at_entry { RB_ENTRY(at_entry) at_rb; char name[24]; FILE *f; unsigned long count; }; RB_HEAD(at_entry_tree, at_entry) at_entry_head; static inline int at_entry_cmp(const struct at_entry *a, const struct at_entry *b) { return (strcmp(a->name, b->name)); } RB_PROTOTYPE_STATIC(at_entry_tree, at_entry, at_rb, at_entry_cmp); RB_GENERATE_STATIC(at_entry_tree, at_entry, at_rb, at_entry_cmp); static void init_at_entry(void) { RB_INIT(&at_entry_head); } static struct at_entry * get_at_entry(const char *name) { =09 struct at_entry key, *e; strcpy(key.name, name); if ((e =3D RB_FIND(at_entry_tree, &at_entry_head, &key)) !=3D NULL) return (e); if (opt_v > 1) warnx("adding device %s", name); if ((e =3D calloc(1, sizeof *e)) =3D=3D NULL) err(1, "calloc()"); strcpy(e->name, name); if ((e->f =3D fopen(name, "a")) =3D=3D NULL) err(1, "open(\"%s\")", name); if (opt_c && ftruncate(fileno(e->f), 0) < 0) err(1, "truncate(\"%s\")", name); RB_INSERT(at_entry_tree, &at_entry_head, e); return (e); } static void exit_at_entry(void) { struct at_entry *e; while ((e =3D RB_ROOT(&at_entry_head)) !=3D NULL) { RB_REMOVE(at_entry_tree, &at_entry_head, e); fclose(e->f); free(e); } } #define MAX_HIST_BITS 16 static unsigned long *hist; static int hist_size =3D 8192; static int hist_max; static int hist_count; static int hist_ignored; static void add_histogram(unsigned long long delta) { int bits, bucket; bits =3D flsll((unsigned long long)delta) - 10; if (bits < 0) return; if (bits > MAX_HIST_BITS) { ++hist_ignored; return; } bucket =3D (int)(delta & ~((uint64_t)1 << bits)); if (hist =3D=3D NULL || hist_size <=3D bucket) { while (hist_size <=3D bucket) hist_size *=3D 2; if ((hist =3D realloc(hist, hist_size * sizeof *hist)) =3D=3D NULL) err(1, "realloc()"); } if (bucket > hist_max) hist_max =3D bucket; ++hist[bucket]; ++hist_count; } static void write_histogram(const char *fn) { FILE *f; int i; if (opt_v) warnx("%d samples collected", hist_count); if (hist_ignored > 0) warnx("%d samples greater than %lu were ignored", hist_ignored, (unsigned long)1 << MAX_HIST_BITS); if (opt_v) warnx("saving histogram"); if ((f =3D fopen(fn, "w")) =3D=3D NULL) err(1, "open(\"%s\")", fn); if (opt_c && ftruncate(fileno(f), 0) < 0) err(1, "truncate(\"%s\")", fn); for (i =3D 0; i < hist_max; ++i) if (hist[i] > 0) fprintf(f, "%d %lu\n", i, hist[i]); fclose(f); } static void read_attachtimes(const char *fn) { struct attachtime at; struct at_entry *e; uint64_t delta; ssize_t rlen; int fd; if (opt_v) warnx("reading %s", fn); if ((fd =3D open(fn, O_RDONLY)) < 0) err(1, "%s", fn); for (;;) { if ((rlen =3D read(fd, &at, sizeof at)) < 0) err(1, "%s", fn); if (rlen =3D=3D 0) break; if (rlen !=3D sizeof at) { warnx("%s: short read", fn); break; } if (*at.name =3D=3D '\0') continue; e =3D get_at_entry(at.name); delta =3D be64toh(at.delta); fprintf(e->f, "%llu\n", (unsigned long long)delta); ++e->count; if (opt_h) add_histogram(delta); } close(fd); } static void usage(void) { fprintf(stderr, "attachtimes [-chv] [file ...]\n" "\n" "\t-c\tclobber existing files\n" "\t-h\tcreate histogram\n" "\t-v\tverbose\n"); exit(1); } int main(int argc, char *argv[]) { int opt; while ((opt =3D getopt(argc, argv, "chv")) !=3D -1) switch (opt) { case 'c': ++opt_c; break; case 'h': ++opt_h; break; case 'v': ++opt_v; break; default: usage(); } argc -=3D optind; argv +=3D optind; init_at_entry(); if (argc =3D=3D 0) read_attachtimes("/dev/stdout"); else while (argc--) read_attachtimes(*argv++); exit_at_entry(); if (opt_h) write_histogram("histogram"); exit(0); } --=-=-=--