Logo Search packages:      
Sourcecode: s390-tools version File versions  Download package

mon_procd.c

/*
 * mon_procd
 * Author: Hongjie Yang <hongjie@us.ibm.com>
 *
 * Copyright IBM Corp. 2007.
 *
 * Daemon that writes process data to the z/VM monitor stream.
 */
#include <unistd.h>
#include <sys/vfs.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <syslog.h>
#include <errno.h>
#include <time.h>
#include <stdarg.h>
#include <linux/types.h>
#include <sys/statvfs.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <getopt.h>
#include <signal.h>
#include <utmp.h>
#include <pwd.h>
#include <grp.h>
#include <ctype.h>
#include <dirent.h>
#include "mon_procd.h"

00032 struct name_lens_t {
      __u16 ruser_len;
      __u16 euser_len;
      __u16 egroup_len;
      __u16 wchan_len;
      __u16 cmd_len;
      __u16 cmdline_len;
};

static int num_cpus;
static int curr_small_max, curr_big_max;
static int prev_small_max, prev_big_max;
static unsigned int pg_to_kb_shift, sort_tbl_size;
static float e_time;
static struct timeval prev_time, curr_time;
static struct cpudata_t cpudata;
static struct proc_sum_t proc_sum;
static struct task_sort_t *prev_sort_tbl, *curr_sort_tbl;
static struct name_lens_t name_lens;

static int attach;
static int mw_dev;
static char *temp;
static char fname[32];
static char buf[BUF_SIZE];
static char mon_record[MAX_REC_LEN];
static long sample_interval = 60;

static const char *pid_file = "/var/run/mon_procd.pid";

/*
 * Clean up when SIGTERM or SIGINT received
 */
void stop_procd(int UNUSED(a))
{
      remove(pid_file);
      exit(0);
}

/*
 * Set up for handling SIGTERM or SIGINT
 */
static void procd_handle_signals(void)
{
      struct sigaction act;

      act.sa_flags = 0;
      sigemptyset( &act.sa_mask );

      act.sa_handler = stop_procd;
      if (sigaction(SIGTERM, &act, NULL) < 0) {
            fprintf(stderr, "sigaction( SIGTERM, ... ) failed - "
                  "reason %s\n", strerror( errno ) );
            exit(1);
      }
      act.sa_handler = stop_procd;
      if (sigaction(SIGINT, &act, NULL) < 0) {
            fprintf(stderr, "sigaction( SIGINT, ... ) failed - "
                  "reason %s\n", strerror( errno ) );
            exit(1);
      }
}

/*
 * Open /dev/monwriter
 */
static void procd_open_monwriter(void)
{
      mw_dev = open("/dev/monwriter", O_EXCL | O_RDWR);
      if (mw_dev == -1) {
            printf("cannot open /dev/monwriter: %s\n", strerror(errno));
            exit(1);
      }
}

/*
 * Store daemon's pid so it can be stopped
 */
static void store_pid(void)
{
      FILE *f = fopen(pid_file, "w");

      if (!f) {
            syslog(LOG_ERR, "cannot open pid file %s: %s", pid_file,
                   strerror(errno));
            exit(1);
      }
      fprintf(f, "%d\n", getpid());
      fclose(f);
}

/*
 * Stop sampling of any buffers that are not longer needed
 */
static void stop_unused(int curr_max, int prev_max)
{
      struct monwrite_hdr *mw_hdrp;
      int i;

      mw_hdrp = (struct monwrite_hdr *)mon_record;
      mw_hdrp->mon_function = MONWRITE_STOP_INTERVAL;
      mw_hdrp->datalen = 0;
      for (i = 0; i < prev_max - curr_max; i += 2) {
            mw_hdrp->mod_level = curr_max + i;
            if (write(mw_dev, mw_hdrp, sizeof(struct monwrite_hdr)) == -1)
                  syslog(LOG_ERR, "write error on STOP: %s\n",
                         strerror(errno));
      }
}

/*
 * Write process data to monitor stream
 */
static void procd_write_ent(void *entry, int size, char flag)
{
      struct monwrite_hdr *mw_hdrp;
      struct procd_hdr *mw_pchdrp;

      char *mw_tmpp;
      char *mw_bufp;
      int write_len;

      mw_bufp = mon_record;
      mw_hdrp = (struct monwrite_hdr *)mw_bufp;
      write_len = size + sizeof(struct monwrite_hdr)
            + sizeof(struct procd_hdr);
      /* fill in monwrite_hdr */
      if (flag == TASK_FLAG) {
            if (write_len <= SMALL_MON_RECORD_LEN) {
                  write_len = SMALL_MON_RECORD_LEN;
                  mw_hdrp->mod_level = curr_small_max;
                  curr_small_max += 2;
            } else {
                  write_len = MAX_REC_LEN;
                  mw_hdrp->mod_level = curr_big_max;
                  curr_big_max += 2;
            }
      } else {
            mw_hdrp->mod_level = 0;
      }
      mw_hdrp->datalen = write_len - sizeof(struct monwrite_hdr);
      mw_hdrp->applid = PROCD_APPLID;
      mw_hdrp->record_num = flag;
      mw_hdrp->hdrlen = sizeof(struct monwrite_hdr);
      mw_hdrp->mon_function = MONWRITE_START_INTERVAL;

      /* fill in procd_hdr */
      mw_tmpp = mw_bufp + sizeof(struct monwrite_hdr);
      mw_pchdrp = (struct procd_hdr *)mw_tmpp;
      mw_pchdrp->time_stamp = (__u64) curr_time.tv_sec;
      mw_pchdrp->data_len = (__u16) size;
      mw_pchdrp->data_offset = (__u16) sizeof(struct procd_hdr);

      /* fill in entry information */
      mw_tmpp += sizeof(struct procd_hdr);
      if (flag == SUM_FLAG)
            memcpy(mw_tmpp, entry, size);
      else
            memcpy(mw_tmpp, entry, sizeof(struct task_t));

      if (write(mw_dev, mw_bufp, write_len) == -1)
            syslog(LOG_ERR, "write error: %s\n", strerror(errno));
}

/*
 * Open and read a file into a buffer
*/
static int read_file(char *fname, char *buf, int size)
{
      int num, fp;

      fp = open(fname, O_RDONLY);
      if (!fp)
            return -1;

      num = read(fp, buf, size);
      if (num < 0) {
            close(fp);
            return -1;
      }

      close(fp);
      return num;
}

/*
 * Get uptime
*/
static void read_uptime(void)
{
      double uptm;

      if (read_file("/proc/uptime", buf, sizeof(buf) - 1) <= 0)
            return;

      if (sscanf(buf, "%lf ", &uptm) < 1) {
            syslog(LOG_ERR, "bad data in %s \n", fname);
            return;
      }
      proc_sum.uptime = (__u64)uptm;
}

/*
 * Get number of users
*/
static void count_users(void)
{
      struct utmp *temp;

      proc_sum.users = 0;
      setutent();
      while ((temp = getutent())) {
            if ((temp->ut_type == USER_PROCESS) && (temp->ut_name))
                  proc_sum.users++;
      }
      endutent();
}

/*
 * Get load averages
*/
static void read_loadavg(void)
{
      int ret_num;

      if (read_file("/proc/loadavg", buf, sizeof(buf) - 1) <= 0)
            return;

      ret_num = sscanf(buf, "%s %s %s", proc_sum.loadavg_1,
                  proc_sum.loadavg_5, proc_sum.loadavg_15);

      if (ret_num < 3)
            syslog(LOG_ERR, "bad data in %s \n", fname);
}

/*
 * Calculate the state percentages for a CPU
*/
static void cal_cpu(struct cpudata_t *cpudt, struct cpu_t *cpu)
{
      __u64 total_time;

      total_time = cpudt->usr - cpudt->usr_prev;
      total_time += cpudt->sys - cpudt->sys_prev;
      total_time += cpudt->nice - cpudt->nice_prev;
      if (cpudt->idle - cpudt->idle_prev > 0)
            total_time += cpudt->idle - cpudt->idle_prev;
      total_time += cpudt->iowt - cpudt->iowt_prev;
      total_time += cpudt->irq - cpudt->irq_prev;
      total_time += cpudt->sirq - cpudt->sirq_prev;
      total_time += cpudt->steal - cpudt->steal_prev;

      if (total_time < 1)
            total_time = 1;

      cpu->num_cpus = cpudt->id;
      cpu->puser = (__u16)((cpudt->usr - cpudt->usr_prev) * 10000
                  / total_time);
      cpu->psystem = (__u16)((cpudt->sys - cpudt->sys_prev) * 10000
                  / total_time);
      cpu->pnice = (__u16)((cpudt->nice - cpudt->nice_prev) * 10000
                  / total_time);
      if (cpudt->idle - cpudt->idle_prev > 0)
            cpu->pidle = (__u16)((cpudt->idle - cpudt->idle_prev) * 10000
                        / total_time);
      else
            cpu->pidle = 0;
      cpu->piowait = (__u16)((cpudt->iowt - cpudt->iowt_prev) * 10000
                  / total_time);
      cpu->pirq = (__u16)((cpudt->irq - cpudt->irq_prev) * 10000
                  / total_time);
      cpu->psoftirq = (__u16)((cpudt->sirq - cpudt->sirq_prev) * 10000
                  / total_time);
      cpu->psteal = (__u16)((cpudt->steal - cpudt->steal_prev) * 10000
                  / total_time);

      cpudt->usr_prev = cpudt->usr;
      cpudt->sys_prev = cpudt->sys;
      cpudt->nice_prev = cpudt->nice;
      cpudt->idle_prev = cpudt->idle;
      cpudt->iowt_prev = cpudt->iowt;
      cpudt->irq_prev = cpudt->irq;
      cpudt->sirq_prev = cpudt->sirq;
      cpudt->steal_prev = cpudt->steal;
}

/*
 * Get CPU summary information
*/
static void read_cpu(void)
{
      unsigned long long u, n, s, i, w, x, y, z;

      if (read_file("/proc/stat", buf, sizeof(buf) - 1) <= 0)
            return;

      temp = strstr(buf, "cpu");
      sscanf(temp, "cpu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu",
            &u, &n, &s, &i, &w, &x, &y, &z);
      cpudata.usr = (__u64)u;
      cpudata.nice = (__u64)n;
      cpudata.sys = (__u64)s;
      cpudata.idle = (__u64)i;
      cpudata.iowt = (__u64)w;
      cpudata.irq = (__u64)x;
      cpudata.sirq = (__u64)y;
      cpudata.steal = (__u64)z;
      cpudata.id = (__u32)num_cpus;
      cal_cpu(&cpudata, &proc_sum.cpu);
}

/*
 * Get memory information
*/
static void read_mem(void)
{
      unsigned long long mtotal, mfree, mbuf;
      unsigned long long stotal, sfree, scached;

      if (read_file("/proc/meminfo", buf, sizeof(buf) - 1) <= 0)
            return;

      temp = strstr(buf, "MemTotal");
      sscanf(temp, "MemTotal: %Lu kB", &mtotal);
      temp = strstr(buf, "MemFree");
      sscanf(temp, "MemFree: %Lu kB", &mfree);
      temp = strstr(buf, "Buffers");
      sscanf(temp, "Buffers: %Lu kB", &mbuf);
      temp = strstr(buf, "SwapTotal");
      sscanf(temp, "SwapTotal: %Lu kB", &stotal);
      temp = strstr(buf, "SwapFree");
      sscanf(temp, "SwapFree: %Lu kB", &sfree);
      temp = strstr(buf, "Cached");
      sscanf(temp, "Cached: %Lu kB", &scached);

      proc_sum.mem.total = (__u64)mtotal;
      proc_sum.mem.free = (__u64)mfree;
      proc_sum.mem.buffers = (__u64)mbuf;
      proc_sum.swap.total = (__u64)stotal;
      proc_sum.swap.free = (__u64)sfree;
      proc_sum.swap.cached = (__u64)scached;
      proc_sum.mem.used = proc_sum.mem.total - proc_sum.mem.free;
      proc_sum.swap.used = proc_sum.swap.total - proc_sum.swap.free;
}

/*
 * Get virtual memory information
*/
static void read_vmem(void)
{
      unsigned long long pgin, pgout, swpin, swpout;

      if (read_file("/proc/vmstat", buf, sizeof(buf) - 1) <= 0)
            return;

      temp = strstr(buf, "pgpgin");
      sscanf(temp, "pgpgin %Lu", &pgin);
      temp = strstr(buf, "pgpgout");
      sscanf(temp, "pgpgout %Lu", &pgout);
      temp = strstr(buf, "pswpin");
      sscanf(temp, "pswpin %Lu", &swpin);
      temp = strstr(buf, "pswpout");
      sscanf(temp, "pswpout %Lu", &swpout);

      proc_sum.mem.pgpgin = (__u64)(pgin << pg_to_kb_shift);
      proc_sum.mem.pgpgout = (__u64)(pgout << pg_to_kb_shift);
      proc_sum.swap.pswpin = (__u64)swpin;
      proc_sum.swap.pswpout = (__u64)swpout;
}

/*
 * Get process summary information
*/
static void read_summary(void)
{
      read_uptime();
      count_users();
      read_loadavg();
      read_cpu();
      read_mem();
      read_vmem();
}

/*
 * Get memory information for a task
*/
static int read_statm(struct task_t *task)
{
      long size, res, sh, trs, lrs, drs, dt;

      snprintf(fname, sizeof(fname), "/proc/%u/statm", task->pid);
      if (read_file(fname, buf, sizeof(buf) - 1) == -1)
            return 0;

      sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld",
            &size, &res, &sh, &trs, &lrs, &drs, &dt);
      task->size = (__u64)(size << pg_to_kb_shift);
      task->resident = (__u64)(res << pg_to_kb_shift);
      task->swap = task->size - task->resident;
      task->share = (__u64)(sh << pg_to_kb_shift);
      task->trs = (__u64)(trs << pg_to_kb_shift);
      task->drs = (__u64)(drs << pg_to_kb_shift);
      task->dt = (__u64)dt;

      task->pmem = (__u16)(task->resident * 10000 / proc_sum.mem.total);
      return 1;
}

/*
 * Get status information for a task from /proc/.../status
*/
static int read_status(struct task_t *task)
{
      int ruid, euid, egid;
      char *lenp, *namep;
      struct passwd *pwd;
      struct group *grp;

      snprintf(fname, sizeof(fname), "/proc/%u/status", task->pid);
      if (read_file(fname, buf, sizeof(buf) - 1) == -1)
            return 0;

      temp = strstr(buf, "Uid");
      sscanf(temp, "Uid: %d %d", &ruid, &euid);
      temp = strstr(buf, "Gid");
      sscanf(temp, "Gid: %*d %d", &egid);
      task->euid = (__u16)euid;

      lenp = mon_record + sizeof(struct monwrite_hdr);
      lenp += sizeof(struct procd_hdr);
      lenp += sizeof(struct task_t);
      namep = lenp + sizeof(__u16);
      pwd = getpwuid(ruid);
      if (!pwd)
            name_lens.ruser_len = sprintf(namep, "%u", ruid);
      else {
            name_lens.ruser_len = strlen(pwd->pw_name);
            if (name_lens.ruser_len > MAX_NAME_LEN)
                  name_lens.ruser_len = MAX_NAME_LEN;
            memcpy(namep, pwd->pw_name, name_lens.ruser_len);
      }
      memcpy(lenp, &name_lens.ruser_len, sizeof(__u16));

      lenp = namep + name_lens.ruser_len;
      namep = lenp + sizeof(__u16);
      pwd = getpwuid(task->euid);
      if (!pwd)
            name_lens.euser_len = sprintf(namep, "%u", task->euid);
      else {
            name_lens.euser_len = strlen(pwd->pw_name);
            if (name_lens.euser_len > MAX_NAME_LEN)
                  name_lens.euser_len = MAX_NAME_LEN;
            memcpy(namep, pwd->pw_name, name_lens.euser_len);
      }
      memcpy(lenp, &name_lens.euser_len, sizeof(__u16));

      lenp = namep + name_lens.euser_len;
      namep = lenp + sizeof(__u16);
      grp = getgrgid(egid);
      if (!grp)
            name_lens.egroup_len = sprintf(namep, "%u", egid);
      else {
            name_lens.egroup_len = strlen(grp->gr_name);
            if (name_lens.egroup_len > MAX_NAME_LEN)
                  name_lens.egroup_len = MAX_NAME_LEN;
            memcpy(namep, grp->gr_name, name_lens.egroup_len);
      }
      memcpy(lenp, &name_lens.egroup_len, sizeof(__u16));
      return 1;
}

/*
 * Calculate percentage of CPU used by a task since last sampling
*/
static void cal_task_pcpu(struct task_t *task, const unsigned long long tics)
{
      unsigned int i, size;
      __u64 etics;

      if (proc_sum.task.total + 1 >= sort_tbl_size) {
            sort_tbl_size = sort_tbl_size * 5 / 4 + 100;
            size = sort_tbl_size * sizeof(struct task_sort_t);
            curr_sort_tbl = realloc(curr_sort_tbl, size);
            if (!curr_sort_tbl) {
                  fprintf(stderr, "Allocating memory failed - "
                  "reason %s\n", strerror(errno));
                  exit(1);
            }
            prev_sort_tbl = realloc(prev_sort_tbl, size);
            if (!prev_sort_tbl) {
                  fprintf(stderr, "Allocating memory failed - "
                  "reason %s\n", strerror(errno));
                  exit(1);
            }
      }
      curr_sort_tbl[proc_sum.task.total].pid = task->pid;
      curr_sort_tbl[proc_sum.task.total].tics = (__u64)tics;

      etics = (__u64)tics;
      for (i = 0; i < sort_tbl_size; i++) {
            if (prev_sort_tbl[i].pid == task->pid) {
                  etics -= prev_sort_tbl[i].tics;
                  break;
            }
      }
      task->pcpu = (__u16)((etics * 10000 / Hertz) / (e_time * num_cpus));
      if (task->pcpu > 9999)
            task->pcpu = 9999;
}

/*
 * Get status information for a task from /proc/.../stat
*/
static int read_stat(struct task_t *task)
{
      int ppid, tty, proc;
      unsigned long flags, pri, nice;
      unsigned long long maj_flt, utime, stime, cutime, cstime;
      char *cmd_start, *cmd_end, *cmdlenp, *cmdp;

      snprintf(fname, sizeof(fname), "/proc/%u/stat", task->pid);
      if (read_file(fname, buf, sizeof(buf) - 1) == -1)
            return 0;

      cmd_start = strchr(buf, '(') + 1;
      cmd_end = strchr(cmd_start, ')');
      name_lens.cmd_len = cmd_end - cmd_start;
      cmdlenp = mon_record + sizeof(struct monwrite_hdr);
      cmdlenp += sizeof(struct procd_hdr);
      cmdlenp += sizeof(struct task_t);
      cmdlenp += sizeof(__u16) + name_lens.ruser_len;
      cmdlenp += sizeof(__u16) + name_lens.euser_len;
      cmdlenp += sizeof(__u16) + name_lens.egroup_len;
      cmdlenp += sizeof(__u16) + name_lens.wchan_len;

      if (name_lens.cmd_len <= 0)
            name_lens.cmd_len = 0;
      else {
            cmdp = cmdlenp + sizeof(__u16);
            if (name_lens.cmd_len > MAX_NAME_LEN)
                  name_lens.cmd_len = MAX_NAME_LEN;
            memcpy(cmdp, cmd_start, name_lens.cmd_len);
      }
      memcpy(cmdlenp, &name_lens.cmd_len, sizeof(__u16));

      cmd_end += 2;
      sscanf(cmd_end,
            "%c %d %*d %*d %d %*d "
            "%lu %*s %*s %Lu %*s "
            "%Lu %Lu %Lu %Lu "
            "%ld %ld "
            "%*d %*s "
            "%*s %*s %*s "
            "%*s %*s %*s %*s %*s %*s "
            "%*s %*s %*s %*s "
            "%*s %*s %*s "
            "%*d %d "
            "%*s %*s",
            &task->state, &ppid, &tty,
            &flags, &maj_flt,
            &utime, &stime, &cutime, &cstime,
            &pri, &nice,
            &proc);
      task->ppid = (__u32)ppid;
      task->tty = (__u16)tty;
      task->flags = (__u32)flags;
      task->maj_flt = (__u64)maj_flt;
      task->priority = (__s16)pri;
      task->nice = (__s16)nice;
      task->processor = (__u32)proc;
      task->total_time = (__u64)((utime + stime) * 100 / Hertz);
      task->ctotal_time = (__u64)((utime + stime + cutime + cstime) * 100
                        / Hertz);
      cal_task_pcpu(task, utime + stime);

      return 1;
}

/*
 * Get the sleeping in function of a task
*/
static int read_wchan(struct task_t *task)
{
      int num;
      char *wchanlenp, *wchanp;

      snprintf(fname, sizeof(fname), "/proc/%u/wchan", task->pid);
      num = read_file(fname, buf, sizeof(buf) -1);

      if (num < 0)
            return 0;

      wchanlenp = mon_record + sizeof(struct monwrite_hdr);
      wchanlenp += sizeof(struct procd_hdr);
      wchanlenp += sizeof(struct task_t);
      wchanlenp += sizeof(__u16) + name_lens.ruser_len;
      wchanlenp += sizeof(__u16) + name_lens.euser_len;
      wchanlenp += sizeof(__u16) + name_lens.egroup_len;
      wchanp = wchanlenp + sizeof(__u16);

      name_lens.wchan_len = num;
      if (num == 0) {
            memcpy(wchanlenp, &name_lens.wchan_len, sizeof(__u16));
            return 1;
      }
      buf[num] = '\0';

      if (buf[0] == '0' && buf[1] == '\0') {
            memcpy(wchanlenp, &name_lens.wchan_len, sizeof(__u16));
            wchanp[0] = '-';
            return 1;
      }

      if (buf[0] == 's' && !strncmp(buf, "sys_", 4)) {
            name_lens.wchan_len -= 4;
            if (name_lens.wchan_len > MAX_NAME_LEN)
                  name_lens.wchan_len = MAX_NAME_LEN;
            memcpy(wchanlenp, &name_lens.wchan_len, sizeof(__u16));
            memcpy(wchanp, buf + 4, name_lens.wchan_len);
            return 1;
      }

      if (buf[0] == 'd' && !strncmp(buf, "do_", 3)) {
            name_lens.wchan_len -= 3;
            if (name_lens.wchan_len > MAX_NAME_LEN)
                  name_lens.wchan_len = MAX_NAME_LEN;
            memcpy(wchanlenp, &name_lens.wchan_len, sizeof(__u16));
            memcpy(wchanp, buf + 3, name_lens.wchan_len);
            return 1;
      }

      temp = buf;
      while (*temp == '_') {
            temp++;
            name_lens.wchan_len--;
      }
      if (name_lens.wchan_len > MAX_NAME_LEN)
            name_lens.wchan_len = MAX_NAME_LEN;
      memcpy(wchanlenp, &name_lens.wchan_len, sizeof(__u16));
      memcpy(wchanp, temp, name_lens.wchan_len);
      return 1;
}

/*
 * Get command line of a task
*/
static int read_cmdline(struct task_t *task)
{
      int i, num;
      char *cmdlnlenp, *cmdlinep;

      snprintf(fname, sizeof(fname), "/proc/%u/cmdline", task->pid);
      num = read_file(fname, buf, sizeof(buf) - 1);
      if (num == -1)
            return 0;
      for (i = 0; i < num; i++) {
            if (buf[i] < ' ' || buf[i] > '~')
                  buf[i] = ' ';
      }
      name_lens.cmdline_len = num;
      cmdlnlenp = mon_record + sizeof(struct monwrite_hdr);
      cmdlnlenp += sizeof(struct procd_hdr);
      cmdlnlenp += sizeof(struct task_t);
      cmdlnlenp += sizeof(__u16) + name_lens.ruser_len;
      cmdlnlenp += sizeof(__u16) + name_lens.euser_len;
      cmdlnlenp += sizeof(__u16) + name_lens.egroup_len;
      cmdlnlenp += sizeof(__u16) + name_lens.wchan_len;
      cmdlnlenp += sizeof(__u16) + name_lens.cmd_len;
      cmdlinep = cmdlnlenp + sizeof(__u16);

      memcpy(cmdlnlenp, &name_lens.cmdline_len, sizeof(__u16));
      if (name_lens.cmdline_len > 0)
            memcpy(cmdlinep, buf, name_lens.cmdline_len);
      return 1;
}

/*
 * Usage sorting help function
*/
static int sort_usage(const void *et1, const void *et2)
{
      return ((struct task_sort_t *)et2)->cpu_mem_usage
            - ((struct task_sort_t *)et1)->cpu_mem_usage;
}

/*
 * Adjust task state counters
*/
static void task_count(char oldst, char newst)
{
      if (oldst == newst)
            return;

      switch (oldst) {
      case 'R':
            proc_sum.task.running--;
            break;
      case 'S':
      case 'D':
            proc_sum.task.sleeping--;
            break;
      case 'T':
            proc_sum.task.stopped--;
            break;
      case 'Z':
            proc_sum.task.zombie--;
            break;
      }
      switch (newst) {
      case 'R':
            proc_sum.task.running++;
            break;
      case 'S':
      case 'D':
            proc_sum.task.sleeping++;
            break;
      case 'T':
            proc_sum.task.stopped++;
            break;
      case 'Z':
            proc_sum.task.zombie++;
            break;
      }
}

/*
 * Read and calculate memory and cpu usages of a task
*/
static void task_usage(struct task_t *task)
{
      long res;
      unsigned long long utime, stime;

      snprintf(fname, sizeof(fname), "/proc/%u/statm", task->pid);
      if (read_file(fname, buf, sizeof(buf) - 1) == -1)
            return;
      sscanf(buf, "%*s %ld %*s %*s %*s %*s %*s", &res);
      task->resident = (__u64)(res << pg_to_kb_shift);
      task->pmem = (__u16)(task->resident * 10000 / proc_sum.mem.total);

      snprintf(fname, sizeof(fname), "/proc/%u/stat", task->pid);
      if (read_file(fname, buf, sizeof(buf) - 1) == -1)
            return;
      sscanf(buf,
            "%*s %*s "
            "%c %*s %*s %*s %*s %*s "
            "%*s %*s %*s %*s %*s "
            "%Lu %Lu ",
            &task->state,
            &utime, &stime);
      cal_task_pcpu(task, utime + stime);

      curr_sort_tbl[proc_sum.task.total].cpu_mem_usage = task->pcpu +
            task->pmem;
      curr_sort_tbl[proc_sum.task.total].state = task->state;
      task_count('\0', task->state);
      proc_sum.task.total++;
}

/*
 * read tasks information and write to monitor stream
*/
static void read_tasks(void)
{
      int size;
      unsigned int i = 0, j = 0;
      DIR *proc_dir;
      struct direct *entry;
      struct task_t task;

      proc_dir = opendir("/proc");
      if (!proc_dir) {
            syslog(LOG_ERR, "failed /proc open: %s ", strerror(errno));
            return;
      }

      while ((entry = readdir(proc_dir))) {
            if (!entry->d_name)
                  break;
            if (!isdigit(entry->d_name[0]) || !atoi(entry->d_name))
                  continue;
            memset(&task, 0, sizeof(struct task_t));
            task.pid = atoi(entry->d_name);
            task_usage(&task);
      }
      closedir(proc_dir);

      if (proc_sum.task.total > MAX_TASK_REC)
            qsort(curr_sort_tbl, proc_sum.task.total,
                  sizeof(struct task_sort_t), sort_usage);

      /* only write up to top 100 processes data to monitor stream */
      while ((i < proc_sum.task.total) && (j < MAX_TASK_REC)) {
            memset(&task, 0, sizeof(struct task_t));
            memset(mon_record, 0, sizeof(mon_record));
            task.pid = curr_sort_tbl[i].pid;
            if (read_statm(&task) && read_status(&task) &&
                  read_wchan(&task) && read_stat(&task) &&
                  read_cmdline(&task)) {
                  task_count(curr_sort_tbl[i].state, task.state);
                  size = sizeof(struct task_t);
                  size += sizeof(struct name_lens_t);
                  size += name_lens.ruser_len + name_lens.euser_len;
                  size += name_lens.egroup_len + name_lens.wchan_len;
                  size += name_lens.cmd_len + name_lens.cmdline_len;
                  procd_write_ent(&task, size, TASK_FLAG);
                  j++;
            } else
                  task_count(curr_sort_tbl[i].state, '\0');
            i++;
      }
      proc_sum.task.total -= i - j;
}

/*
 * Run as background process
 */
static void procd_daemonize(void)
{
      pid_t pid;

      /* Fork off the parent process */
      pid = fork();
      if (pid < 0) {
            syslog(LOG_ERR, "fork error: %s\n", strerror(errno));
            exit(1);
      }
      if (pid > 0)
            exit(0);

      /* Change the file mode mask */
      umask(0);

      /* Store daemon pid */
      store_pid();
      /* Catch SIGINT and SIGTERM to clean up pid file on exit */
      procd_handle_signals();

      /* Create a new SID for the child process */
      if (setsid() < 0) {
            syslog(LOG_ERR, "setsid error: %s\n",  strerror(errno));
            exit(1);
      }

      /* Change the current working directory */
      if (chdir("/") < 0) {
            syslog(LOG_ERR, "chdir error: %s\n",  strerror(errno));
            exit(1);
      }

      /* Close out the standard file descriptors */
      close(STDIN_FILENO);
      close(STDOUT_FILENO);
      close(STDERR_FILENO);
}

static int procd_do_work(void)
{
      int pgsize;
      struct timezone tz;
      struct task_sort_t *tmp;

      prev_small_max = 0;
      prev_big_max = 1;
      num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
      if (num_cpus < 1)
            num_cpus = 1;

      pg_to_kb_shift = 0;
      pgsize = getpagesize();
      while (pgsize > 1024) {
            pgsize >>= 1;
            pg_to_kb_shift++;
      }

      syslog(LOG_INFO, "procd sample interval: %lu\n", sample_interval);
      while (1) {
            gettimeofday(&curr_time, &tz);
            e_time = (curr_time.tv_sec - prev_time.tv_sec) +
                  (float)(curr_time.tv_usec - prev_time.tv_usec)
                  / 1000000.0;
            memset(&proc_sum, 0, sizeof(struct proc_sum_t));
            tmp = prev_sort_tbl;
            prev_sort_tbl = curr_sort_tbl;
            curr_sort_tbl = tmp;
            curr_small_max = 0;
            curr_big_max = 1;
            read_summary();
            read_tasks();
            memset(mon_record, 0, sizeof(mon_record));
            procd_write_ent(&proc_sum, sizeof(struct proc_sum_t), SUM_FLAG);

            if (curr_small_max < prev_small_max)
                  stop_unused(curr_small_max, prev_small_max);
            if (curr_big_max < prev_big_max)
                  stop_unused(curr_big_max, prev_big_max);

            prev_small_max = curr_small_max;
            prev_big_max = curr_big_max;
            prev_time.tv_sec = curr_time.tv_sec;
            prev_time.tv_usec = curr_time.tv_usec;
            sleep(sample_interval);
      }
      return 1;
}

/*
 Parse options
*/
static int parse_options(int argc, char **argv)
{
      int opt;

      do {
            opt = getopt_long(argc, argv, opt_string, options, NULL);
            switch (opt) {
            case -1:
                  /* Reached end of parameter list. */
                  break;
            case 'h':
                  printf("%s", help_text);
                  exit(0);
            case 'v':
                  printf( "mon_procd: version %s\n", RELEASE_STRING);
                  printf("Copyright IBM Corp. 2007\n");
                  exit(0);
            case 'a':
                  attach = 1;
                  break;
            case 'i':
                  sample_interval = strtol(optarg, NULL, 10);
                  if (sample_interval <= 0) {
                        fprintf(stderr, "Error: Invalid interval "
                              "(needs to be greater than 0)\n");
                        return(1);
                  }
                  break;
            default:
                  fprintf(stderr, "Try ' --help' for more"
                        " information.\n");
                  return(1);
            }
      } while (opt != -1);
      return(0);
}

int main(int argc, char **argv)
{
      int rc;

      attach = 0;
      rc = parse_options(argc, argv);
      if (rc > 0)
            return rc;
      procd_open_monwriter();
      openlog("mon_procd", 0, LOG_DAEMON);
      if (!attach)
            procd_daemonize();
      rc = procd_do_work();
      close(mw_dev);
      return rc;
}

Generated by  Doxygen 1.6.0   Back to index