Exemplo n.º 1
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;
}
Exemplo n.º 2
0
Arquivo: atop.c Projeto: ryandoyle/pcp
/*
** The engine() drives the main-loop of the program
*/
void
engine(void)
{
	int 			i, j;
	struct sigaction 	sigact;
	double 			timed, delta;
	void			getusr1(int), getusr2(int);

	/*
	** reserve space for system-level statistics
	*/
	static struct sstat	*cursstat; /* current   */
	static struct sstat	*presstat; /* previous  */
	static struct sstat	*devsstat; /* deviation */
	static struct sstat	*hlpsstat;

	/*
	** reserve space for task-level statistics
	*/
	static struct tstat	*curtpres;	/* current present list      */
	static int		 curtlen;	/* size of present list      */

	struct tstat		*curpexit;	/* exited process list	     */
	struct tstat		*devtstat;	/* deviation list	     */
	struct tstat		**devpstat;	/* pointers to processes     */
						/* in deviation list         */

	unsigned int		ntaskpres;	/* number of tasks present   */
	unsigned int		nprocexit;	/* number of exited procs    */
	unsigned int		nprocexitnet;	/* number of exited procs    */
						/* via netatopd daemon       */
	unsigned int		ntaskdev;       /* nr of tasks deviated      */
	unsigned int		nprocdev;       /* nr of procs deviated      */
	int			nprocpres;	/* nr of procs present       */
	int			totrun, totslpi, totslpu, totzombie;
	unsigned int		noverflow;

	/*
	** initialization: allocate required memory dynamically
	*/
	cursstat = sstat_alloc("current sysstats");
	presstat = sstat_alloc("prev    sysstats");
	devsstat = sstat_alloc("deviate sysstats");

	curtlen  = PROCMIN * 3 / 2;	/* add 50% for threads */
	curtpres = calloc(curtlen, sizeof(struct tstat));
	ptrverify(curtpres, "Malloc failed for %d procstats\n", curtlen);

	/*
	** install the signal-handler for ALARM, USR1 and USR2 (triggers
	** for the next sample)
	*/
	memset(&sigact, 0, sizeof sigact);
	sigact.sa_handler = getusr1;
	sigaction(SIGUSR1, &sigact, (struct sigaction *)0);

	memset(&sigact, 0, sizeof sigact);
	sigact.sa_handler = getusr2;
	sigaction(SIGUSR2, &sigact, (struct sigaction *)0);

	memset(&sigact, 0, sizeof sigact);
	sigact.sa_handler = getalarm;
	sigaction(SIGALRM, &sigact, (struct sigaction *)0);

	if (interval.tv_sec || interval.tv_usec)
		setalarm(&interval);

	/*
	** MAIN-LOOP:
	**    -	Wait for the requested number of seconds or for other trigger
	**
	**    -	System-level counters
	**		get current counters
	**		calculate the differences with the previous sample
	**
	**    -	Process-level counters
	**		get current counters from running & exited processes
	**		calculate the differences with the previous sample
	**
	**    -	Call the print-function to visualize the differences
	*/
	for (sampcnt=0; sampcnt < nsamples; sampcnt++)
	{
		char	lastcmd;

		/*
		** wait for alarm-signal to arrive (except first sample)
		** or wait for SIGUSR1/SIGUSR2
		*/
		if (sampcnt > 0 && awaittrigger && !rawreadflag)
			pause();

		awaittrigger = 1;

		/*
		** take a snapshot of the current system-level statistics 
		*/
		hlpsstat = cursstat;	/* swap current/prev. stats */
		cursstat = presstat;
		presstat = hlpsstat;

		photosyst(cursstat);	/* obtain new counters     */

		/*
		** take a snapshot of the current task-level statistics 
		**
		** first register active tasks
		**  --> atop malloc's a minimal amount of space which is
		**      only extended when needed
		*/
		memset(curtpres, 0, curtlen * sizeof(struct tstat));

		ntaskpres = photoproc(&curtpres, &curtlen);

		/*
		** register processes that exited during last sample;
		** first determine how many processes exited
		**
		** the number of exited processes is limited to avoid
		** that atop explodes in memory and introduces OOM killing
		*/
		nprocexit = acctprocnt();	/* number of exited processes */

		if (nprocexit > MAXACCTPROCS)
		{
			noverflow = nprocexit - MAXACCTPROCS;
			nprocexit = MAXACCTPROCS;
		}
		else
			noverflow = 0;

		/*
		** determine how many processes have been exited
		** for the netatop module (only processes that have
		** used the network)
		*/
		if (nprocexit > 0 && (supportflags & NETATOPD))
			nprocexitnet = netatop_exitstore();
		else
			nprocexitnet = 0;

		/*
		** reserve space for the exited processes and read them
		*/
		if (nprocexit > 0)
		{
			curpexit = malloc(nprocexit * sizeof(struct tstat));

			ptrverify(curpexit,
			          "Malloc failed for %d exited processes\n",
			          nprocexit);

			memset(curpexit, 0, nprocexit * sizeof(struct tstat));

			nprocexit = acctphotoproc(curpexit, nprocexit);

			/*
 			** reposition offset in accounting file when not
			** all exited processes have been read (i.e. skip
			** those processes)
			*/
			if (noverflow)
				acctrepos(noverflow);
		}
		else
		{
			curpexit    = NULL;
		}

		/*
		** calculate the deviations (i.e. calculate the activity
		** during the last sample).  Note for PMAPI calls we had
		** to delay changing curtime until after sampling due to
		** the way pmSetMode(3) works.
		*/
		pretime  = curtime;	/* timestamp for previous sample */
		curtime  = cursstat->stamp; /* timestamp for this sample */
		timed = __pmtimevalToReal(&curtime);
		delta = timed - __pmtimevalToReal(&pretime);

		deviatsyst(cursstat, presstat, devsstat, delta);

		devtstat = malloc((ntaskpres+nprocexit) * sizeof(struct tstat));

		ptrverify(devtstat, "Malloc failed for %d modified tasks\n",
			          			ntaskpres+nprocexit);

		ntaskdev = deviattask(curtpres,  ntaskpres,
		                      curpexit,  nprocexit, deviatonly,
		                      devtstat,  devsstat,
		                      &nprocdev, &nprocpres,
		                      &totrun, &totslpi, &totslpu, &totzombie);

  	      	/*
 		** create list of pointers specifically to the process entries
		** in the task list
		*/
       		devpstat = malloc(sizeof (struct tstat *) * nprocdev);

		ptrverify(devpstat, "Malloc failed for %d process ptrs\n",
			          				nprocdev);

		for (i=0, j=0; i < ntaskdev; i++)
		{
			if ( (devtstat+i)->gen.isproc)
				devpstat[j++] = devtstat+i;
		}

		/*
		** activate the installed print-function to visualize
		** the deviations
		*/
		lastcmd = (vis.show_samp)(timed,
				     delta > 1.0 ? delta : 1.0,
		           	     devsstat,  devtstat, devpstat,
		                     ntaskdev,  ntaskpres, nprocdev, nprocpres, 
		                     totrun, totslpi, totslpu, totzombie, 
		                     nprocexit, noverflow, sampcnt==0);

		if (rawreadflag)
			__pmtimevalInc(&curtime, &interval);

		/*
		** release dynamically allocated memory
		*/
		if (nprocexit > 0)
			free(curpexit);

		if (nprocexitnet > 0)
			netatop_exiterase();

		free(devtstat);
		free(devpstat);

		if (lastcmd == 'r')	/* reset requested ? */
		{
			sampcnt = -1;

			curtime = origin;

			/* set current (will be 'previous') counters to 0 */
			memset(curtpres, 0, curtlen * sizeof(struct tstat));
			sstat_reset(cursstat);

			/* remove all tasks in database */
			pdb_makeresidue();
			pdb_cleanresidue();
		}
	} /* end of main-loop */
}
Exemplo n.º 3
0
/*
** The engine() drives the main-loop of the program
*/
static void
engine(void)
{
	int 			i, j;
	struct sigaction 	sigact;
	static time_t		timelimit;
	void			getusr1(int), getusr2(int);

	/*
	** reserve space for system-level statistics
	*/
	static struct sstat	*cursstat; /* current   */
	static struct sstat	*presstat; /* previous  */
	static struct sstat	*devsstat; /* deviation */
	static struct sstat	*hlpsstat;

	/*
	** reserve space for task-level statistics
	*/
	static struct tstat	*curpact;	/* current active list  */
	static int		curplen;	/* current active size  */

	struct tstat		*curpexit;	/* exited process list	*/
	struct tstat		*devtstat;	/* deviation list	*/
	struct tstat		**devpstat;	/* pointers to processes*/
						/* in deviation list    */

	unsigned int		ntask, nexit, nexitnet;
	unsigned int		noverflow, ndeviat, nactproc;
	int			totproc, totrun, totslpi, totslpu, totzombie;

	/*
	** initialization: allocate required memory dynamically
	*/
	cursstat = calloc(1, sizeof(struct sstat));
	presstat = calloc(1, sizeof(struct sstat));
	devsstat = calloc(1, sizeof(struct sstat));

	curplen  = countprocs() * 3 / 2;	/* add 50% for threads */
	curpact  = calloc(curplen, sizeof(struct tstat));

	ptrverify(cursstat, "Malloc failed for current sysstats\n");
	ptrverify(presstat, "Malloc failed for prev    sysstats\n");
	ptrverify(devsstat, "Malloc failed for deviate sysstats\n");
	ptrverify(curpact,  "Malloc failed for %d procstats\n", curplen);

	/*
	** install the signal-handler for ALARM, USR1 and USR2 (triggers
	* for the next sample)
	*/
	memset(&sigact, 0, sizeof sigact);
	sigact.sa_handler = getusr1;
	sigaction(SIGUSR1, &sigact, (struct sigaction *)0);

	memset(&sigact, 0, sizeof sigact);
	sigact.sa_handler = getusr2;
	sigaction(SIGUSR2, &sigact, (struct sigaction *)0);

	memset(&sigact, 0, sizeof sigact);
	sigact.sa_handler = getalarm;
	sigaction(SIGALRM, &sigact, (struct sigaction *)0);

	if (interval > 0)
		alarm(interval);

	if (midnightflag)
	{
		time_t		timenow = time(0);
		struct tm	*tp = localtime(&timenow);

		tp->tm_hour = 23;
		tp->tm_min  = 59;
		tp->tm_sec  = 59;

		timelimit = mktime(tp);
	}

	/*
	** MAIN-LOOP:
	**    -	Wait for the requested number of seconds or for other trigger
	**
	**    -	System-level counters
	**		get current counters
	**		calculate the differences with the previous sample
	**
	**    -	Process-level counters
	**		get current counters from running & exited processes
	**		calculate the differences with the previous sample
	**
	**    -	Call the print-function to visualize the differences
	*/
	for (sampcnt=0; sampcnt < nsamples; sampcnt++)
	{
		char	lastcmd;

		/*
		** if the limit-flag is specified:
		**  check if the next sample is expected before midnight;
		**  if not, stop atop now 
		*/
		if (midnightflag && (curtime+interval) > timelimit)
			break;

		/*
		** wait for alarm-signal to arrive (except first sample)
		** or wait for SIGUSR1/SIGUSR2
		*/
		if (sampcnt > 0 && awaittrigger)
			pause();

		awaittrigger = 1;

		/*
		** gather time info for this sample
		*/
		pretime  = curtime;
		curtime  = time(0);		/* seconds since 1-1-1970 */

		/*
		** take a snapshot of the current system-level statistics 
		** and calculate the deviations (i.e. calculate the activity
		** during the last sample)
		*/
		hlpsstat = cursstat;	/* swap current/prev. stats */
		cursstat = presstat;
		presstat = hlpsstat;

		photosyst(cursstat);	/* obtain new counters      */

		deviatsyst(cursstat, presstat, devsstat);

		/*
		** take a snapshot of the current task-level statistics 
		** and calculate the deviations (i.e. calculate the activity
		** during the last sample)
		**
		** first register active tasks
		**  --> atop malloc's a minimal amount of space which is
		**      only extended when needed
		*/
		memset(curpact, 0, curplen * sizeof(struct tstat));

		while ( (ntask = photoproc(curpact, curplen)) == curplen)
		{
			curplen += PROCCHUNK;

			curpact = realloc(curpact,
					curplen * sizeof(struct tstat));

			ptrverify(curpact,
			          "Realloc failed for %d tasks\n", curplen);

			memset(curpact, 0, curplen * sizeof(struct tstat));
		}

		/*
		** register processes that exited during last sample;
		** first determine how many processes exited
		**
		** the number of exited processes is limited to avoid
		** that atop explodes in memory and introduces OOM killing
		*/
		nexit = acctprocnt();	/* number of exited processes */

		if (nexit > MAXACCTPROCS)
		{
			noverflow = nexit - MAXACCTPROCS;
			nexit     = MAXACCTPROCS;
		}
		else
			noverflow = 0;

		/*
		** determine how many processes have been exited
		** for the netatop module (only processes that have
		** used the network)
		*/
		if (nexit > 0 && (supportflags & NETATOPD))
			nexitnet = netatop_exitstore();
		else
			nexitnet = 0;

		/*
		** reserve space for the exited processes and read them
		*/
		if (nexit > 0)
		{
			curpexit = malloc(nexit * sizeof(struct tstat));

			ptrverify(curpexit,
			          "Malloc failed for %d exited processes\n",
			          nexit);

			memset(curpexit, 0, nexit * sizeof(struct tstat));

			acctphotoproc(curpexit, nexit);

			/*
 			** reposition offset in accounting file when not
			** all exited processes have been read (i.e. skip
			** those processes)
			*/
			if (noverflow)
				acctrepos(noverflow);
		}
		else
		{
			curpexit    = NULL;
		}

		/*
		** calculate deviations
		*/
		devtstat = malloc((ntask+nexit) * sizeof(struct tstat));

		ptrverify(devtstat, "Malloc failed for %d modified processes\n",
			          				ntask+nexit);

		ndeviat = deviatproc(curpact, ntask, curpexit, nexit, 
				deviatonly, devtstat, devsstat, &nactproc,
				&totproc, &totrun, &totslpi, &totslpu, 
		                &totzombie);

  	      	/*
 		** create list of pointers specifically to the process entries
		** in the task list
		*/
       		devpstat = malloc(sizeof (struct tstat *) * nactproc);

		ptrverify(devpstat, "Malloc failed for %d process ptrs\n",
			          				nactproc);

		for (i=0, j=0; i < ndeviat; i++)
		{
			if ( (devtstat+i)->gen.isproc)
				devpstat[j++] = devtstat+i;
		}

		/*
		** activate the installed print-function to visualize
		** the deviations
		*/
		lastcmd = (vis.show_samp)( curtime,
				     curtime-pretime > 0 ? curtime-pretime : 1,
		           	     devsstat, devtstat, devpstat,
		                     ndeviat, ntask, nactproc,
		                     totproc, totrun, totslpi, totslpu,
		                     totzombie, nexit, noverflow, sampcnt==0);

		/*
		** release dynamically allocated memory
		*/
		if (nexit > 0)
			free(curpexit);

		if (nexitnet > 0)
			netatop_exiterase();

		free(devtstat);
		free(devpstat);

		if (lastcmd == 'r')	/* reset requested ? */
		{
			sampcnt = -1;

			curtime = getboot() / hertz;	// reset current time

			/* set current (will be 'previous') counters to 0 */
			memset(cursstat, 0,           sizeof(struct sstat));
			memset(curpact,  0, curplen * sizeof(struct tstat));

			/* remove all tasks in database */
			pdb_makeresidue();
			pdb_cleanresidue();
		}
	} /* end of main-loop */
}
Exemplo n.º 4
0
/*
** The engine() drives the main-loop of the program
*/
static void
engine(void)
{
	struct sigaction 	sigact;
	static time_t		timelimit;
	void			getusr1(int), getusr2(int);

	/*
	** reserve space for system-level statistics
	*/
	static struct sstat	*cursstat; /* current   */
	static struct sstat	*presstat; /* previous  */
	static struct sstat	*devsstat; /* deviation */
	static struct sstat	*hlpsstat;

	/*
	** reserve space for process-level statistics
	*/
	static struct pstat	*curpact;	/* current active list  */
	static int		curplen;	/* current active size  */

	struct pstat		*curpexit;	/* exitted process list	*/
	struct pstat		*devpstat;	/* deviation list	*/

	int			npresent, nexit, n;
	int			ntrun, ntslpi, ntslpu, nzombie;

	/*
	** initialization: allocate required memory dynamically
	*/
	cursstat = calloc(1, sizeof(struct sstat));
	presstat = calloc(1, sizeof(struct sstat));
	devsstat = calloc(1, sizeof(struct sstat));

	curplen = countprocs() + PROCCHUNK;
	curpact = calloc(curplen, sizeof(struct pstat));

	if (!cursstat || !presstat || !devsstat || !curpact)
	{
		fprintf(stderr, "unexpected calloc-failure...\n");
		cleanstop(1);
	}

	/*
	** install the signal-handler for ALARM, USR1 and USR2 (triggers
	* for the next sample)
	*/
	memset(&sigact, 0, sizeof sigact);
	sigact.sa_handler = getusr1;
	sigaction(SIGUSR1, &sigact, (struct sigaction *)0);

	memset(&sigact, 0, sizeof sigact);
	sigact.sa_handler = getusr2;
	sigaction(SIGUSR2, &sigact, (struct sigaction *)0);

	memset(&sigact, 0, sizeof sigact);
	sigact.sa_handler = getalarm;
	sigaction(SIGALRM, &sigact, (struct sigaction *)0);

	if (interval > 0)
		alarm(interval);

	if (midnightflag)
	{
		time_t		timenow = time(0);
		struct tm	*tp = localtime(&timenow);

		tp->tm_hour = 23;
		tp->tm_min  = 59;
		tp->tm_sec  = 59;

		timelimit = mktime(tp);
	}

	/*
	** MAIN-LOOP:
	**    -	Wait for the requested number of seconds or for other trigger
	**
	**    -	System-level counters
	**		get current counters
	**		calculate the differences with the previous sample
	**
	**    -	Process-level counters
	**		get current counters from running & exited processes
	**		calculate the differences with the previous sample
	**
	**    -	Call the print-function to visualize the differences
	*/
	for (sampcnt=0; sampcnt < nsamples; sampcnt++)
	{
		char	lastcmd;

		/*
		** if the limit-flag is specified:
		**  check if the next sample is expected before midnight;
		**  if not, stop atop now 
		*/
		if (midnightflag && (curtime+interval) > timelimit)
			break;

		/*
		** wait for alarm-signal to arrive (except first sample)
		** or wait for SIGUSR1/SIGUSR2
		*/
		if (sampcnt > 0 && awaittrigger)
			pause();

		awaittrigger = 1;

		/*
		** gather time info for this sample
		*/
		pretime  = curtime;
		curtime  = time(0);		/* seconds since 1-1-1970 */

		/*
		** take a snapshot of the current system-level statistics 
		** and calculate the deviations (i.e. calculate the activity
		** during the last sample)
		*/
		hlpsstat = cursstat;	/* swap current/prev. stats */
		cursstat = presstat;
		presstat = hlpsstat;

		photosyst(cursstat);	/* obtain new counters      */

		deviatsyst(cursstat, presstat, devsstat);

		/*
		** take a snapshot of the current process-level statistics 
		** and calculate the deviations (i.e. calculate the activity
		** during the last sample)
		**
		** first register active processes
		**  --> atop malloc's a minimal amount of space which is
		**      only extended when needed
		*/
		memset(curpact, 0, curplen * sizeof(struct pstat));

		while ( (npresent = photoproc(curpact, curplen)) == curplen)
		{
			curplen = countprocs() + PROCCHUNK;

			curpact = realloc(curpact,
			                   curplen * sizeof(struct pstat));

			memset(curpact, 0, curplen * sizeof(struct pstat));
		}

		/*
		** register processes which exited during last sample;
		** first determine how many processes exited and
		** reserve space for them, and secondly obtain the info
		*/
		nexit = acctprocnt();	/* number of exited processes */

		if (nexit > 0)	
		{
			curpexit = malloc(  nexit * sizeof(struct pstat));
			memset(curpexit, 0, nexit * sizeof(struct pstat));

			acctphotoproc(curpexit, nexit);
		}
		else
			curpexit = NULL;

		/*
		** calculate deviations
		*/
		devpstat = malloc((npresent+nexit) * sizeof(struct pstat));

		n = deviatproc(curpact, npresent, curpexit, nexit,
				deviatonly, devpstat, devsstat,
				&ntrun, &ntslpi, &ntslpu, &nzombie);

		/*
		** activate the installed print-function to visualize
		** the deviations
		*/
		lastcmd = (vis.show_samp)( curtime,
				     curtime-pretime > 0 ? curtime-pretime : 1,
		           	     devsstat, devpstat, n, npresent,
		                     ntrun, ntslpi, ntslpu, nzombie,
		                     nexit, sampcnt==0);

		/*
		** release dynamically allocated memory
		*/
		if (nexit > 0)
			free(curpexit);

		free(devpstat);

		if (lastcmd == 'r')	/* reset requested ? */
		{
			sampcnt = -1;

			curtime = getboot();	/* reset current time */

			/* set current (will be 'previous') counters to 0 */
			memset(cursstat, 0,           sizeof(struct sstat));
			memset(curpact,  0, curplen * sizeof(struct pstat));

			/* remove all processes in process database */
			pdb_makeresidue();
			pdb_cleanresidue();
		}
	} /* end of main-loop */
}