SUMMARY: How much memory?

From: Alastair Young (alastair@eucad.co.uk)
Date: Wed Feb 12 1992 - 16:52:51 CST


Original question:

  Is there a method of discovering how much physical memory is installed
  without actually rebooting? eg looking into the running kernel with
  adb?

  I need to ascertain which of our systems are under-memoried. Some have been
  up for so long the boot messages are no longer in /usr/adm.

  Thanks in advance

  Alastair Young
  Systems Supervisor
  EuCAD

  alastair@eucad.co.uk

Many, many responses, some with suggestions that do work, some which don't.
Thanks to you all.

First the unreliable ones.

dd if=/dev/mem of=/dev/null bs=1024

or

wc -c /dev/mem

These gave the incorrect answer of 20Mb on our 40Mb machine.

Several people suggested using "dmesg". This only works if the system has been
relatively recently rebooted as it takes its infomation from the
/usr/adm/messages files. As our machines tend to be pretty reliable, (highest
uptime is currently 186 days, about half the machines have been up for over
a month) several of the machines could not provide the info in this way.

One I discovered myself is to run

adb -k /vmunix /dev/mem

this will respond with

physmem nnf3

where nn is a hex number. For sun4c add one, for sun3 add one and double it.
This will give the number of megabytes.

SOme people posted me scripts which utilise adb. I will not post these
here, as I was also posted some spiffy c programs to do the job.

I have tried the first of these, and it seems to work just dandy.

From: kensmith@cs.Buffalo.edu (Ken Smith)

/*
 * mem.c - print physical memory installed in a machine
 *
 * $Author: kensmith $
 *
 * $Date: 90/03/12 14:18:18 $
 *
 * $Log: mem.c,v $
 * Revision 1.2 90/03/12 14:18:18 kensmith
 * misc. cleanup
 *
 * Revision 1.1 90/02/09 21:43:41 kensmith
 * Initial revision
 *
 */

static char rcsid[] = "$Id: mem.c,v 1.2 90/03/12 14:18:18 kensmith Exp Locker: kensmith $";

#include <stdio.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/file.h>
#include <nlist.h>

struct nlist nls[] = {
        { "_physmem" },
#define PHYSMEM 0
        { "" },
};

int fd, physmem;

char *name; /* program name */
char *rindex();

main(argc, argv)
        int argc;
        char *argv[];
{
        if ((name = rindex(argv[0], '/')) == NULL)
                name = argv[0];
        else
                name++;
        if (nlist("/vmunix", nls) < 0) {
                perror("nlist");
                exit(1);
        }
        if ((fd = open("/dev/kmem", O_RDONLY)) <= 0) {
                perror("/dev/kmem");
                exit(1);
        }
        if (nls[PHYSMEM].n_type == 0) {
                fprintf(stderr, "%s: physmem symbol not found\n", name);
                exit(1);
        }
        lseek(fd, nls[PHYSMEM].n_value, L_SET);
        read(fd, &physmem, sizeof(physmem));
        printf("%dK bytes of memory\n", ctob(physmem) / 1024);
}

I tried tthis and it worked, but one user did have a warning about it:

From: johbro@johbro.Auto-trol.com (John Brown)

   If you get an acceptable answer, I would be interested in a copy. If you
don't get anything more interesting, here is a "sort of" solution. It is a
C program that is supposed to determine memory size. I got this from some
forgotton place and don't know exactly how it works and so can't fix the
problems it has. The basic problem is that it either reports the correct
amount of memory or reports exactly half the memory. If run on the same
machine at two different times, it may give either answer. It seems to be
related to load on the machine and to some sort of memory pagesize that
changes dynamically. If you know more about kernal memory structures you
might be able to figure out how to correct it. I should note that I have
tweeked it a little bit so that the same program can be compiled for
sun3,sun386i,sun4,dec platforms and will work, though all exibit the full
or half memory problems.

Two other c progs that people posted that I haven't tried:
/*
 * Figure out how much memory there is on a machine. This works under
 * Berkeley UNIX. It should work under System V if you change the
 * UNIX define to "/unix" instead of "/vmunix".
 *
 * Of course, if you don't have read permission on the kernel and
 * kernel memory, this won't work.
 *
 * Dave Curry
 * Purdue University
 * Engineering Computer Network
 *
 * Hacked by Larry Breniser 10/1/91
 * Pagesize is now determied dynamically, not at copile
 * time, as it varies from host to host (server vs workstation)
 *
 * davy@intrepid.ecn.purdue.edu
 * $Header: /usr2/larryb/c/RCS/physmem.c,v 1.3 91/10/02 17:51:10 larryb Exp $
 * $Log: physmem.c,v $
 * Revision 1.3 91/10/02 17:51:10 larryb
 * Added Version string to executable for ident.
 *
 * Revision 1.2 91/10/02 17:46:21 larryb
 * Added RCS log comments.
 *
 */
#include <sys/param.h>
#include <sys/types.h>
#include <nlist.h>
#include <stdio.h>

char version[] = "$Header: /usr2/larryb/c/RCS/physmem.c,v 1.3 91/10/02 17:51:10 larryb Exp $";

#define UNIX "/vmunix"
#define KMEM "/dev/kmem"

struct nlist nl[] = {
#define X_PHYSMEM 0
        { "_physmem" },
#define X_MAXMEM 1
        { "_maxmem" },
        { NULL }
};

main()
{
        int kmem;
        int maxmem, physmem;
        int pagesize;

        /*
         * Look up addresses of variables.
         */
        if ((nlist(UNIX, nl) < 0) || (nl[0].n_type == 0)) {
                fprintf(stderr, "%s: no namelist.\n", UNIX);
                exit(1);
        }

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

        /*
         * Read variables.
         */
        lseek(kmem, (long) nl[X_PHYSMEM].n_value, 0);
        read(kmem, (char *) &physmem, sizeof(int));

        lseek(kmem, (long) nl[X_MAXMEM].n_value, 0);
        read(kmem, (char *) &maxmem, sizeof(int));

        close(kmem);

        pagesize=getpagesize();

        /*
         * Print the numbers. The internal representation is
         * in units of core clicks; convert to bytes.
         */

        printf("Pagesize: %d\n", pagesize);

        printf("Physical machine memory: %d\n", pagesize * physmem);
        printf("Max memory available to a process: %d\n", pagesize * maxmem);

        exit(0);
}

/*
 * Program to determine the size installed physical memory on Suns.
 *
 * Casper Dik.
 */

#define MEGABYTE 0x00100000
#define MAXMEM 0x7ff00000
#define THEMEM "/dev/mem"

#include <stdio.h>
#include <fcntl.h>

main() {
    int fd = open(THEMEM,O_RDONLY);
    char c;
    unsigned long pos, mapstart = 0;
    int totmb = 0;

    if (fd == -1) {
        perror(THEMEM);
        exit(1);
    }
    for (pos = 0; pos < MAXMEM; pos += MEGABYTE) {
        if (lseek(fd,pos,0) == -1) {
            perror("lseek");
            exit(1);
        }
        if (read(fd,&c,1) == -1) {
            int size = (pos-mapstart)/MEGABYTE;
            if (size != 0) {
                printf("found %3d MB starting at 0x%08x\n", size,mapstart);
                totmb += size;
            }
            mapstart = pos + MEGABYTE; /* start of next possible mapping */
        }
    }
    printf("Total memory size: %d MB\n",totmb);
    exit(0);
}

----- End Included Message -----

----- Begin Included Message -----

/*
 * Figure out how much memory there is on a machine. This works under
 * Berkeley UNIX. It should work under System V if you change the
 * UNIX define to "/unix" instead of "/vmunix".
 *
 * Of course, if you don't have read permission on the kernel and
 * kernel memory, this won't work.
 *
 * Dave Curry
 * Purdue University
 * Engineering Computer Network
 *
 * Hacked by Larry Breniser 10/1/91
 * Pagesize is now determied dynamically, not at copile
 * time, as it varies from host to host (server vs workstation)
 *
 * davy@intrepid.ecn.purdue.edu
 * $Header: /usr2/larryb/c/RCS/physmem.c,v 1.3 91/10/02 17:51:10 larryb Exp $
 * $Log: physmem.c,v $
 * Revision 1.3 91/10/02 17:51:10 larryb
 * Added Version string to executable for ident.
 *
 * Revision 1.2 91/10/02 17:46:21 larryb
 * Added RCS log comments.
 *
 */

#include <sys/param.h>
#include <sys/types.h>
#include <nlist.h>
#include <stdio.h>

char version[] = "$Header: /usr2/larryb/c/RCS/physmem.c,v 1.3 91/10/02 17:51:10 larryb Exp $";

#define UNIX "/vmunix"
#define KMEM "/dev/kmem"
#ifndef dgm
#define MEG (1024 * 1024)
#endif

struct nlist nl[] =
{
#define X_PHYSMEM 0
        { "_physmem" },
#define X_MAXMEM 1
        { "_maxmem" },
        { NULL }
};

main()
{
        int kmem;
        int maxmem, physmem;
        int pagesize;

/* Look up addresses of variables. */
        if ((nlist(UNIX, nl) < 0) || (nl[0].n_type == 0))
        {
                fprintf(stderr, "%s: no namelist.\n", UNIX);
                exit(1);
        }

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

/* Read variables. */
        lseek(kmem, (long) nl[X_PHYSMEM].n_value, 0);
        read(kmem, (char *) &physmem, sizeof(int));

        lseek(kmem, (long) nl[X_MAXMEM].n_value, 0);
        read(kmem, (char *) &maxmem, sizeof(int));

        close(kmem);

        pagesize=getpagesize();
        printf("%d byte pages\n", pagesize);

/* convert to bytes */
        physmem *= pagesize;
        maxmem *= pagesize;

/* print the numbers in Mbytes */
        printf("%0.3f MB of physical memory\n", (float)physmem / (float)MEG);
        printf("%0.3f MB available to a process\n", (float)maxmem / (float)MEG);

        exit(0);
}

----- End Included Message -----

----- End Included Message -----



This archive was generated by hypermail 2.1.2 : Fri Sep 28 2001 - 23:06:36 CDT