[BACK]Return to mbufs.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / systat

File: [local] / src / usr.bin / systat / mbufs.c (download)

Revision 1.29, Thu Sep 23 10:49:55 2010 UTC (13 years, 8 months ago) by dlg
Branch: MAIN
Changes since 1.28: +2 -2 lines

tweak the mclgeti algorithm to behave better under load.

instead of letting hardware rings grow on every interrupt, restrict
it so it can only grow once per softclock tick. we can only punish
the rings on softclock ticks, so it make sense to only grow on
softclock tick boundaries too.

the rings are now punished after >1 lost softclock tick rather than
>2. mclgeti is now more aggressive at detecting livelock.

the rings get punished by an 8th, rather than by half.

we now allow the rings to be punished again even if the system is
already considered in livelock.

without this diff a livelocked system will have its rx ring sizes
scale up and down very rapidly, while holding the rings low for too
long. this affected throughput significantly.

discussed and tested heavily at j2k10. there are still some games
with softnet we can play, but this is a good first step.

"put it in" and ok deraadt@
ok claudio@ krw@ henning@ mcbride@

if we find out that it sucks we can pull it out again later. till then
we'll run with it and see how it goes.

/*	$OpenBSD: mbufs.c,v 1.29 2010/09/23 10:49:55 dlg Exp $ */
/*
 * Copyright (c) 2008 Can Erkin Acar <canacar@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/mbuf.h>
#include <sys/pool.h>
#include <net/if.h>

#include <err.h>
#include <errno.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <string.h>

#include "systat.h"


/* pool info for mcl* pools */
struct mclpool_info {
	char title[16];
	int pool_offset;
	int size;
} mclpools[MCLPOOLS];

int mclpool_count = 0;
int mbpool_index = -1;
struct pool mbpool;

/* interfaces */
static int num_ifs;
struct if_info {
	char name[16];
	struct if_data data;
} *interfaces = NULL;

void print_mb(void);
int read_mb(void);
int select_mb(void);
static void showmbuf(struct if_info *, int, int);


/* Define fields */
field_def fields_mbuf[] = {
	{"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
	{"RXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
	{"TXDELAY", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
	{"LIVELOCKS", 5, 10, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
	{"SIZE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
	{"ALIVE", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
	{"LWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
	{"HWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
	{"CWM", 3, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
};


#define FIELD_ADDR(x) (&fields_mbuf[x])

#define FLD_MB_IFACE	FIELD_ADDR(0)
#define FLD_MB_RXDELAY	FIELD_ADDR(1)
#define FLD_MB_TXDELAY	FIELD_ADDR(2)
#define FLD_MB_LLOCKS	FIELD_ADDR(3)
#define FLD_MB_MSIZE	FIELD_ADDR(4)
#define FLD_MB_MALIVE	FIELD_ADDR(5)
#define FLD_MB_MLWM	FIELD_ADDR(6)
#define FLD_MB_MHWM	FIELD_ADDR(7)
#define FLD_MB_MCWM	FIELD_ADDR(8)


/* Define views */
field_def *view_mbuf[] = {
	FLD_MB_IFACE,
#if NOTYET
	FLD_MB_RXDELAY, FLD_MB_TXDELAY,
#endif
	FLD_MB_LLOCKS, FLD_MB_MSIZE, FLD_MB_MALIVE, FLD_MB_MLWM, FLD_MB_MHWM,
	FLD_MB_MCWM, NULL
};

/* Define view managers */

struct view_manager mbuf_mgr = {
	"Mbufs", select_mb, read_mb, NULL, print_header,
	print_mb, keyboard_callback, NULL, NULL
};

field_view views_mb[] = {
	{view_mbuf, "mbufs", '4', &mbuf_mgr},
	{NULL, NULL, 0, NULL}
};


int
initmembufs(void)
{
	field_view *v;
	int i, mib[4], npools;
	struct pool pool;
	char pname[32];
	size_t size;

	/* go through all pools to identify mbuf and cluster pools */
	bzero(mclpools, sizeof(mclpools));

	mib[0] = CTL_KERN;
	mib[1] = KERN_POOL;
	mib[2] = KERN_POOL_NPOOLS;
	size = sizeof(npools);

	if (sysctl(mib, 3, &npools, &size, NULL, 0) < 0) {
		err(1, "sysctl(KERN_POOL_NPOOLS)");
		/* NOTREACHED */
	}

	for (i = 1; i <= npools; i++) {
		mib[0] = CTL_KERN;
		mib[1] = KERN_POOL;
		mib[2] = KERN_POOL_NAME;
		mib[3] = i;
		size = sizeof(pname);
		if (sysctl(mib, 4, &pname, &size, NULL, 0) < 0) {
			continue;
		}

		if (strcmp(pname, "mbpl") == 0) {
			mbpool_index = i;
			continue;
		}

		if (strncmp(pname, "mcl", 3) != 0)
			continue;

		if (mclpool_count == MCLPOOLS) {
			warnx("mbufs: Too many mcl* pools");
			break;
		}

		mib[2] = KERN_POOL_POOL;
		size = sizeof(struct pool);

		if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) {
			err(1, "sysctl(KERN_POOL_POOL, %d)", i);
			/* NOTREACHED */
		}

		mclpools[mclpool_count].size = pool.pr_size;
		mclpools[mclpool_count].pool_offset = i;
		snprintf(mclpools[mclpool_count].title,
		    sizeof(mclpools[0].title), "%dk",
		    pool.pr_size / 1024);

		mclpool_count++;
	}

	if (mclpool_count != MCLPOOLS)
		warnx("mbufs: Unable to read all %d mcl* pools", MCLPOOLS);

	/* add view to the engine */
	for (v = views_mb; v->name != NULL; v++)
		add_view(v);


	/* finally read it once */
	read_mb();

	return(1);
}

int
select_mb(void)
{
	num_disp = 0;
	return (0);
}

int
read_mb(void)
{
	struct pool pool;
	struct ifaddrs *ifap, *ifa;
	struct if_info *ifi;
	int mib[4];
	int i, p, nif, ret = 1;
	size_t size;

	num_disp = 0;
	if (getifaddrs(&ifap)) {
		error("getifaddrs: %s", strerror(errno));
		return (1);
	}

	nif = 1;
	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK)
			nif++;

	if (interfaces == NULL || num_ifs < nif) {
		size_t len = sizeof(*ifi) * nif;
		if (nif > SIZE_MAX / sizeof(*ifi)) {
			error("overflow allocting %u interfaces", nif);
			goto exit;
		}

		ifi = realloc(interfaces, len);
		if (ifi == NULL) {
			error("realloc: out of memory allocating %lld bytes",
			      (long long) len);
			goto exit;
		}

		interfaces = ifi;
		num_ifs = nif;
	}

	/* Fill in the "real" interfaces */
	ifi = interfaces + 1;

	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
		if (ifa->ifa_addr == NULL ||
		    ifa->ifa_addr->sa_family != AF_LINK)
			continue;
			
		strlcpy(ifi->name, ifa->ifa_name, sizeof(ifi->name));

		if (ifa->ifa_data)
			memcpy(&ifi->data, ifa->ifa_data, sizeof(ifi->data));
		else
			bzero(&ifi->data, sizeof(ifi->data));
		ifi++;
	}

	/* Fill in the "System" entry from pools */
	bzero(interfaces, sizeof(interfaces[0]));
	strlcpy(interfaces[0].name, "System", sizeof(interfaces[0].name));

	mib[0] = CTL_KERN;
	mib[1] = KERN_POOL;
	mib[2] = KERN_POOL_POOL;
	mib[3] = mbpool_index;
	size = sizeof(struct pool);

	if (sysctl(mib, 4, &mbpool, &size, NULL, 0) < 0) {
		error("sysctl(KERN_POOL_POOL, %d)", mib[3]);
		goto exit;
	}

	for (i = 0; i < mclpool_count; i++) {
		struct mclpool *mp = &interfaces[0].data.ifi_mclpool[i];

		mib[3] = mclpools[i].pool_offset;
		size = sizeof(struct pool);

		if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) {
			error("sysctl(KERN_POOL_POOL, %d)", mib[3]);
			continue;
		}

		mp->mcl_alive = pool.pr_nget - pool.pr_nput;
		mp->mcl_hwm = pool.pr_hiwat;
	}

	num_disp = 1;
	ret = 0;

	for (i = 0; i < num_ifs; i++) {
		struct if_info *ifi = &interfaces[i];
		int pnd = num_disp;
		for (p = 0; p < mclpool_count; p++) {
			struct mclpool *mp = &ifi->data.ifi_mclpool[p];
			if (mp->mcl_alive == 0)
				continue;
			num_disp++;
		}
		if (i && pnd == num_disp)
			num_disp++;
	}

 exit:
	freeifaddrs(ifap);
	return (ret);
}

void
print_mb(void)
{
	int i, p, n, count = 0;

	showmbuf(interfaces, -1, 1);

	for (n = i = 0; i < num_ifs; i++) {
		struct if_info *ifi = &interfaces[i];
		int pcnt = count;
		int showif = i;

		if (maxprint > 0 && count >= maxprint)
			return;

		for (p = 0; p < mclpool_count; p++) {
			struct mclpool *mp = &ifi->data.ifi_mclpool[p];
			if (mp->mcl_alive == 0)
				continue;
			if (n++ >= dispstart) {
				showmbuf(ifi, p, showif);
				showif = 0;
				count++;
			}
		}

		if (i && pcnt == count) {
			/* only print the first line */
			if (n++ >= dispstart) {
				showmbuf(ifi, -1, 1);
				count++;
			}
		}


	}
}


static void
showmbuf(struct if_info *ifi, int p, int showif)
{
	if (showif)
		print_fld_str(FLD_MB_IFACE, ifi->name);

	if (p == -1 && ifi == interfaces) {
		print_fld_size(FLD_MB_MSIZE, mbpool.pr_size);
		print_fld_size(FLD_MB_MALIVE, mbpool.pr_nget - mbpool.pr_nput);
		print_fld_size(FLD_MB_MHWM, mbpool.pr_hiwat);
	}

#if NOTYET
	print_fld_uint(FLD_MB_RXDELAY, ifi->data.ifi_rxdelay);
	print_fld_uint(FLD_MB_TXDELAY, ifi->data.ifi_txdelay);
	if (ifi->data.ifi_livelocks)
		print_fld_size(FLD_MB_LLOCKS, ifi->data.ifi_livelocks);
#endif

	if (p >= 0 && p < mclpool_count) {
		struct mclpool *mp = &ifi->data.ifi_mclpool[p];

		print_fld_str(FLD_MB_MSIZE, mclpools[p].title);
		print_fld_uint(FLD_MB_MALIVE, mp->mcl_alive);
		if (mp->mcl_lwm)
			print_fld_size(FLD_MB_MLWM, mp->mcl_lwm);
		if (mp->mcl_hwm)
			print_fld_size(FLD_MB_MHWM, mp->mcl_hwm);
		if (mp->mcl_cwm)
			print_fld_size(FLD_MB_MCWM, mp->mcl_cwm);
	}

	end_line();
}