Bill Allombert on Thu, 15 Jan 2004 22:57:04 +0100


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

patch for a `soft stack limit'


Hello PARI-dev,

I wrote a prototype patch that implement a soft limit on the stack size.

This a bit technical so here are the explanation:
1) The goal is to avoid unwanted "PARI stack overflow" error.
2) The patch implement 2 stack size:
  -- the real stack size allocated by GP from the system.
  -- the soft stack size, which is smaller than the real stack size.
3) PARI will advertise to the lowstack garbage collector the soft stack
   size.
4) When a "PARI stack overflow" condition would occur due to the 
   soft stack size being reached, the soft stack size is increased
   until it reach the real stack size. At this point "PARI stack
   overflow" condition will trigger an error.

What is the benefit ?
1) On system implement copy-on-write memory management like Linux,
memory allocated but never used take no system resource, so you can
allocate a very large stack to begin with without using more resource.
2) Without this patch the lowstack garbage collector will tend to use
a large fraction of the available stack even for a computation with
modest memory requirement.
3) This patch cause the lowstack garbage collector to try to make the
stack fit in the soft stack size.
4) This allow to start with a very large stack without wasting memory.

What do this patch:
1) At start up , the soft stack size is equal to the real stack size.
2) allocatemem() will change only the real stack size.
3) The soft stack size will increase automatically and write a warning
  ***   Warning: Increasing soft memory limit to xxxx.

How to check the memory usage:
The command 'ps aux' has two relevant fields : VSZ and RSS.
VSZ is the virtual memory allocated (linked to the real stack size)
RSS is the used memory (linked to the soft stack size)

This patch will not change the VSZ but some time will lower the RSS.

An example: try 
? allocatemem(10^8)
? Mod(3,2^8192+1)^(2^8192)

With gp              I get VSZ/RSS:104608 6516 
With gp -s 100000000 I get VSZ/RSS:104608 29232 

So with the same stack size, I managed to use 4 time less system
resource at the end.

Finding how to crash GP with this patch applied is left as an exercise
to the interested reader.

I fixed only new_chunk(). There are others routines that can raise
errpile but I consider this is a bug.

Cheers,
Bill.
Index: src/headers/paristio.h
===================================================================
RCS file: /home/cvs/pari/src/headers/paristio.h,v
retrieving revision 1.21
diff -u -r1.21 paristio.h
--- src/headers/paristio.h	10 Oct 2003 17:43:31 -0000	1.21
+++ src/headers/paristio.h	15 Jan 2004 21:28:16 -0000
@@ -24,7 +24,7 @@
 
 typedef struct stackzone
 {
-  pari_sp zonetop, bot, top, avma;
+  pari_sp zonetop, bot, top, vbot, avma;
   size_t memused;
 } stackzone;
 
@@ -71,7 +71,7 @@
 #define TEXSTYLE_PAREN	2
 #define TEXSTYLE_BREAK	4
 
-extern pari_sp avma,bot,top;
+extern pari_sp avma,bot,top,vbot;
 extern size_t memused;
 extern byteptr diffptr;
 extern entree  **varentries;
Index: src/kernel/none/level1.h
===================================================================
RCS file: /home/cvs/pari/src/kernel/none/level1.h,v
retrieving revision 1.43
diff -u -r1.43 level1.h
--- src/kernel/none/level1.h	19 Dec 2003 11:05:36 -0000	1.43
+++ src/kernel/none/level1.h	15 Jan 2004 21:28:17 -0000
@@ -135,7 +135,12 @@
 new_chunk(long x)
 {
   const GEN z = ((GEN) avma) - x;
-  if ((ulong)x > (ulong)((GEN)avma-(GEN)bot)) err(errpile);
+  if ((ulong)x > (ulong)((GEN)avma-(GEN)bot))
+  {
+    if ((ulong)x > (ulong)((GEN)avma-(GEN)vbot)) err(errpile);
+    bot=(pari_sp) z;
+    err(warner,"Increasing soft memory limit to %lu",top-bot);
+  }
 #ifdef MEMSTEP
   checkmemory(z);
 #endif
Index: src/language/init.c
===================================================================
RCS file: /home/cvs/pari/src/language/init.c,v
retrieving revision 1.212
diff -u -r1.212 init.c
--- src/language/init.c	19 Dec 2003 11:05:36 -0000	1.212
+++ src/language/init.c	15 Jan 2004 21:28:21 -0000
@@ -47,7 +47,7 @@
 ulong   DEBUGFILES, DEBUGLEVEL, DEBUGMEM, compatible;
 ulong   prec, precdl;
 ulong   init_opts = INIT_JMPm | INIT_SIGm;
-pari_sp bot = 0, top = 0, avma;
+pari_sp bot = 0, top = 0, vbot=0, avma;
 size_t memused;
 
 gp_data *GP_DATA = NULL;
@@ -569,22 +569,30 @@
 init_stack(size_t size)
 {
   size_t s = fix_size(size), old = 0;
-  if (bot)
+  if (vbot)
   {
-    old = top - bot;
-    free((void*)bot);
+    old = top - vbot;
+    free((void*)vbot);
   }
   /* NOT gpmalloc, memer would be deadly */
-  bot = (pari_sp)__gpmalloc(s);
-  if (!bot)
+  vbot = (pari_sp)__gpmalloc(s);
+  if (!vbot)
     for (s = old;; s>>=1)
     {
       if (!s) err(memer); /* no way out. Die */
       err(warner,"not enough memory, new stack %lu",s);
-      bot = (pari_sp)__gpmalloc(s);
-      if (bot) break;
+      vbot = (pari_sp)__gpmalloc(s);
+      if (vbot) break;
     }
-  avma = top = bot+s;
+  if (!bot)
+    bot=vbot;
+  else
+  { 
+    bot=(vbot+s)-(top-bot);
+    if (bot<vbot)
+      bot=vbot;
+  }
+  avma = top = vbot+s;
   memused = 0; return s;
 }
 
@@ -708,7 +716,7 @@
   while (cur_bloc) delete_from_bloclist(cur_bloc);
   killallfiles(1);
   free((void *)functions_hash);
-  free((void *)bot);
+  free((void *)vbot);
   free((void *)diffptr);
   free(current_logfile);
   free(current_psfile);
@@ -1181,7 +1189,7 @@
   if (numerr==errpile)
   {
     fprintferr("\n  current stack size: %lu (%.3f Mbytes)\n",
-      top-bot, (top-bot)/1048576.);
+      top-vbot, (top-vbot)/1048576.);
     fprintferr("  [hint] you can increase GP stack with allocatemem()\n");
   }
   pariOut = out;
@@ -1847,7 +1855,7 @@
 {
   if (!newsize)
   {
-    newsize = (top - bot) << 1;
+    newsize = (top - vbot) << 1;
     err(warner,"doubling stack size; new stack = %lu (%.3f Mbytes)",
                 newsize, newsize/1048576.);
   }
Index: src/test/kerntest.c
===================================================================
RCS file: /home/cvs/pari/src/test/kerntest.c,v
retrieving revision 1.7
diff -u -r1.7 kerntest.c
--- src/test/kerntest.c	19 Nov 2002 17:57:06 -0000	1.7
+++ src/test/kerntest.c	15 Jan 2004 21:28:21 -0000
@@ -2,7 +2,7 @@
 #include <anal.h>
 
 GEN   gzero, gun, gdeux;
-pari_sp top, bot, avma;
+pari_sp top, bot, vbot, avma;
 size_t memused = 0;
 ulong  DEBUGLEVEL,DEBUGMEM = 0;