Beispiel #1
0
/*
 * timer thread
 *
 * Modes:
 * - clock_nanosleep based
 * - cyclic timer based
 *
 * Clock:
 * - CLOCK_MONOTONIC
 * - CLOCK_REALTIME
 * - CLOCK_MONOTONIC_HR
 * - CLOCK_REALTIME_HR
 *
 */
static void *timerthread(void *param)
{
	struct thread_param *par = param;
	struct sched_param schedp;
	sigset_t sigset;
	struct timespec now, next, interval;
	struct thread_stat *stat = par->stats;
	int policy = par->prio ? SCHED_FIFO : SCHED_OTHER;
	int err;
#ifdef __UNSUPPORTED
	struct itimerval itimer;
	struct sigevent sigev;
	timer_t timer;
	struct itimerspec tspec;
#endif
#if (INGO_TRACE + TGLX_TRACE)
	int stopped = 0;
#endif

	interval.tv_sec = par->interval / USEC_PER_SEC;
	interval.tv_nsec = (par->interval % USEC_PER_SEC) * 1000;

#if INGO_TRACE
	system("echo 1 > /proc/sys/kernel/trace_all_cpus");
	system("echo 1 > /proc/sys/kernel/trace_enabled");
	system("echo 1 > /proc/sys/kernel/trace_freerunning");
	system("echo 0 > /proc/sys/kernel/trace_print_at_crash");
	system("echo 1 > /proc/sys/kernel/trace_user_triggered");
	system("echo 0 > /proc/sys/kernel/trace_user_trigger_irq");
	system("echo 0 > /proc/sys/kernel/trace_verbose");
	system("echo 0 > /proc/sys/kernel/preempt_thresh");
	system("echo 0 > /proc/sys/kernel/wakeup_timing");
	system("echo 0 > /proc/sys/kernel/preempt_max_latency");
#endif

	stat->tid = gettid();

	sigemptyset(&sigset);
	sigaddset(&sigset, par->signal);
	sigprocmask(SIG_BLOCK, &sigset, NULL);

#ifdef __UNSUPPORTED
	if (par->mode == MODE_CYCLIC) {
		sigev.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
		sigev.sigev_signo = par->signal;
		sigev.sigev_notify_thread_id = stat->tid;
		timer_create(par->clock, &sigev, &timer);
		tspec.it_interval = interval;
	}
#endif

	memset(&schedp, 0, sizeof(schedp));
	schedp.sched_priority = par->prio;
	err = pthread_setschedparam(pthread_self(), policy, &schedp);
#ifdef __XENO__
	if (err) {
	    fprintf(stderr, "pthread_setschedparam: %s\n"
		    "(modprobe xeno_posix?)\n", strerror(err));
	    test_shutdown = 1;
	    return (void *) 1;
	}
#endif

	/* Get current time */
	next = start;
	next.tv_sec++;

#ifdef __UNSUPPORTED
	if (par->mode == MODE_CYCLIC) {
		if (par->timermode == TIMER_ABSTIME)
			tspec.it_value = next;
		else {
			tspec.it_value.tv_nsec = 0;
			tspec.it_value.tv_sec = 1;
		}
		timer_settime(timer, par->timermode, &tspec, NULL);
	}

	if (par->mode == MODE_SYS_ITIMER) {
		itimer.it_value.tv_sec = 1;
		itimer.it_value.tv_usec = 0;
		itimer.it_interval.tv_sec = interval.tv_sec;
		itimer.it_interval.tv_usec = interval.tv_nsec / 1000;
		setitimer (ITIMER_REAL,  &itimer, NULL);
	}
#endif

	stat->threadstarted++;

#if (INGO_TRACE + TGLX_TRACE)
	gettimeofday(0,(struct timezone *)1);
#endif

	while (!test_shutdown) {

		long diff;
#ifdef __UNSUPPORTED
		int sigs;
#endif

		/* Wait for next period */
		switch (par->mode) {
#ifdef __UNSUPPORTED
		case MODE_CYCLIC:
		case MODE_SYS_ITIMER:
			if (sigwait(&sigset, &sigs) < 0)
				goto out;
			break;
#endif

		case MODE_CLOCK_NANOSLEEP:
			if (par->timermode == TIMER_ABSTIME)
				clock_nanosleep(par->clock, TIMER_ABSTIME, &next, NULL);
			else {
				clock_gettime(par->clock, &now);
				clock_nanosleep(par->clock, TIMER_RELTIME, &interval, NULL);
				next.tv_sec = now.tv_sec + interval.tv_sec;
				next.tv_nsec = now.tv_nsec + interval.tv_nsec;
				tsnorm(&next);
			}
			break;

#ifdef __UNSUPPORTED
		case MODE_SYS_NANOSLEEP:
			clock_gettime(par->clock, &now);
			nanosleep(&interval, NULL);
			next.tv_sec = now.tv_sec + interval.tv_sec;
			next.tv_nsec = now.tv_nsec + interval.tv_nsec;
			tsnorm(&next);
			break;
#endif
		}
		clock_gettime(par->clock, &now);

		diff = calcdiff(now, next);
		if (diff < stat->min)
			stat->min = diff;
		if (diff > stat->max) {
			stat->max = diff;
#if IPIPE_TRACE
			if (stat->traced)
				xntrace_user_freeze(diff, 0);
#endif
		}
		stat->avg += (double) diff;

#if (INGO_TRACE + TGLX_TRACE)
		if (!stopped && (diff > tracelimit)) {
			stopped++;
			gettimeofday(0,0);
			test_shutdown++;
		}
#endif
		stat->act = diff;
		stat->cycles++;

		if (par->bufmsk)
			stat->values[stat->cycles & par->bufmsk] = diff;

		next.tv_sec += interval.tv_sec;
		next.tv_nsec += interval.tv_nsec;
		tsnorm(&next);

		if (par->max_cycles && par->max_cycles == stat->cycles)
			break;
	}

#ifdef __UNSUPPORTED
out:
	if (par->mode == MODE_CYCLIC)
		timer_delete(timer);

	if (par->mode == MODE_SYS_ITIMER) {
		itimer.it_value.tv_sec = 0;
		itimer.it_value.tv_usec = 0;
		itimer.it_interval.tv_sec = 0;
		itimer.it_interval.tv_usec = 0;
		setitimer (ITIMER_REAL,  &itimer, NULL);
	}
#endif

	/* switch to normal */
	schedp.sched_priority = 0;
	pthread_setschedparam(pthread_self(), SCHED_OTHER, &schedp);

	stat->threadstarted = -1;

	return NULL;
}
Beispiel #2
0
/*
** calculate the process-activity during the last sample
*/
int
deviattask(struct tstat *curtpres, int ntaskpres,
           struct tstat *curpexit, int nprocexit, int deviatonly,
	   struct tstat *devtstat, struct sstat *devsstat,
           unsigned int *nprocdev, int *nprocpres,
           int *totrun, int *totslpi, int *totslpu, int *totzombie)
{
	register int		c, d;
	register struct tstat	*curstat, *devstat, *procstat = 0;
	struct tstat		prestat;
	struct pinfo		*pinfo;
	count_t			totusedcpu;
	char			procsaved = 1, hashtype = 'p';

	/*
	** needed for sanity check later on...
	*/
	totusedcpu	= devsstat->cpu.all.stime + devsstat->cpu.all.utime +
			  devsstat->cpu.all.ntime + devsstat->cpu.all.itime +
			  devsstat->cpu.all.wtime + devsstat->cpu.all.Itime +
			  devsstat->cpu.all.Stime + devsstat->cpu.all.steal;

	/*
	** make new list of all tasks in the process-database;
	** after handling all processes, the left-overs are processes
	** that have disappeared since the previous sample
	*/
	pdb_makeresidue();

	/*
	** calculate deviations per present process
	*/
	*nprocpres = *totrun = *totslpi = *totslpu = *totzombie = 0;

	for (c=0, d=0, *nprocdev=0; c < ntaskpres; c++)
	{
		char	newtask = 0;

		curstat = curtpres+c;

		if (curstat->gen.isproc)
		{
			(*nprocpres)++;

			if (curstat->gen.state == 'Z')
			{
				(*totzombie)++;
			}
			else
			{
				*totrun		+= curstat->gen.nthrrun;
				*totslpi	+= curstat->gen.nthrslpi;
				*totslpu	+= curstat->gen.nthrslpu;
			}
		}

		/*
		** get previous figures from task-database
		*/
		if ( pdb_gettask(curstat->gen.pid, curstat->gen.isproc,
		                 curstat->gen.btime, &pinfo))
		{
			/*
			** task already present during the previous sample;
			** if no differences with previous sample, skip task
			** unless all tasks have to be shown
			**
			** it might be that a process appears to have no
			** differences while one its threads has differences;
			** than the process will be inserted as well
			*/
			if (deviatonly && memcmp(curstat, &pinfo->tstat, 
					           sizeof(struct tstat)) == EQ)
			{
				/* remember last unsaved process */
				if (curstat->gen.isproc)
				{
					procstat  = curstat;
					procsaved = 0;
				}

				continue;
			}

			/*
			** differences detected, so the task was active,
		        ** or its status or memory-occupation has changed;
			** save stats from previous sample (to use for
			** further calculations) and store new statistics
			** in task-database
			*/
			prestat 	= pinfo->tstat;	/* save old	*/
			pinfo->tstat 	= *curstat;	/* overwrite	*/
		}
		else
		{
			/*
			** new task which must have been started during
			** last interval
			*/
			memset(&prestat, 0, sizeof(prestat));

			/*
			** create new task struct
			*/
			pinfo = calloc(1, sizeof(struct pinfo));

			ptrverify(pinfo, "Malloc failed for new pinfo\n");

			pinfo->tstat = *curstat;

			/*
			** add new task to task-database
			*/
			pdb_addtask(curstat->gen.pid, pinfo);

			newtask = 1;
		}

		/*
		** active task found; do the difference calculations
		*/
		if (curstat->gen.isproc)
		{
			procsaved = 1;
			(*nprocdev)++;
		}
		else
		{
			/*
			** active thread: check if related process registered
			*/
			if (!procsaved)
			{
				devstat = devtstat+d;
				calcdiff(devstat, procstat, procstat, 0,
								totusedcpu);
				procsaved = 1;
				(*nprocdev)++;
				d++;
			}
		}

		devstat = devtstat+d;

		calcdiff(devstat, curstat, &prestat, newtask, totusedcpu);
		d++;
	}

	/*
	** calculate deviations per exited process
	*/
	if (nprocexit > 0 && supportflags&NETATOPD)
	{
		if (curpexit->gen.pid)
			hashtype = 'p';
		else
			hashtype = 'b';

		netatop_exithash(hashtype);
	}

	for (c=0; c < nprocexit; c++)
	{
		/*
		** check if this process has been started AND
		** finished since previous sample;
		** if so, it has no use to check if there is still 
		** existing info present in the process-database
		*/
		curstat = curpexit+c;

		if (curstat->gen.pid)	/* acctrecord contains pid? */
		{
			if ( pdb_gettask(curstat->gen.pid, 1,
			                 curstat->gen.btime, &pinfo))
					prestat = pinfo->tstat;
				else
					memset(&prestat, 0, sizeof(prestat));
		}
		else
		{
			if ( curstat->gen.btime > pretime.tv_sec )
			{
				/*
				** process-start and -finish in same interval
				*/
				memset(&prestat, 0, sizeof(prestat));
			}
			else
			{
				/*
				** process must be known in process-database;
				** try to match one of the remaining processes
				** against this exited one
				*/
				if ( pdb_srchresidue(curstat, &pinfo) )
					prestat = pinfo->tstat;
				else
					memset(&prestat, 0, sizeof(prestat));
		 	}
		}

		/*
		** now do the calculations
		*/
		devstat = devtstat+d;
		memset(devstat, 0, sizeof *devstat);

		devstat->gen        = curstat->gen;

		if ( curstat->gen.pid == 0 )
			devstat->gen.pid    = prestat.gen.pid;

		if (!prestat.gen.pid)
			devstat->gen.excode |= ~(INT_MAX);

		strcpy(devstat->gen.cmdline, prestat.gen.cmdline);

		/*
		** due to the strange exponent-type storage of values
		** in the process accounting record, the resource-value
		** in the exit-record might have been smaller than the
		** stored value of the last registered sample; in that
		** case the deviation should be set to zero
		*/
		if (curstat->cpu.stime > prestat.cpu.stime)
			devstat->cpu.stime  = curstat->cpu.stime -
			                      prestat.cpu.stime;

		if (curstat->cpu.utime > prestat.cpu.utime)
			devstat->cpu.utime  = curstat->cpu.utime -
			                      prestat.cpu.utime;

		if (curstat->mem.minflt > prestat.mem.minflt)
			devstat->mem.minflt = curstat->mem.minflt - 
			                      prestat.mem.minflt;

		if (curstat->mem.majflt > prestat.mem.majflt)
			devstat->mem.majflt = curstat->mem.majflt -
			                      prestat.mem.majflt;

		if (curstat->dsk.rio > (prestat.dsk.rio + prestat.dsk.wio))
			devstat->dsk.rio    = curstat->dsk.rio  -
			                      prestat.dsk.rio   -
			                      prestat.dsk.wio;

		/*
		** try to match the network counters of netatop
		*/
		if (supportflags & NETATOPD)
		{
			unsigned long	val = (hashtype == 'p' ?
						curstat->gen.pid :
						curstat->gen.btime);

			netatop_exitfind(val, devstat, &prestat);
		}
		d++;
		(*nprocdev)++;

		if (prestat.gen.pid > 0)
			pdb_deltask(prestat.gen.pid, prestat.gen.isproc);
	}

	/*
	** remove unused entries from RESIDUE chain
	*/
	pdb_cleanresidue();

	return d;
}
/*
 * signal thread
 *
 */
void *signalthread(void *param)
{
	struct thread_param *par = param;
	struct sched_param schedp;
	sigset_t sigset;
	struct timespec before, after;
	struct thread_stat *stat = par->stats;
	int policy = par->prio ? SCHED_FIFO : SCHED_OTHER;
	int stopped = 0;
	int first = 1;

	if (tracelimit) {
		do_system("echo 1 > /proc/sys/kernel/trace_all_cpus");
		do_system("echo 1 > /proc/sys/kernel/trace_freerunning");
		do_system("echo 0 > /proc/sys/kernel/trace_print_at_crash");
		do_system("echo 1 > /proc/sys/kernel/trace_user_triggered");
		do_system("echo -1 > /proc/sys/kernel/trace_user_trigger_irq");
		do_system("echo 0 > /proc/sys/kernel/trace_verbose");
		do_system("echo 0 > /proc/sys/kernel/preempt_thresh");
		do_system("echo 0 > /proc/sys/kernel/wakeup_timing");
		do_system("echo 0 > /proc/sys/kernel/preempt_max_latency");
		if (ftrace)
			do_system("echo 1 > /proc/sys/kernel/mcount_enabled");

		do_system("echo 1 > /proc/sys/kernel/trace_enabled");
	}

	stat->tid = gettid();

	sigemptyset(&sigset);
	sigaddset(&sigset, par->signal);
	sigprocmask(SIG_BLOCK, &sigset, NULL);

	memset(&schedp, 0, sizeof(schedp));
	schedp.sched_priority = par->prio;
	sched_setscheduler(0, policy, &schedp);

	stat->threadstarted++;

	if (tracelimit) {
		if (oldtrace)
			gettimeofday(NULL, (struct timezone *)1);
		else
			prctl(0, 1);
	}

	clock_gettime(CLOCK_MONOTONIC, &before);

	while (!shutdown) {
		struct timespec now;
		long diff;
		int sigs;

		if (sigwait(&sigset, &sigs) < 0)
			goto out;

		clock_gettime(CLOCK_MONOTONIC, &after);

		/*
		 * If it is the first thread, sleep after every 16
		 * round trips.
		 */
		if (!par->id && !(stat->cycles & 0x0F))
			usleep(10000);

		/* Get current time */
		clock_gettime(CLOCK_MONOTONIC, &now);
		pthread_kill(stat->tothread, SIGUSR1);

		/* Skip the first cycle */
		if (first) {
			first = 0;
			before = now;
			continue;
		}

		diff = calcdiff(after, before);
		before = now;
		if (diff < stat->min)
			stat->min = diff;
		if (diff > stat->max)
			stat->max = diff;
		stat->avg += (double) diff;

		if (!stopped && tracelimit && (diff > tracelimit)) {
			stopped++;
			if (oldtrace)
				gettimeofday(NULL, NULL);
			else
				prctl(0, 0);
			shutdown++;
		}
		stat->act = diff;
		stat->cycles++;

		if (par->bufmsk)
			stat->values[stat->cycles & par->bufmsk] = diff;

		if (par->max_cycles && par->max_cycles == stat->cycles)
			break;
	}

out:
	/* switch to normal */
	schedp.sched_priority = 0;
	sched_setscheduler(0, SCHED_OTHER, &schedp);

	stat->threadstarted = -1;

	return NULL;
}