/* * 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; }
/* ** 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; }