svn commit: r274739 - head/sys/mips/conf

Dag-Erling Smørgrav des at des.no
Tue Nov 25 12:16:03 UTC 2014


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
-- 
Dag-Erling Smørgrav - des at des.no

-------------- next part --------------
A non-text attachment was scrubbed...
Name: attachtimes-20141125.diff
Type: text/x-patch
Size: 1963 bytes
Desc: not available
URL: <http://lists.freebsd.org/pipermail/freebsd-arch/attachments/20141125/dc05b8ee/attachment.bin>
-------------- next part --------------
/*-
 * Copyright (c) 2012 Dag-Erling Smørgrav
 * 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 PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * 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, STRICT
 * 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 <sys/endian.h>
#include <sys/tree.h>

#include <err.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

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)
{
	
	struct at_entry key, *e;

	strcpy(key.name, name);
	if ((e = RB_FIND(at_entry_tree, &at_entry_head, &key)) != NULL)
		return (e);
	if (opt_v > 1)
		warnx("adding device %s", name);
	if ((e = calloc(1, sizeof *e)) == NULL)
		err(1, "calloc()");
	strcpy(e->name, name);
	if ((e->f = fopen(name, "a")) == 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 = RB_ROOT(&at_entry_head)) != 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 = 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 = flsll((unsigned long long)delta) - 10;
	if (bits < 0)
		return;
	if (bits > MAX_HIST_BITS) {
		++hist_ignored;
		return;
	}
	bucket = (int)(delta & ~((uint64_t)1 << bits));
	if (hist == NULL || hist_size <= bucket) {
		while (hist_size <= bucket)
			hist_size *= 2;
		if ((hist = realloc(hist, hist_size * sizeof *hist)) == NULL)
			err(1, "realloc()");
	}
	if (bucket > hist_max)
		hist_max = 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 = fopen(fn, "w")) == NULL)
		err(1, "open(\"%s\")", fn);
	if (opt_c && ftruncate(fileno(f), 0) < 0)
		err(1, "truncate(\"%s\")", fn);
	for (i = 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 = open(fn, O_RDONLY)) < 0)
		err(1, "%s", fn);
	for (;;) {
		if ((rlen = read(fd, &at, sizeof at)) < 0)
			err(1, "%s", fn);
		if (rlen == 0)
			break;
		if (rlen != sizeof at) {
			warnx("%s: short read", fn);
			break;
		}
		if (*at.name == '\0')
			continue;
		e = get_at_entry(at.name);
		delta = 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 = getopt(argc, argv, "chv")) != -1)
		switch (opt) {
		case 'c':
			++opt_c;
			break;
		case 'h':
			++opt_h;
			break;
		case 'v':
			++opt_v;
			break;
		default:
			usage();
		}

	argc -= optind;
	argv += optind;

	init_at_entry();
	if (argc == 0)
		read_attachtimes("/dev/stdout");
	else
		while (argc--)
			read_attachtimes(*argv++);
	exit_at_entry();
	if (opt_h)
		write_histogram("histogram");

	exit(0);
}


More information about the freebsd-arch mailing list