⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lockstat.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright 2005 Sun Microsystems, Inc.  All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident	"@(#)lockstat.c	1.12	04/11/17 SMI"#include <stdio.h>#include <stddef.h>#include <stdlib.h>#include <stdarg.h>#include <string.h>#include <strings.h>#include <ctype.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#include <limits.h>#include <sys/types.h>#include <sys/modctl.h>#include <sys/stat.h>#include <sys/wait.h>#include <dtrace.h>#include <sys/lockstat.h>#include <alloca.h>#include <signal.h>#define	LS_MAX_STACK_DEPTH	50#define	LS_MAX_EVENTS		64typedef struct lsrec {	struct lsrec	*ls_next;	/* next in hash chain */	uintptr_t	ls_lock;	/* lock address */	uintptr_t	ls_caller;	/* caller address */	uint32_t	ls_count;	/* cumulative event count */	uint32_t	ls_event;	/* type of event */	uintptr_t	ls_refcnt;	/* cumulative reference count */	uint64_t	ls_time;	/* cumulative event duration */	uint32_t	ls_hist[64];	/* log2(duration) histogram */	uintptr_t	ls_stack[LS_MAX_STACK_DEPTH];} lsrec_t;typedef struct lsdata {	struct lsrec	*lsd_next;	/* next available */	int		lsd_count;	/* number of records */} lsdata_t;/* * Definitions for the types of experiments which can be run.  They are * listed in increasing order of memory cost and processing time cost. * The numerical value of each type is the number of bytes needed per record. */#define	LS_BASIC	offsetof(lsrec_t, ls_time)#define	LS_TIME		offsetof(lsrec_t, ls_hist[0])#define	LS_HIST		offsetof(lsrec_t, ls_stack[0])#define	LS_STACK(depth)	offsetof(lsrec_t, ls_stack[depth])static void report_stats(FILE *, lsrec_t **, size_t, uint64_t, uint64_t);static void report_trace(FILE *, lsrec_t **);extern int symtab_init(void);extern char *addr_to_sym(uintptr_t, uintptr_t *, size_t *);extern uintptr_t sym_to_addr(char *name);extern size_t sym_size(char *name);extern char *strtok_r(char *, const char *, char **);#define	DEFAULT_NRECS	10000#define	DEFAULT_HZ	97#define	MAX_HZ		1000static int g_stkdepth;static int g_topn = INT_MAX;static hrtime_t g_elapsed;static int g_rates = 0;static int g_pflag = 0;static int g_Pflag = 0;static int g_wflag = 0;static int g_Wflag = 0;static int g_cflag = 0;static int g_kflag = 0;static int g_gflag = 0;static int g_Vflag = 0;static int g_tracing = 0;static size_t g_recsize;static size_t g_nrecs;static int g_nrecs_used;static uchar_t g_enabled[LS_MAX_EVENTS];static hrtime_t g_min_duration[LS_MAX_EVENTS];static dtrace_hdl_t *g_dtp;static char *g_predicate;static char *g_ipredicate;static char *g_prog;static int g_proglen;static int g_dropped;typedef struct ls_event_info {	char	ev_type;	char	ev_lhdr[20];	char	ev_desc[80];	char	ev_units[10];	char	ev_name[DTRACE_NAMELEN];	char	*ev_predicate;	char	*ev_acquire;} ls_event_info_t;static ls_event_info_t g_event_info[LS_MAX_EVENTS] = {	{ 'C',	"Lock",	"Adaptive mutex spin",			"spin",	    "lockstat:::adaptive-spin" },	{ 'C',	"Lock",	"Adaptive mutex block",			"nsec",	    "lockstat:::adaptive-block" },	{ 'C',	"Lock",	"Spin lock spin",			"spin",	    "lockstat:::spin-spin" },	{ 'C',	"Lock",	"Thread lock spin",			"spin",	    "lockstat:::thread-spin" },	{ 'C',	"Lock",	"R/W writer blocked by writer",		"nsec",	    "lockstat:::rw-block", "arg2 == 0 && arg3 == 1" },	{ 'C',	"Lock",	"R/W writer blocked by readers",	"nsec",	    "lockstat:::rw-block", "arg2 == 0 && arg3 == 0 && arg4" },	{ 'C',	"Lock",	"R/W reader blocked by writer",		"nsec",	    "lockstat:::rw-block", "arg2 != 0 && arg3 == 1" },	{ 'C',	"Lock",	"R/W reader blocked by write wanted",	"nsec",	    "lockstat:::rw-block", "arg2 != 0 && arg3 == 0 && arg4" },	{ 'C',	"Lock",	"Unknown event (type 8)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 9)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 10)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 11)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 12)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 13)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 14)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 15)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 16)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 17)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 18)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 19)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 20)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 21)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 22)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 23)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 24)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 25)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 26)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 27)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 28)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 29)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 30)",		"units"	},	{ 'C',	"Lock",	"Unknown event (type 31)",		"units"	},	{ 'H',	"Lock",	"Adaptive mutex hold",			"nsec",	    "lockstat:::adaptive-release", NULL,	    "lockstat:::adaptive-acquire" },	{ 'H',	"Lock",	"Spin lock hold",			"nsec",	    "lockstat:::spin-release", NULL,	    "lockstat:::spin-acquire" },	{ 'H',	"Lock",	"R/W writer hold",			"nsec",	    "lockstat:::rw-release", "arg1 == 0",	    "lockstat:::rw-acquire" },	{ 'H',	"Lock",	"R/W reader hold",			"nsec",	    "lockstat:::rw-release", "arg1 != 0",	    "lockstat:::rw-acquire" },	{ 'H',	"Lock",	"Unknown event (type 36)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 37)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 38)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 39)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 40)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 41)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 42)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 43)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 44)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 45)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 46)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 47)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 48)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 49)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 50)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 51)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 52)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 53)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 54)",		"units"	},	{ 'H',	"Lock",	"Unknown event (type 55)",		"units"	},	{ 'I',	"CPU+PIL", "Profiling interrupt",		"nsec",	    "profile:::profile-97", NULL },	{ 'I',	"Lock",	"Unknown event (type 57)",		"units"	},	{ 'I',	"Lock",	"Unknown event (type 58)",		"units"	},	{ 'I',	"Lock",	"Unknown event (type 59)",		"units"	},	{ 'E',	"Lock",	"Recursive lock entry detected",	"(N/A)",	    "lockstat:::rw-release", NULL, "lockstat:::rw-acquire" },	{ 'E',	"Lock",	"Lockstat enter failure",		"(N/A)"	},	{ 'E',	"Lock",	"Lockstat exit failure",		"nsec"	},	{ 'E',	"Lock",	"Lockstat record failure",		"(N/A)"	},};static voidfail(int do_perror, const char *message, ...){	va_list args;	int save_errno = errno;	va_start(args, message);	(void) fprintf(stderr, "lockstat: ");	(void) vfprintf(stderr, message, args);	va_end(args);	if (do_perror)		(void) fprintf(stderr, ": %s", strerror(save_errno));	(void) fprintf(stderr, "\n");	exit(2);}static voiddfail(const char *message, ...){	va_list args;	va_start(args, message);	(void) fprintf(stderr, "lockstat: ");	(void) vfprintf(stderr, message, args);	va_end(args);	(void) fprintf(stderr, ": %s\n",	    dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));	exit(2);}static voidshow_events(char event_type, char *desc){	int i, first = -1, last;	for (i = 0; i < LS_MAX_EVENTS; i++) {		ls_event_info_t *evp = &g_event_info[i];		if (evp->ev_type != event_type ||		    strncmp(evp->ev_desc, "Unknown event", 13) == 0)			continue;		if (first == -1)			first = i;		last = i;	}	(void) fprintf(stderr,	    "\n%s events (lockstat -%c or lockstat -e %d-%d):\n\n",	    desc, event_type, first, last);	for (i = first; i <= last; i++)		(void) fprintf(stderr,		    "%4d = %s\n", i, g_event_info[i].ev_desc);}static voidusage(void){	(void) fprintf(stderr,	    "Usage: lockstat [options] command [args]\n"	    "\nEvent selection options:\n\n"	    "  -C              watch contention events [on by default]\n"	    "  -E              watch error events [off by default]\n"	    "  -H              watch hold events [off by default]\n"	    "  -I              watch interrupt events [off by default]\n"	    "  -A              watch all lock events [equivalent to -CH]\n"	    "  -e event_list   only watch the specified events (shown below);\n"	    "                  <event_list> is a comma-separated list of\n"	    "                  events or ranges of events, e.g. 1,4-7,35\n"	    "  -i rate         interrupt rate for -I [default: %d Hz]\n"	    "\nData gathering options:\n\n"	    "  -b              basic statistics (lock, caller, event count)\n"	    "  -t              timing for all events [default]\n"	    "  -h              histograms for event times\n"	    "  -s depth        stack traces <depth> deep\n"	    "\nData filtering options:\n\n"	    "  -n nrecords     maximum number of data records [default: %d]\n"	    "  -l lock[,size]  only watch <lock>, which can be specified as a\n"	    "                  symbolic name or hex address; <size> defaults\n"	    "                  to the ELF symbol size if available, 1 if not\n"	    "  -f func[,size]  only watch events generated by <func>\n"	    "  -d duration     only watch events longer than <duration>\n"	    "  -T              trace (rather than sample) events\n"	    "\nData reporting options:\n\n"	    "  -c              coalesce lock data for arrays like pse_mutex[]\n"	    "  -k              coalesce PCs within functions\n"	    "  -g              show total events generated by function\n"	    "  -w              wherever: don't distinguish events by caller\n"	    "  -W              whichever: don't distinguish events by lock\n"	    "  -R              display rates rather than counts\n"	    "  -p              parsable output format (awk(1)-friendly)\n"	    "  -P              sort lock data by (count * avg_time) product\n"	    "  -D n            only display top <n> events of each type\n"	    "  -o filename     send output to <filename>\n",	    DEFAULT_HZ, DEFAULT_NRECS);	show_events('C', "Contention");	show_events('H', "Hold-time");	show_events('I', "Interrupt");	show_events('E', "Error");	(void) fprintf(stderr, "\n");	exit(1);}static intlockcmp(lsrec_t *a, lsrec_t *b){	int i;	if (a->ls_event < b->ls_event)		return (-1);	if (a->ls_event > b->ls_event)		return (1);	for (i = g_stkdepth - 1; i >= 0; i--) {		if (a->ls_stack[i] < b->ls_stack[i])			return (-1);		if (a->ls_stack[i] > b->ls_stack[i])			return (1);	}	if (a->ls_caller < b->ls_caller)		return (-1);	if (a->ls_caller > b->ls_caller)		return (1);	if (a->ls_lock < b->ls_lock)		return (-1);	if (a->ls_lock > b->ls_lock)		return (1);	return (0);}static intcountcmp(lsrec_t *a, lsrec_t *b){	if (a->ls_event < b->ls_event)		return (-1);	if (a->ls_event > b->ls_event)		return (1);	return (b->ls_count - a->ls_count);}static inttimecmp(lsrec_t *a, lsrec_t *b){	if (a->ls_event < b->ls_event)		return (-1);	if (a->ls_event > b->ls_event)		return (1);	if (a->ls_time < b->ls_time)		return (1);	if (a->ls_time > b->ls_time)		return (-1);	return (0);}static intlockcmp_anywhere(lsrec_t *a, lsrec_t *b){	if (a->ls_event < b->ls_event)		return (-1);	if (a->ls_event > b->ls_event)		return (1);	if (a->ls_lock < b->ls_lock)		return (-1);	if (a->ls_lock > b->ls_lock)		return (1);	return (0);}static intlock_and_count_cmp_anywhere(lsrec_t *a, lsrec_t *b){	if (a->ls_event < b->ls_event)		return (-1);	if (a->ls_event > b->ls_event)		return (1);	if (a->ls_lock < b->ls_lock)		return (-1);	if (a->ls_lock > b->ls_lock)		return (1);	return (b->ls_count - a->ls_count);}static intsitecmp_anylock(lsrec_t *a, lsrec_t *b){	int i;	if (a->ls_event < b->ls_event)		return (-1);	if (a->ls_event > b->ls_event)		return (1);	for (i = g_stkdepth - 1; i >= 0; i--) {		if (a->ls_stack[i] < b->ls_stack[i])			return (-1);		if (a->ls_stack[i] > b->ls_stack[i])			return (1);	}	if (a->ls_caller < b->ls_caller)		return (-1);	if (a->ls_caller > b->ls_caller)		return (1);	return (0);}static intsite_and_count_cmp_anylock(lsrec_t *a, lsrec_t *b){	int i;	if (a->ls_event < b->ls_event)		return (-1);	if (a->ls_event > b->ls_event)		return (1);	for (i = g_stkdepth - 1; i >= 0; i--) {		if (a->ls_stack[i] < b->ls_stack[i])			return (-1);		if (a->ls_stack[i] > b->ls_stack[i])			return (1);	}	if (a->ls_caller < b->ls_caller)		return (-1);	if (a->ls_caller > b->ls_caller)		return (1);	return (b->ls_count - a->ls_count);}static voidmergesort(int (*cmp)(lsrec_t *, lsrec_t *), lsrec_t **a, lsrec_t **b, int n){	int m = n / 2;	int i, j;	if (m > 1)		mergesort(cmp, a, b, m);	if (n - m > 1)		mergesort(cmp, a + m, b + m, n - m);	for (i = m; i > 0; i--)		b[i - 1] = a[i - 1];	for (j = m - 1; j < n - 1; j++)		b[n + m - j - 2] = a[j + 1];	while (i < j)		*a++ = cmp(b[i], b[j]) < 0 ? b[i++] : b[j--];	*a = b[i];}static voidcoalesce(int (*cmp)(lsrec_t *, lsrec_t *), lsrec_t **lock, int n){	int i, j;	lsrec_t *target, *current;	target = lock[0];	for (i = 1; i < n; i++) {		current = lock[i];		if (cmp(current, target) != 0) {			target = current;			continue;		}		current->ls_event = LS_MAX_EVENTS;		target->ls_count += current->ls_count;		target->ls_refcnt += current->ls_refcnt;		if (g_recsize < LS_TIME)			continue;		target->ls_time += current->ls_time;		if (g_recsize < LS_HIST)			continue;		for (j = 0; j < 64; j++)			target->ls_hist[j] += current->ls_hist[j];	}}static voidcoalesce_symbol(uintptr_t *addrp){	uintptr_t symoff;	size_t symsize;	if (addr_to_sym(*addrp, &symoff, &symsize) != NULL && symoff < symsize)		*addrp -= symoff;}static voidpredicate_add(char **pred, char *what, char *cmp, uintptr_t value){	char *new;	int len, newlen;	if (what == NULL)		return;	if (*pred == NULL) {		*pred = malloc(1);		*pred[0] = '\0';	}	len = strlen(*pred);	newlen = len + strlen(what) + 32 + strlen("( && )");	new = malloc(newlen);	if (*pred[0] != '\0') {		if (cmp != NULL) {			(void) sprintf(new, "(%s) && (%s %s 0x%p)",			    *pred, what, cmp, (void *)value);		} else {			(void) sprintf(new, "(%s) && (%s)", *pred, what);		}	} else {		if (cmp != NULL) {			(void) sprintf(new, "%s %s 0x%p",			    what, cmp, (void *)value);		} else {			(void) sprintf(new, "%s", what);		}	}	free(*pred);	*pred = new;}static voidpredicate_destroy(char **pred){	free(*pred);	*pred = NULL;}static voidfilter_add(char **filt, char *what, uintptr_t base, uintptr_t size){	char buf[256], *c = buf, *new;	int len, newlen;	if (*filt == NULL) {		*filt = malloc(1);		*filt[0] = '\0';	}	(void) sprintf(c, "%s(%s >= 0x%p && %s < 0x%p)", *filt[0] != '\0' ?	    " || " : "", what, (void *)base, what, (void *)(base + size));	newlen = (len = strlen(*filt) + 1) + strlen(c);	new = malloc(newlen);	bcopy(*filt, new, len);	(void) strcat(new, c);	free(*filt);	*filt = new;}static voidfilter_destroy(char **filt){	free(*filt);	*filt = NULL;}static voiddprog_add(const char *fmt, ...){	va_list args;	int size, offs;	char c;	va_start(args, fmt);	size = vsnprintf(&c, 1, fmt, args) + 1;	if (g_proglen == 0) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -