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

📄 dtrace.c

📁 Sun Solaris 10 中的 DTrace 组件的源代码。请参看: http://www.sun.com/software/solaris/observability.jsp
💻 C
📖 第 1 页 / 共 5 页
字号:
 * failure; if there is no space in the aggregation buffer, the data will be * dropped, and a corresponding counter incremented. */static voiddtrace_aggregate(dtrace_aggregation_t *agg, dtrace_buffer_t *dbuf,    intptr_t offset, dtrace_buffer_t *buf, uint64_t arg){	dtrace_recdesc_t *rec = &agg->dtag_action.dta_rec;	uint32_t i, ndx, size, fsize;	uint32_t align = sizeof (uint64_t) - 1;	dtrace_aggbuffer_t *agb;	dtrace_aggkey_t *key;	uint32_t hashval = 0;	caddr_t tomax, data, kdata;	dtrace_actkind_t action;	uintptr_t offs;	if (buf == NULL)		return;	action = agg->dtag_action.dta_kind - DTRACEACT_AGGREGATION;	size = rec->dtrd_offset - agg->dtag_base;	fsize = size + rec->dtrd_size;	ASSERT(dbuf->dtb_tomax != NULL);	data = dbuf->dtb_tomax + offset + agg->dtag_base;	if ((tomax = buf->dtb_tomax) == NULL) {		dtrace_buffer_drop(buf);		return;	}	/*	 * The metastructure is always at the bottom of the buffer.	 */	agb = (dtrace_aggbuffer_t *)(tomax + buf->dtb_size -	    sizeof (dtrace_aggbuffer_t));	if (buf->dtb_offset == 0) {		/*		 * We just kludge up approximately 1/8th of the size to be		 * buckets.  If this guess ends up being routinely		 * off-the-mark, we may need to dynamically readjust this		 * based on past performance.		 */		uintptr_t hashsize = (buf->dtb_size >> 3) / sizeof (uintptr_t);		if ((uintptr_t)agb - hashsize * sizeof (dtrace_aggkey_t *) <		    (uintptr_t)tomax || hashsize == 0) {			/*			 * We've been given a ludicrously small buffer;			 * increment our drop count and leave.			 */			dtrace_buffer_drop(buf);			return;		}		/*		 * And now, a pathetic attempt to try to get a an odd (or		 * perchance, a prime) hash size for better hash distribution.		 */		if (hashsize > (DTRACE_AGGHASHSIZE_SLEW << 3))			hashsize -= DTRACE_AGGHASHSIZE_SLEW;		agb->dtagb_hashsize = hashsize;		agb->dtagb_hash = (dtrace_aggkey_t **)((uintptr_t)agb -		    agb->dtagb_hashsize * sizeof (dtrace_aggkey_t *));		agb->dtagb_free = (uintptr_t)agb->dtagb_hash;		for (i = 0; i < agb->dtagb_hashsize; i++)			agb->dtagb_hash[i] = NULL;	}	/*	 * Calculate the hash value based on the key.  Note that we _don't_	 * include the aggid in the hashing (but we will store it as part of	 * the key).  The hashing algorithm is Bob Jenkins' "One-at-a-time"	 * algorithm: a simple, quick algorithm that has no known funnels, and	 * gets good distribution in practice.  The efficacy of the hashing	 * algorithm (and a comparison with other algorithms) may be found by	 * running the ::dtrace_aggstat MDB dcmd.	 */	for (i = sizeof (dtrace_aggid_t); i < size; i++) {		hashval += data[i];		hashval += (hashval << 10);		hashval ^= (hashval >> 6);	}	hashval += (hashval << 3);	hashval ^= (hashval >> 11);	hashval += (hashval << 15);	/*	 * Yes, the divide here is expensive.  If the cycle count here becomes	 * prohibitive, we can do tricks to eliminate it.	 */	ndx = hashval % agb->dtagb_hashsize;	for (key = agb->dtagb_hash[ndx]; key != NULL; key = key->dtak_next) {		ASSERT((caddr_t)key >= tomax);		ASSERT((caddr_t)key < tomax + buf->dtb_size);		if (hashval != key->dtak_hashval || key->dtak_size != size)			continue;		kdata = key->dtak_data;		ASSERT(kdata >= tomax && kdata < tomax + buf->dtb_size);		for (i = sizeof (dtrace_aggid_t); i < size; i++) {			if (kdata[i] != data[i])				goto next;		}		if (action != key->dtak_action) {			/*			 * We are aggregating on the same value in the same			 * aggregation with two different aggregating actions.			 * (This should have been picked up in the compiler,			 * so we may be dealing with errant or devious DIF.)			 * This is an error condition; we indicate as much,			 * and return.			 */			DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);			return;		}		/*		 * This is a hit:  we need to apply the aggregator to		 * the value at this key.		 */		agg->dtag_aggregate((uint64_t *)(kdata + size), arg);		return;next:		continue;	}	/*	 * We didn't find it.  We need to allocate some zero-filled space,	 * link it into the hash table appropriately, and apply the aggregator	 * to the (zero-filled) value.	 */	offs = buf->dtb_offset;	while (offs & (align - 1))		offs += sizeof (uint32_t);	/*	 * If we don't have enough room to both allocate a new key _and_	 * its associated data, increment the drop count and return.	 */	if ((uintptr_t)tomax + offs + fsize >	    agb->dtagb_free - sizeof (dtrace_aggkey_t)) {		dtrace_buffer_drop(buf);		return;	}	/*CONSTCOND*/	ASSERT(!(sizeof (dtrace_aggkey_t) & (sizeof (uintptr_t) - 1)));	key = (dtrace_aggkey_t *)(agb->dtagb_free - sizeof (dtrace_aggkey_t));	agb->dtagb_free -= sizeof (dtrace_aggkey_t);	key->dtak_data = kdata = tomax + offs;	buf->dtb_offset = offs + fsize;	/*	 * Now copy the data across.	 */	*((dtrace_aggid_t *)kdata) = agg->dtag_id;	for (i = sizeof (dtrace_aggid_t); i < size; i++)		kdata[i] = data[i];	for (i = size; i < fsize; i++)		kdata[i] = 0;	key->dtak_hashval = hashval;	key->dtak_size = size;	key->dtak_action = action;	key->dtak_next = agb->dtagb_hash[ndx];	agb->dtagb_hash[ndx] = key;	/*	 * Finally, apply the aggregator.	 */	*((uint64_t *)(key->dtak_data + size)) = agg->dtag_initial;	agg->dtag_aggregate((uint64_t *)(key->dtak_data + size), arg);}/* * Given consumer state, this routine finds a speculation in the INACTIVE * state and transitions it into the ACTIVE state.  If there is no speculation * in the INACTIVE state, 0 is returned.  In this case, no error counter is * incremented -- it is up to the caller to take appropriate action. */static intdtrace_speculation(dtrace_state_t *state){	int i = 0;	dtrace_speculation_state_t current;	uint32_t *stat = &state->dts_speculations_unavail, count;	while (i < state->dts_nspeculations) {		dtrace_speculation_t *spec = &state->dts_speculations[i];		current = spec->dtsp_state;		if (current != DTRACESPEC_INACTIVE) {			if (current == DTRACESPEC_COMMITTINGMANY ||			    current == DTRACESPEC_COMMITTING ||			    current == DTRACESPEC_DISCARDING)				stat = &state->dts_speculations_busy;			i++;			continue;		}		if (dtrace_cas32((uint32_t *)&spec->dtsp_state,		    current, DTRACESPEC_ACTIVE) == current)			return (i + 1);	}	/*	 * We couldn't find a speculation.  If we found as much as a single	 * busy speculation buffer, we'll attribute this failure as "busy"	 * instead of "unavail".	 */	do {		count = *stat;	} while (dtrace_cas32(stat, count, count + 1) != count);	return (0);}/* * This routine commits an active speculation.  If the specified speculation * is not in a valid state to perform a commit(), this routine will silently do * nothing.  The state of the specified speculation is transitioned according * to the state transition diagram outlined in <sys/dtrace_impl.h> */static voiddtrace_speculation_commit(dtrace_state_t *state, processorid_t cpu,    dtrace_specid_t which){	dtrace_speculation_t *spec;	dtrace_buffer_t *src, *dest;	uintptr_t daddr, saddr, dlimit;	dtrace_speculation_state_t current, new;	intptr_t offs;	if (which == 0)		return;	if (which > state->dts_nspeculations) {		cpu_core[cpu].cpuc_dtrace_flags |= CPU_DTRACE_ILLOP;		return;	}	spec = &state->dts_speculations[which - 1];	src = &spec->dtsp_buffer[cpu];	dest = &state->dts_buffer[cpu];	do {		current = spec->dtsp_state;		if (current == DTRACESPEC_COMMITTINGMANY)			break;		switch (current) {		case DTRACESPEC_INACTIVE:		case DTRACESPEC_DISCARDING:			return;		case DTRACESPEC_COMMITTING:			/*			 * This is only possible if we are (a) commit()'ing			 * without having done a prior speculate() on this CPU			 * and (b) racing with another commit() on a different			 * CPU.  There's nothing to do -- we just assert that			 * our offset is 0.			 */			ASSERT(src->dtb_offset == 0);			return;		case DTRACESPEC_ACTIVE:			new = DTRACESPEC_COMMITTING;			break;		case DTRACESPEC_ACTIVEONE:			/*			 * This speculation is active on one CPU.  If our			 * buffer offset is non-zero, we know that the one CPU			 * must be us.  Otherwise, we are committing on a			 * different CPU from the speculate(), and we must			 * rely on being asynchronously cleaned.			 */			if (src->dtb_offset != 0) {				new = DTRACESPEC_COMMITTING;				break;			}			/*FALLTHROUGH*/		case DTRACESPEC_ACTIVEMANY:			new = DTRACESPEC_COMMITTINGMANY;			break;		default:			ASSERT(0);		}	} while (dtrace_cas32((uint32_t *)&spec->dtsp_state,	    current, new) != current);	/*	 * We have set the state to indicate that we are committing this	 * speculation.  Now reserve the necessary space in the destination	 * buffer.	 */	if ((offs = dtrace_buffer_reserve(dest, src->dtb_offset,	    sizeof (uint64_t), state, NULL)) < 0) {		dtrace_buffer_drop(dest);		goto out;	}	/*	 * We have the space; copy the buffer across.  (Note that this is a	 * highly subobtimal bcopy(); in the unlikely event that this becomes	 * a serious performance issue, a high-performance DTrace-specific	 * bcopy() should obviously be invented.)	 */	daddr = (uintptr_t)dest->dtb_tomax + offs;	dlimit = daddr + src->dtb_offset;	saddr = (uintptr_t)src->dtb_tomax;	/*	 * First, the aligned portion.	 */	while (dlimit - daddr >= sizeof (uint64_t)) {		*((uint64_t *)daddr) = *((uint64_t *)saddr);		daddr += sizeof (uint64_t);		saddr += sizeof (uint64_t);	}	/*	 * Now any left-over bit...	 */	while (dlimit - daddr)		*((uint8_t *)daddr++) = *((uint8_t *)saddr++);	/*	 * Finally, commit the reserved space in the destination buffer.	 */	dest->dtb_offset = offs + src->dtb_offset;out:	/*	 * If we're lucky enough to be the only active CPU on this speculation	 * buffer, we can just set the state back to DTRACESPEC_INACTIVE.	 */	if (current == DTRACESPEC_ACTIVE ||	    (current == DTRACESPEC_ACTIVEONE && new == DTRACESPEC_COMMITTING)) {		uint32_t rval = dtrace_cas32((uint32_t *)&spec->dtsp_state,		    DTRACESPEC_COMMITTING, DTRACESPEC_INACTIVE);		ASSERT(rval == DTRACESPEC_COMMITTING);	}	src->dtb_offset = 0;	src->dtb_xamot_drops += src->dtb_drops;	src->dtb_drops = 0;}/* * This routine discards an active speculation.  If the specified speculation * is not in a valid state to perform a discard(), this routine will silently * do nothing.  The state of the specified speculation is transitioned * according to the state transition diagram outlined in <sys/dtrace_impl.h> */static voiddtrace_speculation_discard(dtrace_state_t *state, processorid_t cpu,    dtrace_specid_t which){	dtrace_speculation_t *spec;	dtrace_speculation_state_t current, new;	dtrace_buffer_t *buf;	if (which == 0)		return;	if (which > state->dts_nspeculations) {		cpu_core[cpu].cpuc_dtrace_flags |= CPU_DTRACE_ILLOP;		return;	}	spec = &state->dts_speculations[which - 1];	buf = &spec->dtsp_buffer[cpu];	do {		current = spec->dtsp_state;		switch (current) {		case DTRACESPEC_INACTIVE:		case DTRACESPEC_COMMITTINGMANY:		case DTRACESPEC_COMMITTING:		case DTRACESPEC_DISCARDING:			return;		case DTRACESPEC_ACTIVE:		case DTRACESPEC_ACTIVEMANY:			new = DTRACESPEC_DISCARDING;			break;		case DTRACESPEC_ACTIVEONE:			if (buf->dtb_offset != 0) {				new = DTRACESPEC_INACTIVE;			} else {				new = DTRACESPEC_DISCARDING;			}			break;		default:			ASSERT(0);		}	} while (dtrace_cas32((uint32_t *)&spec->dtsp_state,	    current, new) != current);	buf->dtb_offset = 0;	buf->dtb_drops = 0;}/* * Note:  not called from probe context.  This function is called * asynchronously from cross call context to clean any speculations that are * in the COMMITTINGMANY or DISCARDING states.  These speculations may not be * transitioned back to the INACTIVE state until all CPUs have cleaned the * speculation. */static voiddtrace_speculation_clean_here(dtrace_state_t *state){	dtrace_icookie_t cookie;	processorid_t cpu = CPU->cpu_id;	dtrace_buffer_t *dest = &state->dts_buffer[cpu];	dtrace_specid_t i;	cookie = dtrace_interrupt_disable();	if (dest->dtb_tomax == NULL) {		dtrace_interrupt_enable(cookie);		return;	}	for (i = 0; i < state->dts_nspeculations; i++) {		dtrace_speculation_t *spec = &state->dts_speculations[i];		dtrace_buffer_t *src = &spec->dtsp_buffer[cpu];		if (src->dtb_tomax == NULL)			continue;		if (spec->dtsp_state == DTRACESPEC_DISCARDING) {			src->dtb_offset = 0;			continue;		}		if (spec->dtsp_state != DTRACESPEC_COMMITTINGMANY)			continue;		if (src->dtb_offset == 0)			continue;

⌨️ 快捷键说明

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