MINI SHELL

Server : Apache/2.2.2 (Fedora)
System : Linux App1.pathumtani.go.th 2.6.20-1.2320.fc5smp #1 SMP Tue Jun 12 19:40:16 EDT 2007 i686
User : apache ( 48)
PHP Version : 5.2.9
Disable Function : NONE
Directory :  /usr/share/systemtap/runtime/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : //usr/share/systemtap/runtime/stat.c
/* -*- linux-c -*-
 * Statistics Aggregation
 * Copyright (C) 2005 Red Hat Inc.
 * Copyright (C) 2006 Intel Corporation
 *
 * This file is part of systemtap, and is free software.  You can
 * redistribute it and/or modify it under the terms of the GNU General
 * Public License (GPL); either version 2, or (at your option) any
 * later version.
 */
#ifndef _STAT_C_
#define _STAT_C_

/** @file stat.c
 * @brief Statistics Aggregation
 */
/** @addtogroup stat Statistics Aggregation
 * The Statistics aggregations keep per-cpu statistics. You
 * must create all aggregations at probe initialization and it is
 * best to not read them until probe exit. If you must read them
 * while probes are running, the values may be slightly off due
 * to a probe updating the statistics of one cpu while another cpu attempts
 * to read the same data. This will also negatively impact performance.
 *
 * If you have a need to poll Stat data while probes are running, and
 * you want to be sure the data is accurate, you can do
 * @verbatim
#define NEED_STAT_LOCKS 1
@endverbatim
 * This will insert per-cpu spinlocks around all accesses to Stat data, 
 * which will reduce performance some.
 *
 * Stats keep track of count, sum, min and max. Average is computed
 * from the sum and count when required. Histograms are optional.
 * If you want a histogram, you must set "type" to HIST_LOG
 * or HIST_LINEAR when you call _stp_stat_init().
 *
 * @{
 */

#include "stat-common.c"

/* for the paranoid. */
#if NEED_STAT_LOCKS == 1
#define STAT_LOCK(st) spin_lock(&st->lock)
#define STAT_UNLOCK(st) spin_unlock(&st->lock)
#else
#define STAT_LOCK(st) ;
#define STAT_UNLOCK(st) ;
#endif

/** Stat struct for stat.c. Maps do not need this */
struct _Stat {
	struct _Hist hist;
	/* per-cpu data. allocated with alloc_percpu() */
	stat *sd;
	/* aggregated data */   
	stat *agg;  
};

typedef struct _Stat *Stat;


/** Initialize a Stat.
 * Call this during probe initialization to create a Stat.
 *
 * @param type HIST_NONE, HIST_LOG, or HIST_LINEAR
 *
 * For HIST_LOG, the following additional parametrs are required:
 * @param buckets - An integer specifying the number of buckets.
 *
 * For HIST_LINEAR, the following additional parametrs are required:
 * @param start - An integer. The start of the histogram.
 * @param stop - An integer. The stopping value. Should be > start.
 * @param interval - An integer. The interval. 
 */
Stat _stp_stat_init (int type, ...)
{
	int size, buckets=0, start=0, stop=0, interval=0;
	stat *sd, *agg;
	Stat st;

	if (type != HIST_NONE) {
		va_list ap;
		va_start (ap, type);
		
		if (type == HIST_LOG) {
			buckets = va_arg(ap, int);
		} else {
			start = va_arg(ap, int);
			stop = va_arg(ap, int);
			interval = va_arg(ap, int);
			/* FIXME. check interval != 0 and not too large */
			buckets = (stop - start) / interval;
			if ((stop - start) % interval) buckets++;
		}
		va_end (ap);
	}
	st = (Stat) kmalloc (sizeof(struct _Stat), GFP_KERNEL);
	if (st == NULL)
		return NULL;
	
	size = buckets * sizeof(int64_t) + sizeof(stat);	
	sd = (stat *) _stp_alloc_percpu (size);
	if (sd == NULL)
		goto exit1;

#if NEED_STAT_LOCKS == 1
	{
		int i;
		for_each_cpu(i) {
			stat *sdp = per_cpu_ptr (sd, i);
			sdp->lock = SPIN_LOCK_UNLOCKED;
		}
	}
#endif
	
	agg = (stat *)kmalloc (size, GFP_KERNEL);
	if (agg == NULL)
		goto exit2;

	st->hist.type = type;
	st->hist.start = start;
	st->hist.stop = stop;
	st->hist.interval = interval;
	st->hist.buckets = buckets;
	st->sd = sd;
	st->agg = agg;
	return st;

exit2:
	kfree (sd);
exit1:
	kfree (st);
	return NULL;
}

/** Delete Stat.
 * Call this to free all memory allocated during initialization.
 *
 * @param st Stat
 */
void _stp_stat_del (Stat st)
{
	if (st) {
		_stp_free_percpu (st->sd);
		kfree (st->agg);
		kfree (st);
	}
}
	
/** Add to a Stat.
 * Add an int64 to a Stat.
 *
 * @param st Stat
 * @param val Value to add
 */
void _stp_stat_add (Stat st, int64_t val)
{
	stat *sd = per_cpu_ptr (st->sd, get_cpu());
	STAT_LOCK(sd);
	__stp_stat_add (&st->hist, sd, val);
	STAT_UNLOCK(sd);
	put_cpu();
}

/** Get per-cpu Stats.
 * Gets the Stats for a specific CPU.
 *
 * If NEED_STAT_LOCKS is set, you MUST call STAT_UNLOCK()
 * when you are finished with the returned pointer.
 *
 * @param st Stat
 * @param cpu CPU number
 * @returns A pointer to a stat.
 */
stat *_stp_stat_get_cpu (Stat st, int cpu)
{
	stat *sd = per_cpu_ptr (st->sd, cpu);
	STAT_LOCK(sd);
	return sd;
}

static void _stp_stat_clear_data (Stat st, stat *sd)
{
        int j;
        sd->count = sd->sum = sd->min = sd->max = 0;
        if (st->hist.type != HIST_NONE) {
                for (j = 0; j < st->hist.buckets; j++)
                        sd->histogram[j] = 0;
        }
}

/** Get Stats.
 * Gets the aggregated Stats for all CPUs.
 *
 * If NEED_STAT_LOCKS is set, you MUST call STAT_UNLOCK()
 * when you are finished with the returned pointer.
 *
 * @param st Stat
 * @param clear Set if you want the data cleared after the read. Useful
 * for polling.
 * @returns A pointer to a stat.
 */
stat *_stp_stat_get (Stat st, int clear)
{
	int i, j;
	stat *agg = st->agg;
	STAT_LOCK(agg);
	_stp_stat_clear_data (st, agg);

	for_each_cpu(i) {
		stat *sd = per_cpu_ptr (st->sd, i);
		STAT_LOCK(sd);
		if (sd->count) {
			if (agg->count == 0) {
				agg->min = sd->min;
				agg->max = sd->max;
			}
			agg->count += sd->count;
			agg->sum += sd->sum;
			if (sd->max > agg->max)
				agg->max = sd->max;
			if (sd->min < agg->min)
				agg->min = sd->min;
			if (st->hist.type != HIST_NONE) {
				for (j = 0; j < st->hist.buckets; j++)
					agg->histogram[j] += sd->histogram[j];
			}
			if (clear)
				_stp_stat_clear_data (st, sd);
		}
		STAT_UNLOCK(sd);
	}
	return agg;
}


static void __stp_stat_print (char *fmt, Stat st, stat *sd, int cpu)
{
	int num;
	char *f = (char *)fmt;
	while (*f) {
		f = next_fmt (f, &num);
		_stp_stat_print_valtype (f, &st->hist, sd, cpu);
		if (*f)
			f++;
	}
	_stp_print_cstr ("\n");
	_stp_print_flush();	
}

/** Print per-cpu Stats.
 * Prints the Stats for each CPU.
 *
 * @param st Stat
 * @param fmt @ref format_string
 * @param clear Set if you want the data cleared after the read. Useful
 * for polling.
 */
void _stp_stat_print_cpu (Stat st, char *fmt, int clear)
{
	int i;
	for_each_cpu(i) {
		stat *sd = per_cpu_ptr (st->sd, i);
		STAT_LOCK(sd);
		__stp_stat_print (fmt, st, sd, i);
		if (clear)
			_stp_stat_clear_data (st, sd);
		STAT_UNLOCK(sd);
	}
}

/** Print Stats.
 * Prints the Stats.
 *
 * @param st Stat
 * @param fmt @ref format_string
 * @param clear Set if you want the data cleared after the read. Useful
 * for polling.
 */
void _stp_stat_print (Stat st, char *fmt, int clear)
{
	stat *agg = _stp_stat_get(st, clear);
	__stp_stat_print (fmt, st, agg, 0);
	STAT_UNLOCK(agg);
}

/** Clear Stats.
 * Clears the Stats.
 *
 * @param st Stat
 */
void _stp_stat_clear (Stat st)
{
	int i;
	for_each_cpu(i) {
		stat *sd = per_cpu_ptr (st->sd, i);
		STAT_LOCK(sd);
		_stp_stat_clear_data (st, sd);
		STAT_UNLOCK(sd);
	}
}
/** @} */
#endif /* _STAT_C_ */


Anon7 - 2021