Subject: Re: Getting current memory utilitization from Solaris 2.3

From: [email-masked] (Brett T. McCoy)
Date: 16 May 1994 00:14:13 -0500

In article <[email-masked]>,
Steve V. Yalovitser <[email-masked]> wrote:
>Hiya,
>
>	Is there a tool available to get current memory utilization 
>under Solaris 2.3 . I hacked top to give me what I need for SunOS and
>HP-UX 4.1.3/9.01 ... Is there anything like that with Solaris 2.3. Thanks
>in advance

Check out eecs.nwu.edu:/pub/top/top-3.3beta3.tar.gz.  It works for
Solaris 2.1 and above.  You may want to apply the following patch to
the "machine" directory it.  This patch fixes support for
muliprocessor boxes, and makes top get it's information from
/dev/kstat instead of grunging around in kernel memory for it (should
be more portable in the future).

Brett McCoy, UNIX Systems Administrator
Computing and Network Services
Kansas State University,  Manhattan KS  66506
vox: (913) 532-4908 / fax: (913) 532-5914 / e-mail: [email-masked]

======================================================================
*** /tmp/T0a004fK	Fri Apr 29 02:15:54 1994
--- m_sunos5.c	Fri Apr 29 02:14:53 1994
***************
*** 14,20 ****
   *     Tested on a SPARCclassic with SunOS 5.1, using gcc-2.3.3, and
   *     SPARCsystem 600 with SunOS 5.2, using Sun C
   *
!  * LIBS: -R/usr/lib -lelf -lkvm
   *
   *
   * AUTHORS:      Torsten Kasch 		<[email-masked]>
--- 14,20 ----
   *     Tested on a SPARCclassic with SunOS 5.1, using gcc-2.3.3, and
   *     SPARCsystem 600 with SunOS 5.2, using Sun C
   *
!  * LIBS: -R/usr/lib -lelf -lkvm -lkstat
   *
   *
   * AUTHORS:      Torsten Kasch 		<[email-masked]>
***************
*** 36,41 ****
--- 36,42 ----
  #include <dirent.h>
  #include <nlist.h>
  #include <string.h>
+ #include <kstat.h>
  #include <kvm.h>
  #include <sys/types.h>
  #include <sys/param.h>
***************
*** 82,124 ****
  #define pagetok(size) ctob(size) >> LOG1024
  
  /* definitions for indices in the nlist array */
! #define X_AVENRUN		 0
! #define X_MPID			 1
! #define X_CPU			 2
! #define X_V			 3
! #define X_NPROC			 4
! #define X_ANONINFO		 5
! #define X_FREEMEM		 6
! #define X_MAXMEM		 7
! #define X_AVAILRMEM		 8
! #define X_SWAPFS_MINFREE	 9
! #define X_NCPUS		   	10
  
  static struct nlist nlst[] =
  {
!   {"avenrun"},			/* 0 */
!   {"mpid"},			/* 1 */
!   {"cpu"},			/* 2 */
!   {"v"},			/* 3 */
!   {"nproc"},			/* 4 */
!   {"anoninfo"},			/* 5 */
!   {"freemem"},			/* 6 */
!   {"maxmem"},			/* 7 */
!   {"availrmem"},		/* 8 */
!   {"swapfs_minfree"},		/* 9 */
!   {"ncpus"},			/* 10 */
    {0}
  };
  
- static unsigned long avenrun_offset;
  static unsigned long mpid_offset;
- static unsigned long *cpu_offset;
- static unsigned long nproc_offset;
- static unsigned long freemem_offset;
  static unsigned long maxmem_offset;
- static unsigned long availrmem_offset;
- static unsigned long swapfs_minfree_offset;
- static unsigned long anoninfo_offset;
  
  /* get_process_info passes back a handle.  This is what it looks like: */
  struct handle
--- 83,100 ----
  #define pagetok(size) ctob(size) >> LOG1024
  
  /* definitions for indices in the nlist array */
! #define X_MPID			 0
! #define X_MAXMEM		 1
  
  static struct nlist nlst[] =
  {
!   {"mpid"},			/* 0 */
!   {"maxmem"},			/* 1 */
    {0}
  };
  
  static unsigned long mpid_offset;
  static unsigned long maxmem_offset;
  
  /* get_process_info passes back a handle.  This is what it looks like: */
  struct handle
***************
*** 180,192 ****
  /* 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};
  
  kvm_t *kd;
  static DIR *procdir;
  static int nproc;
  static int ncpus;
! static int mcpus;
  
  /* these are for keeping track of the proc array */
  static int bytes;
--- 156,172 ----
  /* these are for detailing the memory statistics */
  int memory_stats[5];
  char *memorynames[] =
! {"K real, ", "K kernel, ", "K free, ", "K swap, ", "K free swap", NULL};
  
  kvm_t *kd;
+ kstat_ctl_t	*kstat_ctl;
  static DIR *procdir;
  static int nproc;
  static int ncpus;
! static int pagesize;
! static int *cpu_stats;
! static sysinfo_t	sysinfo;
! static vminfo_t		vminfo;
  
  /* these are for keeping track of the proc array */
  static int bytes;
***************
*** 201,206 ****
--- 181,188 ----
  extern int check_nlist ();
  extern int gettimeofday ();
  extern int getkval ();
+ extern int get_system_misc ();
+ extern int getkstatval ();
  extern void perror ();
  extern void getptable ();
  extern void quit ();
***************
*** 211,217 ****
    {
      static struct var v;
      struct oldproc *op, *endbase;
!     int i;
      processor_info_t pi;
      /* fill in the statics information */
      statics->procstate_names = procstatenames;
--- 193,202 ----
    {
      static struct var v;
      struct oldproc *op, *endbase;
!     int		n, i;
!     kstat_t		*kstat;
!     kstat_named_t	*kstat_named;
!     char	buf[32];
      processor_info_t pi;
      /* fill in the statics information */
      statics->procstate_names = procstatenames;
***************
*** 218,223 ****
--- 203,214 ----
      statics->cpustate_names = cpustatenames;
      statics->memory_names = memorynames;
  
+     pagesize = sysconf(_SC_PAGESIZE);
+ 
+     if ((kstat_ctl = kstat_open()) == NULL) {
+ 	perror("kstat_open");
+ 	return(-1);
+     }
      if ((kd = kvm_open (NULL, NULL, NULL, O_RDONLY, "top")) == NULL)
        {
  	perror ("kvm_open");
***************
*** 232,263 ****
        return (-1);
  
      /* 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;
-     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;
  
!     (void) getkval (nlst[X_NCPUS].n_value, (int *) (&ncpus),
! 		    sizeof (ncpus), "ncpus");
  
!     cpu_offset = (unsigned long *) malloc (ncpus * sizeof (unsigned long));
!     (void) getkval (nlst[X_CPU].n_value, cpu_offset,
! 		    ncpus * sizeof (unsigned long), nlst[X_CPU].n_name);
  
-     /* set mcpus to indicate highest used slot */
-     mcpus = ncpus;
-     while (--mcpus > 0 && cpu_offset[mcpus] == 0);
-     mcpus++;
-     /* ASSERT: mcpus > 0 */
- 
      /* allocate space for proc structure array and array of pointers */
      bytes = nproc * PRPSINFOSIZE;
      pbase = (struct prpsinfo *) malloc (bytes);
--- 223,255 ----
        return (-1);
  
      /* NPROC Tuning parameter for max number of processes */
!     getkstatval("unix", 0, "var", &v);
      nproc = v.v_proc;
+     getkstatval("unix", 0, "sysinfo", &sysinfo);
+     getkstatval("unix", 0, "vminfo", &vminfo);
  
      /* stash away certain offsets for later use */
      mpid_offset = nlst[X_MPID].n_value;
      maxmem_offset = nlst[X_MAXMEM].n_value;
  
!     ncpus = get_system_misc("ncpus");
  
!     /*
!      * figure out which cpu's are installed and record the fact
!      * so we know which cpu's to get info for
!      */
!     cpu_stats = (int *) malloc(ncpus * sizeof(int));
!     n = 0;
!     i = 0;
!     while (n < ncpus) {
! 	sprintf(buf, "cpu_stat%d", i);
! 	if (kstat = kstat_lookup(kstat_ctl, "cpu_stat", i, buf)) {
! 	    cpu_stats[n] = i;
! 	    n++;
! 	}
! 	i++;
!     }
  
      /* allocate space for proc structure array and array of pointers */
      bytes = nproc * PRPSINFOSIZE;
      pbase = (struct prpsinfo *) malloc (bytes);
***************
*** 312,341 ****
  {
    long avenrun[3];
    struct cpu cpu;
!   static int freemem;
!   static int maxmem;
!   static int availrmem;
!   static int swapfs_minfree;
!   struct anoninfo anoninfo;
    static long cp_time[CPUSTATES];
    static long cp_old[CPUSTATES];
    static long cp_diff[CPUSTATES];
    register int j, i;
  
    /* get the cp_time array */
    for (j = 0; j < CPUSTATES; j++)
      cp_time[j] = 0L;
  
!   for (i = 0; i < mcpus; i++)
!     if (cpu_offset[i] != NULL)
!     {
!       (void) getkval (cpu_offset[i], &cpu, sizeof (struct cpu), "cpu");
        for (j = 0; j < CPUSTATES-1; j++)
! 	cp_time[j] += (long) cpu.cpu_stat.cpu_sysinfo.cpu[j];
!       cp_time[CPUSTATES-2] += (long) cpu.cpu_stat.cpu_sysinfo.wait[W_IO] +
!                               (long) cpu.cpu_stat.cpu_sysinfo.wait[W_PIO];
!       cp_time[CPUSTATES-1] += (long) cpu.cpu_stat.cpu_sysinfo.wait[W_SWAP];
!     }
  
    /* convert cp_time counts to percentages */
    (void) percentages (CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
--- 304,340 ----
  {
    long avenrun[3];
    struct cpu cpu;
!   cpu_stat_t	cpu_stat;
!   static ulong	updates;
!   static ulong	freemem;
!   static ulong	maxmem;
!   static ulong  kmem;
!   static int	phys_pages;
!   static sysinfo_t	new_sysinfo;
!   static vminfo_t	new_vminfo;
!   static kmeminfo_t	kmeminfo;
!   static ulong used_swap;
!   static ulong free_swap;
    static long cp_time[CPUSTATES];
    static long cp_old[CPUSTATES];
    static long cp_diff[CPUSTATES];
    register int j, i;
+   kstat_t	*kstat;
+   char		buf[32];
  
    /* get the cp_time array */
    for (j = 0; j < CPUSTATES; j++)
      cp_time[j] = 0L;
  
!   for (i = 0; i < ncpus; i++) {
!       sprintf(buf, "cpu_stat%d", cpu_stats[i]);
!       getkstatval("cpu_stat", cpu_stats[i], buf, &cpu_stat);
        for (j = 0; j < CPUSTATES-1; j++)
! 	cp_time[j] += (long) cpu_stat.cpu_sysinfo.cpu[j];
!       cp_time[CPUSTATES-2] += (long) cpu_stat.cpu_sysinfo.wait[W_IO] +
!                               (long) cpu_stat.cpu_sysinfo.wait[W_PIO];
!       cp_time[CPUSTATES-1] += (long) cpu_stat.cpu_sysinfo.wait[W_SWAP];
!   }
  
    /* convert cp_time counts to percentages */
    (void) percentages (CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
***************
*** 344,367 ****
    (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid), "mpid");
  
    /* get load average array */
!   (void) getkval (avenrun_offset, (int *) avenrun, sizeof (avenrun), "avenrun");
  
    /* convert load averages to doubles */
    for (i = 0; i < 3; i++)
      si->load_avg[i] = loaddouble (avenrun[i]);
  
    /* get system wide main memory usage structure */
!   (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);
!   (void) getkval (anoninfo_offset, (int *) (&anoninfo), sizeof (anoninfo), "anoninfo");
!   (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 ((int) (anoninfo.ani_max - anoninfo.ani_resv), 0) + availrmem - swapfs_minfree);
  
    /* set arrays and strings */
    si->cpustates = cpu_states;
    si->memory = memory_stats;
--- 343,387 ----
    (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid), "mpid");
  
    /* get load average array */
!   avenrun[0] = get_system_misc("avenrun_1min");
!   avenrun[1] = get_system_misc("avenrun_5min");
!   avenrun[2] = get_system_misc("avenrun_15min");
  
    /* convert load averages to doubles */
    for (i = 0; i < 3; i++)
      si->load_avg[i] = loaddouble (avenrun[i]);
  
+   getkstatval("unix", 0, "sysinfo", &new_sysinfo);
+   getkstatval("unix", 0, "vminfo", &new_vminfo);
+   getkstatval("unix", 0, "kmeminfo", &kmeminfo);
+ 
    /* get system wide main memory usage structure */
! 
!   updates = new_sysinfo.updates - sysinfo.updates;
!   if (! updates)
!       updates = 1;
!   freemem = (new_vminfo.freemem - vminfo.freemem) / updates;
!   used_swap = (new_vminfo.swap_resv - vminfo.swap_resv) / updates;
!   free_swap = (new_vminfo.swap_avail - vminfo.swap_avail) / updates;
! 
!   phys_pages = sysconf(_SC_PHYS_PAGES);
!   kmem = ((kmeminfo.km_mem[0] + kmeminfo.km_mem[1] +
! 	  kmeminfo.km_alloc[2]) / pagesize);
! 
!   if (phys_pages > 0)
!       maxmem = phys_pages - kmem;
!   else
!       (void) getkval (maxmem_offset, &maxmem, sizeof (maxmem), "maxmem");
! 
    memory_stats[0] = pagetok (maxmem);
!   memory_stats[1] = pagetok (kmem);
    memory_stats[2] = pagetok (freemem);
!   memory_stats[3] = pagetok (used_swap);
!   memory_stats[4] = pagetok (free_swap);
  
+   sysinfo = new_sysinfo;
+   vminfo = new_vminfo;
+ 
    /* set arrays and strings */
    si->cpustates = cpu_states;
    si->memory = memory_stats;
***************
*** 387,393 ****
    int show_uid;
  
    /* Get current number of processes */
!   (void) getkval (nproc_offset, (int *) (&nproc), sizeof (nproc), "nproc");
  
    /* read all the proc structures */
    getptable (pbase);
--- 407,413 ----
    int show_uid;
  
    /* Get current number of processes */
!   nproc = get_system_misc("nproc");
  
    /* read all the proc structures */
    getptable (pbase);
***************
*** 544,549 ****
--- 564,633 ----
      }
    return (1);
  
+ }
+ 
+ /*
+  *  get_system_misc(variable) - get a misc system stat value
+  *	"variable" is the name of the variable to get the value for
+  */
+ int
+ get_system_misc(char *s)
+ {
+     kstat_t		*kstat;
+     kstat_named_t	*kstat_named;
+     int			n,
+ 			i;
+ 
+     if ((kstat = kstat_lookup(kstat_ctl, "unix", 0, "system_misc")) == NULL) {
+ 	perror("kstat_lookup");
+ 	return(-1);
+     }
+     kstat_named = (kstat_named_t *) malloc(kstat->ks_data_size);
+     n = kstat->ks_ndata;
+     kstat->ks_data = (void *) kstat_named;
+     if (kstat_read(kstat_ctl, kstat, NULL) < 0) {
+ 	perror("kstat_read");
+ 	return(-1);
+     }
+ 
+     for (i = 0; i < n, strcmp(s, kstat_named[i].name); i++);
+ 
+     if (i == n)
+ 	return(-1);
+ 
+     n = kstat_named[i].value.ul;
+     free(kstat_named);
+     return(n);
+ }
+ 
+ /*
+  *  getkstatval(module, instance, name, ptr) - get a kernal stat value
+  *	"module" is the name of the module containing the value
+  *	"instance" is the instance of the module
+  *	"name" is the name of the stat in the module
+  *  	"ptr" points to a buffer into which the value is retrieved,
+  */
+ int
+ getkstatval(char	*module,
+ 	    int		instance,
+ 	    char	*name,
+ 	    void	*value)
+ {
+     kstat_t	*kstat;
+ 
+     kstat = kstat_lookup(kstat_ctl, module, instance, name);
+     if (!kstat) {
+ 	perror("kstat_lookup");
+ 	return(-1);
+     }
+ 
+     kstat->ks_data = value;
+     if (kstat_read(kstat_ctl, kstat, NULL) < 0) {
+ 	perror("kstat_read");
+ 	return(-1);
+     }
+ 
+     return(0);
  }
  
  /* comparison routine for qsort */
*** /tmp/T0a004fK	Fri Apr 29 02:15:55 1994
--- m_sunos5.desc	Fri Apr 29 01:01:35 1994
***************
*** 14,20 ****
  Tested on a SPARCclassic with SunOS 5.1, using gcc-2.3.3, and
  SPARCsystem 600 with SunOS 5.2, using Sun C
  
! LIBS: -R/usr/lib -lelf -lkvm

  AUTHORS:      Torsten Kasch 		<[email-masked]>
--- 14,20 ----
  Tested on a SPARCclassic with SunOS 5.1, using gcc-2.3.3, and
  SPARCsystem 600 with SunOS 5.2, using Sun C
  
! LIBS: -R/usr/lib -lelf -lkvm -lkstat

  AUTHORS:      Torsten Kasch 		<[email-masked]>
======================================================================