::: 강좌/소스/문서 :::

강좌/소스/문서 성격에 맞지 않는 광고,비방,질문의 글은 즉시 삭제하며
내용을 복사하여 사용할 경우 반드시 이곳(http://www.howto.pe.kr)을 출처로 명시하여 주세요


Category

  김영대(2004-02-20 13:21:42, Hit : 6482, Vote : 1121
 http://www.howto.pe.kr
 [소스] top for System V Release 4, Intel or Sparc CPU

/*
* top - a top users display for Unix
*
* SYNOPSIS:  For System V Release 4, Intel or Sparc CPU
*
* DESCRIPTION:
*
* The following must be added to CFLAGS in the Makefile:
* [From <ucbinclude/sys/resource.h>]
* -DPRIO_MIN=-20 -DPRIO_MAX=20
*
* LIBS:  -lelf -lc -L/usr/ucblib -lucb
*
* AUTHOR:  Robert Boucher <boucher@sofkin.ca>
*/

#include <sys/types.h>
#include <sys/param.h>
#include <sys/signal.h>
#include <sys/fault.h>
#include <sys/sysinfo.h>
#include <sys/sysmacros.h>
#include <sys/syscall.h>
#include <dirent.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/procfs.h>
#include <sys/vm.h>
#include <sys/var.h>
#ifdef sun
#include <sys/cpuvar.h>
#endif
#include <sys/file.h>
#include <dirent.h>
#include <stdio.h>
#include <nlist.h>
#include <fcntl.h>
#include <math.h>
#include <vm/anon.h>

#include "top.h"
#include "machine.h"


#ifndef FSCALE
/*
* [From /usr/ucbinclude/sys/param.h]
* Scale factor for scaled integers used to count
* %cpu time and load averages.
*/
#define FSHIFT  8  /* bits to right of fixed binary point */
#define FSCALE  (1<<FSHIFT)
#endif /* FSCALE */

/* get_process_info passes back a handle.  This is what it looks like: */

struct handle
  {
    struct prpsinfo **next_proc;/* points to next valid proc pointer */
    int remaining;  /* number of pointers remaining */
  };

#define CPUSTATES 5

/* declarations for load_avg */
typedef long load_avg;
#define loaddouble(la) ((double)(la) / FSCALE)

/* define what weighted cpu is.  */
#define percent_cpu(pp) ((double)(pp)->pr_cpu / FSCALE)

#define weighted_cpu(pct, pp) ( ((pp)->pr_time.tv_sec) == 0 ? 0.0 :
        ((pp)->pr_cpu) / ((pp)->pr_time.tv_sec) )

#ifdef sun
#undef ctob
#define ctob(x) ((x) << 12)
#endif

/* Convert clicks (kernel pages) to kbytes ... */
#define pagetok(size) ctob(size) >> LOG1024

/* definitions for indices in the nlist array */
#define X_AVENRUN 0
#define X_MPID  1
#ifndef sun
#define X_SYSINFO 2
#else
#define X_CPU  2
#endif
#define X_V  3
#define X_NPROC  4
#define X_ANONINFO 5
#ifndef sun
#define X_TOTAL  6
#else
#define X_FREEMEM 6
#define X_MAXMEM 7
#define X_AVAILRMEM 8
#define X_SWAPFS_MINFREE 9
#endif

static struct nlist nlst[] =
{
  {"avenrun"},   /* 0 */
  {"mpid"},   /* 1 */
#ifndef sun
  {"sysinfo"},   /* 2 */
#else
  {"cpu"},   /* 2 */
#endif
  {"v"},   /* 3 */
  {"nproc"},   /* 4 */
  {"anoninfo"},   /* 5 */
#ifndef sun
  {"total"},   /* 6 */
#else
  {"freemem"},   /* 6 */
  {"maxmem"},   /* 7 */
  {"availrmem"},  /* 8 */
  {"swapfs_minfree"},  /* 9 */
#endif
  {0}
};

/*
*  These definitions control the format of the per-process area
*/

static char header[] =
"  PID X        PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
/* 0123456   -- field to fill in starts at header+6 */
#define UNAME_START 6

#define Proc_format
"%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %3d.0%% %5.2f%% %.16s"


/* process state names for the "STATE" column of the display */
/* the extra nulls in the string "run" are for adding a slash and
   the processor number when needed */

char *state_abbrev[] =
{
  "", "sleep", "run", "zombie", "stop", "start", "cpu", "swap"
};

#ifdef sun
#define UNIX "/kernel/unix"
#else
#define UNIX "/stand/unix"
#endif
#define KMEM "/dev/kmem"
#define PROCFS "/proc"

static int kmem = -1;
static int mem = -1;

#ifndef sun
struct vmtotal total;
#else
int freemem;
int maxmem;
int availrmem;
int swapfs_minfree;
#endif

struct anoninfo anoninfo;

/* these are retrieved from the kernel in _init */

static int nproc;

/* these are offsets obtained via nlist and used in the get_ functions */

static unsigned long mpid_offset;
static unsigned long nproc_offset;
static unsigned long avenrun_offset;
#ifndef sun
static unsigned long total_offset;
static unsigned long sysinfo_offset;
#else
static unsigned long freemem_offset;
static unsigned long maxmem_offset;
static unsigned long availrmem_offset;
static unsigned long swapfs_minfree_offset;
static unsigned long cpu_offset;
#endif
static unsigned long anoninfo_offset;

/* these are for calculating cpu state percentages */

static long cp_time[CPUSTATES];
static long cp_old[CPUSTATES];
static long cp_diff[CPUSTATES];

/* these are for detailing the process states */

int process_states[8];
char *procstatenames[] =
{
  "", " sleeping, ", " running, ", " zombie, ", " stopped, ",
  " starting, ", " on cpu, ", " swapped, ",
  NULL
};

/* these are for detailing the cpu states */

int cpu_states[CPUSTATES];
char *cpustatenames[] =
{
  "idle", "user", "kernel", "wait", "swap",
  NULL
};

/* these are for detailing the memory statistics */

int memory_stats[5];
char *memorynames[] =
{
  "K real, ", "K active, ", "K free, ", "K swap, ", "K free swap", NULL
};

/* these are for keeping track of the proc array */

static int bytes;
static struct prpsinfo *pbase;
static struct prpsinfo **pref;


/* useful externals */
extern int errno;
extern char *sys_errlist[];
extern char *myname;

long lseek ();
long percentages ();

machine_init (statics)
     struct statics *statics;
{
  register int i;
  static struct var v;

  /* open kernel memory */
  if ((kmem = open (KMEM, 0)) < 0)
    {
      perror (KMEM);
      exit (20);
    }

  /* get the list of symbols we want to access in the kernel */
  if ((i = nlist (UNIX, nlst)) < 0)
    {
      fprintf (stderr, "%s: nlist failedn", myname);
      return (-1);
    }

  /* make sure they were all found */
  if (i > 0 && check_nlist (nlst) > 0)
    {
      return (-1);
    }

  /* get the symbol values out of kmem */
  /* NPROC Tuning parameter for max number of processes */
  (void) getkval (nlst[X_V].n_value, &v, sizeof (struct var), nlst[X_V].n_name);
  nproc = v.v_proc;

  /* stash away certain offsets for later use */
  mpid_offset = nlst[X_MPID].n_value;
  nproc_offset = nlst[X_NPROC].n_value;
  avenrun_offset = nlst[X_AVENRUN].n_value;
  anoninfo_offset = nlst[X_ANONINFO].n_value;
#ifndef sun
  total_offset = nlst[X_TOTAL].n_value;
  sysinfo_offset = nlst[X_SYSINFO].n_value;
#else
  freemem_offset = nlst[X_FREEMEM].n_value;
  maxmem_offset = nlst[X_MAXMEM].n_value;
  availrmem_offset = nlst[X_AVAILRMEM].n_value;
  swapfs_minfree_offset = nlst[X_SWAPFS_MINFREE].n_value;
  /* XXX This is very dangerous... cpu is actually an array[ncpus] of cpu */
  /* Since my box only has one, I'll fix this later... */
  (void) getkval (nlst[X_CPU].n_value, &cpu_offset, sizeof (cpu_offset), nlst[X_CPU].n_name);
#endif

  /* allocate space for proc structure array and array of pointers */
  bytes = nproc * sizeof (struct prpsinfo);
  pbase = (struct prpsinfo *) malloc (bytes);
  pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));

  /* Just in case ... */
  if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
    {
      fprintf (stderr, "%s: can't allocate sufficient memoryn", myname);
      return (-1);
    }

  /* fill in the statics information */
  statics->procstate_names = procstatenames;
  statics->cpustate_names = cpustatenames;
  statics->memory_names = memorynames;

  /* all done! */
  return (0);
}

char *
format_header (uname_field)
     register char *uname_field;
{
  register char *ptr;

  ptr = header + UNAME_START;
  while (*uname_field != '')
    {
      *ptr++ = *uname_field++;
    }

  return (header);
}

get_system_info (si)
     struct system_info *si;
{
  load_avg avenrun[3];
#ifndef sun
  struct sysinfo sysinfo;
#else
  struct cpu cpu;  /* XXX ROB: Very bad, cpu is an array of ncpus */
#endif
  register int j;

  /* get the cp_time array */
  for (j = 0; j < CPUSTATES; j++)
    cp_time[j] = 0L;
#ifndef sun
  (void) getkval (sysinfo_offset, &sysinfo, sizeof (struct sysinfo), "sysinfo");
  for (j = 0; j < CPUSTATES; j++)
    cp_time[j] += (long) sysinfo.cpu[j];
#else
  (void) getkval (cpu_offset, &cpu, sizeof (struct cpu), "cpu");
  for (j = 0; j < CPUSTATES; j++)
    cp_time[j] += (long) cpu.cpu_stat.cpu_sysinfo.cpu[j];
#endif

  /* get load average array */
  (void) getkval (avenrun_offset, (int *) avenrun, sizeof (avenrun),
    "avenrun");

  /* get mpid -- process id of last process */
  (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid),
    "mpid");

  /* convert load averages to doubles */
  {
    register int i;
    register double *infoloadp;
    register load_avg *sysloadp;

    infoloadp = si->load_avg;
    sysloadp = avenrun;
    for (i = 0; i < 3; i++)
      {
*infoloadp++ = loaddouble (*sysloadp++);
      }
  }

  /* convert cp_time counts to percentages */
  (void) percentages (CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);

#ifndef sun
  /* get total -- systemwide main memory usage structure */
  (void) getkval (total_offset, (int *) (&total), sizeof (total), "total");
  /* convert memory stats to Kbytes */
  memory_stats[0] = pagetok (total.t_rm);
  memory_stats[1] = pagetok (total.t_arm);
  memory_stats[2] = pagetok (total.t_free);
#else
  (void) getkval (freemem_offset, (int *) (&freemem), sizeof (freemem), "freemem");
  (void) getkval (maxmem_offset, (int *) (&maxmem), sizeof (maxmem), "maxmem");
  memory_stats[0] = pagetok (maxmem);
  memory_stats[1] = 0;
  memory_stats[2] = pagetok (freemem);
#endif
  (void) getkval (anoninfo_offset, (int *) (&anoninfo), sizeof (anoninfo),
    "anoninfo");
#ifndef sun
  memory_stats[3] = pagetok (anoninfo.ani_max - anoninfo.ani_free);
  memory_stats[4] = pagetok (anoninfo.ani_max - anoninfo.ani_resv);
#else
  (void) getkval (availrmem_offset, (int *) (&availrmem), sizeof (availrmem), "availrmem");
  (void) getkval (swapfs_minfree_offset, (int *) (&swapfs_minfree), sizeof (swapfs_minfree), "swapfs_minfree");
  memory_stats[3] = pagetok (anoninfo.ani_resv);
  memory_stats[4] = pagetok (MAX (anoninfo.ani_max - anoninfo.ani_resv, 0) + availrmem - swapfs_minfree);
#endif

  /* set arrays and strings */
  si->cpustates = cpu_states;
  si->memory = memory_stats;
}

static struct handle handle;

caddr_t
get_process_info (si, sel, compare)
     struct system_info *si;
     struct process_select *sel;
     int (*compare) ();
{
  register int i;
  register int total_procs;
  register int active_procs;
  register struct prpsinfo **prefp;
  register struct prpsinfo *pp;

  /* these are copied out of sel for speed */
  int show_idle;
  int show_system;
  int show_uid;

  /* Get current number of processes */
  (void) getkval (nproc_offset, (int *) (&nproc), sizeof (nproc), "nproc");

  /* read all the proc structures */
  getptable (pbase);

  /* get a pointer to the states summary array */
  si->procstates = process_states;

  /* set up flags which define what we are going to select */
  show_idle = sel->idle;
  show_system = sel->system;
  show_uid = sel->uid != -1;

  /* count up process states and get pointers to interesting procs */
  total_procs = 0;
  active_procs = 0;
  bzero ((char *) process_states, sizeof (process_states));
  prefp = pref;

  for (pp = pbase, i = 0; i < nproc; pp++, i++)
    {
      /*
  *  Place pointers to each valid proc structure in pref[].
  *  Process slots that are actually in use have a non-zero
  *  status field.  Processes with SSYS set are system
  *  processes---these get ignored unless show_sysprocs is set.
  */
      if (pp->pr_state != 0 &&
   (show_system || ((pp->pr_flag & SSYS) == 0)))
{
   total_procs++;
   process_states[pp->pr_state]++;
   if ((!pp->pr_zomb) &&
       (show_idle || (pp->pr_state == SRUN) || (pp->pr_state == SONPROC)) &&
       (!show_uid || pp->pr_uid == (uid_t) sel->uid))
     {
       *prefp++ = pp;
       active_procs++;
     }
}
    }

  /* if requested, sort the "interesting" processes */
  if (compare != NULL)
    {
      qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), compare);
    }

  /* remember active and total counts */
  si->p_total = total_procs;
  si->p_active = active_procs;

  /* pass back a handle */
  handle.next_proc = pref;
  handle.remaining = active_procs;
  return ((caddr_t) & handle);
}

char fmt[128];   /* static area where result is built */

char *
format_next_process (handle, get_userid)
     caddr_t handle;
     char *(*get_userid) ();
{
  register struct prpsinfo *pp;
  struct handle *hp;
  register long cputime;
  register double pctcpu;

  /* find and remember the next proc structure */
  hp = (struct handle *) handle;
  pp = *(hp->next_proc++);
  hp->remaining--;

  /* get the cpu usage and calculate the cpu percentages */
  cputime = pp->pr_time.tv_sec;
  pctcpu = percent_cpu (pp);

  /* format this entry */
  sprintf (fmt,
    Proc_format,
    pp->pr_pid,
    (*get_userid) (pp->pr_uid),
    pp->pr_pri - PZERO,
    pp->pr_nice - NZERO,
#ifdef sun
    pp->pr_bysize / 1024,
    pp->pr_byrssize / 1024,
#else
    pagetok (pp->pr_size),
    pagetok (pp->pr_rssize),
#endif
    state_abbrev[pp->pr_state],
    cputime / 60l,
    cputime % 60l,
    (pp->pr_cpu & 0377),
    100.0 * pctcpu,
    pp->pr_fname);
/*            pp->pr_fname ); */

  /* return the result */
  return (fmt);
}

/*
* check_nlist(nlst) - checks the nlist to see if any symbols were not
*  found.  For every symbol that was not found, a one-line
*  message is printed to stderr.  The routine returns the
*  number of symbols NOT found.
*/
int
check_nlist (nlst)
     register struct nlist *nlst;
{
  register int i;

  /* check to see if we got ALL the symbols we requested */
  /* this will write one line to stderr for every symbol not found */

  i = 0;
  while (nlst->n_name != NULL)
    {
      if (nlst->n_type == 0)
{
   /* this one wasn't found */
   fprintf (stderr, "kernel: no symbol named `%s'n", nlst->n_name);
   i = 1;
}   nlst++;
    } return (i);
}


/*
*  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
* "offset" is the byte offset into the kernel for the desired value,
*   "ptr" points to a buffer into which the value is retrieved,
*   "size" is the size of the buffer (and the object to retrieve),
*   "refstr" is a reference string used when printing error meessages,
*     if "refstr" starts with a '!', then a failure on read will not
*       be fatal (this may seem like a silly way to do things, but I
*       really didn't want the overhead of another argument).
*
*/
getkval (offset, ptr, size, refstr)
     unsigned long offset;
     int *ptr;
     int size;
     char *refstr;
{
  if (lseek (kmem, (long) offset, 0) == -1)
    {
      if (*refstr == '!')
{
   refstr++;
}
      fprintf (stderr, "%s: lseek to %s: %sn",
        KMEM, refstr, sys_errlist[errno]);
      quit (22);
    }
  if (read (kmem, (char *) ptr, size) == -1)
    {
      if (*refstr == '!')
{
   /* we lost the race with the kernel, process isn't in memory */
   return (0);
}
      else
{
   fprintf (stderr, "%s: reading %s: %sn",
     KMEM, refstr, sys_errlist[errno]);
   quit (23);
}
    } return (1);
}

/* comparison routine for qsort */

/*
*  proc_compare - comparison function for "qsort"
* Compares the resource consumption of two processes using five
*   distinct keys.  The keys (in descending order of importance) are:
*   percent cpu, cpu ticks, state, resident set size, total virtual
*   memory usage.  The process states are ordered as follows (from least
*   to most important):  WAIT, zombie, sleep, stop, start, run.  The
*   array declaration below maps a process state index into a number
*   that reflects this ordering.
*/


unsigned char sorted_state[] =
{
  0,    /* not used  */
  3,    /* sleep  */
  6,    /* run   */
  2,    /* zombie  */
  4,    /* stop   */
  5,    /* start  */
  7,    /* run on a processor   */
  1    /* being swapped (WAIT) */
};

proc_compare (pp1, pp2)
     struct prpsinfo **pp1;
     struct prpsinfo **pp2;
{
  register struct prpsinfo *p1;
  register struct prpsinfo *p2;
  register long result;

  /* remove one level of indirection */
  p1 = *pp1;
  p2 = *pp2;

  /* compare percent cpu (pctcpu) */
  if ((result = (long) (p2->pr_cpu - p1->pr_cpu)) == 0)
    {
      /* use cpticks to break the tie */
      if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
{
   /* use process state to break the tie */
   if ((result = (long) (sorted_state[p2->pr_state] -
    sorted_state[p1->pr_state])) == 0)
     {
       /* use priority to break the tie */
       if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0)
  {
    /* use resident set size (rssize) to break the tie */
    if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
      {
        /* use total memory to break the tie */
        result = (p2->pr_size - p1->pr_size);
      }
  }  }
}
    } return (result);
}

/*
get process table
V.4 only has a linked list of processes so we want to follow that
linked list, get all the process structures, and put them in our own
table
*/
getptable (baseptr)
     struct prpsinfo *baseptr;
{
  struct prpsinfo *currproc; /* pointer to current proc structure */
  int numprocs = 0;
  DIR *procdir;
  struct dirent *direntp;
  int fd;
  char fname[40];

  if ((procdir = opendir (PROCFS)) == NULL)
    {
      fprintf (stderr, "%s: Unable to open %sn", myname, PROCFS);
      exit (1);
    }

  while (((direntp = readdir (procdir)) != NULL) && (numprocs < nproc))
    {
      if ((!strcmp (direntp->d_name, ".")) || (!strcmp (direntp->d_name, "..")))
{
   continue;
}
      strcpy (fname, PROCFS);
      strcat (fname, "/");
      strcat (fname, direntp->d_name);
      if ((fd = open (fname, O_RDONLY)) < 0)
{
/*    fprintf(stderr,"%s: Unable to open %sn",myname, direntp->d_name); */
   close (fd);
   continue;
}
      currproc = &baseptr[numprocs];
      if (ioctl (fd, PIOCPSINFO, currproc) < 0)
{
/*    fprintf(stderr,"%s: Unable to get info from %sn", myname, direntp->d_name); */
   close (fd);
   continue;
}
      numprocs++;
      close (fd);
    }
  closedir (procdir);
  if (nproc != numprocs)
    nproc = numprocs;
}





62   [Unix/Linux] [강좌] 인텔 센트리노 무선랜 카드: ndiswrapper  김영대 2004/06/27 10841 1932
  [Unix/Linux] [소스] top for System V Release 4, Intel or Sparc CPU  김영대 2004/02/20 6482 1121
60   [Unix/Linux] [소스] top for SunOS 5.x (Solaris 2.x)  김영대 2004/02/20 8737 1166
59   [Unix/Linux] [소스] String 해쉬(hash) 함수  김영대 2003/07/29 6202 1383
58   [Unix/Linux] [강좌] 웹로그분석을 위한 Webalizer + GDlib + PNGlib + Zlib 설치  김영대 2003/05/04 7026 1344
57   [Unix/Linux] [강좌] Apache + MySQL + PHP4 + Zend Optimizer 설치  김영대 2003/04/15 6082 1320
56   [Unix/Linux] [System V IPC] shmop() function - 공유메모리  김영대 2003/03/17 5639 1376
55   [Unix/Linux] [System V IPC] shmctl() function - 공유메모리  김영대 2003/03/17 5659 1526
54   [Unix/Linux] [System V IPC] shmget() function - 공유메모리  김영대 2003/03/17 5997 1504
53   [Unix/Linux] [System V IPC] semop() function - 세마포어  김영대 2003/03/17 4872 1286
52   [Unix/Linux] [System V IPC] semctl() function - 세마포어  김영대 2003/03/17 4544 1253
51   [Unix/Linux] [System V IPC] semget() function - 세마포어  김영대 2003/03/17 5636 1508
50   [Unix/Linux] [System V IPC] msgget() function - 메세지큐  김영대 2003/03/17 5549 1423
49   [Unix/Linux] [System V IPC] msgctl() function - 메세지큐  김영대 2003/03/17 5636 1319
48   [Unix/Linux] [System V IPC] msgrcv() function - 메세지큐  김영대 2003/03/17 6051 1550
47   [Unix/Linux] [System V IPC] msgsnd() function - 메세지큐  김영대 2003/03/17 7394 1489
46   [Unix/Linux] [POSIX IPC] 생산자/소비자 - 세마포어  김영대 2003/03/17 7016 1452
45   [Unix/Linux] [POSIX IPC] mq_receive() function - 메세지큐  김영대 2003/03/17 6499 1589
44   [Unix/Linux] [POSIX IPC] mq_send() function - 메세지큐  김영대 2003/03/17 7626 1507
43   [Unix/Linux] [Thread] pthread_cond() function  김영대 2003/03/17 5782 1544

1 [2][3][4]
 

Copyright 1999-2017 Zeroboard / skin by zero