Subject: kern/2755: Touching virtual memory==physical memory causes pathological
To: None <gnats-bugs@gnats.netbsd.org>
From: Jonathan Stone <jonathan@DSG.Stanford.EDU>
List: netbsd-bugs
Date: 09/14/1996 16:05:15
>Number: 2755
>Category: kern
>Synopsis: Exhausting memory causes a machine to freeze for up to a minute
>Confidential: yes
>Severity: critical
>Priority: high
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Sep 15 21:50:03 1996
>Last-Modified:
>Originator: Jonathan Stone
>Organization:
>Release: 1.2_BETA
>Environment:
System: NetBSD Cup.DSG.Stanford.EDU 1.2_BETA NetBSD 1.2_BETA (DSG) #47: Mon Jul 29 12:05:57 PDT 1996 jonathan@Cup.DSG.Stanford.EDU:/aga/n1/src/NetBSD/IP-PLUS/src/sys/arch/i386/compile/DSG i386
>Description:
NetBSD exhibits pathological behaviour somewhere in the VM system,
under at least some circumstances when the active memory (desired
working-set size) is greater than physical memory. I have replicated
the behaviour several times on a 64Mbyte machine. I describe the
bebaviour as "pathological" because (as observed from either local X
applications or remote logins from another machine) *all* processes on
the afflicted machine are blocked for 60 to 65 seconds.
During this time, X applications on the thrashing machine do not
repaint when iconified and de-iconified; the kernel answers TCP
connects to listening ports, but inetd can't seem to fork new daemons
(e.g., telnet gets a "connect" message but no login prompt, and a
telnet interrupt or "are you there" are not answered. system monitoring
tools also seem to get stopped.
Listening to the swap disk suggests that not much disk I/O activity
is taking place during the one-minute hiatus.
This is
>How-To-Repeat:
Compile and run the following program on a NetBSD/i386 machine, with
arguments "-v N", where N is the amount of physical memory, in megabytes,
installed in the machine. I find that on a 64Mbyte machine, the
pathological behaviour starts approximately when touching the 50th Mbyte.
Re-running the program on a previously-idle system forces idle processes
to get swapped out, and increases the amount of memory that can be touched
before the pathological regime is entered.
>Fix:
I dont have a clue.
>Audit-Trail:
>Unformatted:
>Sharfile of Example Program:
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# memtest.c
#
echo x - memtest.c
sed 's/^X//' >memtest.c << 'END-of-memtest.c'
X/*
X * Write test pattern into N megabytes of virtual memory.
X * May also induce thrashing or demonstrate VM performance problems
X * when the size tested is at or near physical memory size.
X */
X
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <unistd.h>
X
X#define ONE_MBYTE (1024* 1024)
X
X/*
X * Flags
X */
Xint verboseflag = 0;
Xint foreverflag = 0;
X
X
X/*
X * Fill a hunk of memory with a test pattern, then do a read-after-write
X * comparison.
X */
Xint
Xmemtest (int *mem, int size, int pattern)
X{
X register int i;
X
X for (i = 0; i < size; i++) {
X mem[i] = pattern ;
X }
X
X for (i = 0; i < size; i++) {
X if (mem[i] != pattern) {
X printf("failed at %p, should be 0x%x, is 0x%x\n",
X mem+i, pattern, mem[i]);
X ((volatile int*)mem)[i] = pattern ;
X if (mem[i] != pattern)
X printf("failed again at %p, should be 0x%x, is 0x%x\n",
X mem+i, pattern, mem[i]);
X }
X }
X}
X
Xvoid
Xusage()
X{
X extern char *__progname;
X printf("usage: %s [-v] [-f] <megabytes>\n", __progname);
X exit(2);
X}
X
X
Xint
Xparseopts(int argc, char *argv[])
X{
X extern int optind;
X int ch;
X
X while ((ch = getopt(argc, argv, "vf")) != -1) {
X switch (ch) {
X case 'v':
X verboseflag = 1;
X break;
X case 'f':
X foreverflag = 1;
X break;
X default:
X usage();
X }
X }
X
X argc -= optind;
X argv += optind;
X
X if (argc != 1) usage();
X
X return (atoi (argv[0]));
X}
X
X
X
Xint
Xmain(int argc, char *argv[])
X{
X void *p;
X int i, megs;
X
X megs = parseopts(argc, argv);
X p = (void*)malloc(ONE_MBYTE * megs);
X
Xtest:
X for (i = 0; i < megs; i++) {
X int *thishunk = p+(ONE_MBYTE*i);
X if (verboseflag)
X printf("testing: %d Mbytes\n", i);
X memtest(thishunk, (ONE_MBYTE / sizeof(int)), 0);
X memtest(thishunk, (ONE_MBYTE / sizeof(int)), 0xffffffff);
X memtest(thishunk, (ONE_MBYTE / sizeof(int)), 0xa5a5a5a5);
X memtest(thishunk, (ONE_MBYTE / sizeof(int)), 0x5a5a5a5a);
X memtest(thishunk, (ONE_MBYTE / sizeof(int)), 0);
X }
X if (foreverflag) goto test;
X}
END-of-memtest.c
exit