Skip to content
This repository was archived by the owner on Feb 1, 2023. It is now read-only.

Commit c7c058b

Browse files
author
Release Manager
committed
Trac #31395: RuntimeError: can't start new thread (due to memlimit)
My home machine can't run `sage -t` in 9.3.beta7: {{{ $ echo "" > foo.py $ sage -t foo.py too many failed tests, not using stored timings Running doctests with ID 2021-02-14-07-59-58-a18c55bc. Git branch: u/mjo/ticket/31382 Using --optional=build,dochtml,gentoo,memlimit,pip,sage,sage_spkg Doctesting 1 file. Process DocTestWorker-1: sage -t --random-seed=0 foo.py Traceback (most recent call last): File "/usr/lib/python3.9/multiprocessing/process.py", line 315, in _bootstrap self.run() File "/home/mjo/src/sage.git/local/lib/python3.9/site- packages/sage/doctest/forker.py", line 2179, in run task(self.options, self.outtmpfile, msgpipe, self.result_queue) File "/home/mjo/src/sage.git/local/lib/python3.9/site- packages/sage/doctest/forker.py", line 2529, in __call__ result_queue.put(result, False) File "/usr/lib/python3.9/multiprocessing/queues.py", line 94, in put self._start_thread() File "/usr/lib/python3.9/multiprocessing/queues.py", line 179, in _start_thread self._thread.start() File "/usr/lib/python3.9/threading.py", line 874, in start _start_new_thread(self._bootstrap, ()) RuntimeError: can't start new thread Bad exit: 1 ********************************************************************** Tests run before process (pid=13654) failed: ********************************************************************** ---------------------------------------------------------------------- sage -t --random-seed=0 foo.py # Bad exit: 1 ---------------------------------------------------------------------- Total time for all tests: 0.1 seconds cpu time: 0.0 seconds cumulative wall time: 0.0 seconds }}} Running strace on that command shows a bunch of ENOMEM: {{{ [pid 13910] mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory) }}} So I tried `--memlimit=0`, and that seems to work: {{{ $ sage -t -m 0 foo.py too many failed tests, not using stored timings Running doctests with ID 2021-02-14-08-08-27-1edc5213. Git branch: u/mjo/ticket/31382 Using --optional=build,dochtml,gentoo,pip,sage,sage_spkg Doctesting 1 file. sage -t --random-seed=0 foo.py [0 tests, 0.00 s] ---------------------------------------------------------------------- All tests passed! ---------------------------------------------------------------------- Total time for all tests: 0.0 seconds cpu time: 0.0 seconds cumulative wall time: 0.0 seconds }}} I think the default memlimit of 3300 MiB is arbitrary anyway, so maybe it just needs to be raised a little? A slight increase to `--memlimit=3400` solves the problem on that machine. URL: https://trac.sagemath.org/31395 Reported by: mjo Ticket author(s): Michael Orlitzky Reviewer(s): Dima Pasechnik
2 parents 9a1e3cc + cf0c05c commit c7c058b

File tree

6 files changed

+21
-70
lines changed

6 files changed

+21
-70
lines changed

src/bin/sage-runtests

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,6 @@ if __name__ == "__main__":
4343
callback=optional_argument, callback_args=(int, 0), nargs=0,
4444
metavar="N", help="tests in parallel using N threads with 0 interpreted as max(2, min(8, cpu_count()))")
4545
parser.add_option("-T", "--timeout", type=int, default=-1, help="timeout (in seconds) for doctesting one file, 0 for no timeout")
46-
parser.add_option("-m", "--memlimit", type=int, default=3300,
47-
help='maximum virtual memory to allow each test '
48-
'process, in megabytes; no limit if zero or less, '
49-
'but tests tagged "optional - memlimit" are '
50-
'skipped if no limit is set (default: 3300 MB)')
5146
parser.add_option("-a", "--all", action="store_true", default=False, help="test all files in the Sage library")
5247
parser.add_option("--logfile", metavar="FILE", help="log all output to FILE")
5348

@@ -135,39 +130,6 @@ if __name__ == "__main__":
135130
parser.print_help()
136131
sys.exit(2)
137132

138-
# Ensure that all doctests can be run with virtual memory limited to 3300
139-
# MiB (or a user-provided value). We must set this limit before starting
140-
# Sage. Note that this is a per-process limit, so we do not need to worry
141-
# about running multiple doctest processes in parallel. It is in
142-
# particular doctests in src/sage/schemes/elliptic_curves/heegner.py
143-
# which need this much memory.
144-
memlimit = options.memlimit << 20
145-
146-
# Python's resource module only supports limits up to sys.maxsize,
147-
# even if the OS does support higher limits.
148-
if 0 < memlimit <= sys.maxsize:
149-
import resource
150-
lim, hard = resource.getrlimit(resource.RLIMIT_AS)
151-
if lim == resource.RLIM_INFINITY or lim > memlimit:
152-
try:
153-
resource.setrlimit(resource.RLIMIT_AS, (memlimit, hard))
154-
except ValueError:
155-
options.memlimit = -1
156-
if sys.platform != 'cygwin':
157-
# RLIMIT_AS is not currently supported on Cygwin so
158-
# this will probably fail there:
159-
# https://trac.sagemath.org/ticket/23979
160-
raise
161-
else:
162-
if resource.RLIMIT_AS == getattr(resource, 'RLIMIT_RSS', None):
163-
# On some platforms (e.g. OSX) RLIMIT_AS is just an alias
164-
# for RLIMIT_RSS (see
165-
# https://trac.sagemath.org/ticket/24190)
166-
# In this case we still call setrlimit, but then disable
167-
# high mem tests since we don't want such tests to actually
168-
# cause us to run out of physical memory, leading to system
169-
# instability (as opposed to virtual memory allocs failing)
170-
options.memlimit = -1
171133
# Limit the number of threads to 2 to save system resources.
172134
# See Trac #23713, #23892, #30351
173135
if sys.platform == 'darwin':

src/sage/doctest/control.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ def __init__(self, **kwds):
9696
self.nthreads = 1
9797
self.serial = False
9898
self.timeout = -1
99-
self.memlimit = 0
10099
self.all = False
101100
self.logfile = None
102101
self.long = False
@@ -381,10 +380,6 @@ def __init__(self, options, args):
381380

382381
self.options = options
383382

384-
if options.memlimit > 0:
385-
# Allow tests that require a virtual memory limit to be set
386-
options.optional.add('memlimit')
387-
388383
self.files = args
389384
if options.logfile:
390385
try:
@@ -1013,7 +1008,7 @@ def _assemble_cmd(self):
10131008
for o in ("all", "long", "force_lib", "verbose", "failed", "new"):
10141009
if o in opt:
10151010
cmd += "--%s "%o
1016-
for o in ("timeout", "memlimit", "randorder", "stats_path"):
1011+
for o in ("timeout", "randorder", "stats_path"):
10171012
if o in opt:
10181013
cmd += "--%s=%s "%(o, opt[o])
10191014
if "optional" in opt:

src/sage/doctest/reporting.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -488,10 +488,6 @@ def report(self, source, timeout, return_code, results, output, pid=None):
488488
if not self.controller.options.long:
489489
if self.controller.options.show_skipped:
490490
log(" %s not run"%(count_noun(nskipped, "long test")))
491-
elif tag == "memlimit":
492-
if self.controller.options.memlimit <= 0:
493-
seen_other = True
494-
log(" %s not run"%(count_noun(nskipped, "memlimit")))
495491
elif tag == "not tested":
496492
if self.controller.options.show_skipped:
497493
log(" %s not run"%(count_noun(nskipped, "not tested test")))

src/sage/doctest/test.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -513,20 +513,6 @@
513513
....: except OSError:
514514
....: pass
515515
516-
Test the ``--memlimit`` option and ``# optional - memlimit``
517-
(but only on Linux). If this test fails, the memory needed to
518-
run it may have increased. Try increasing the limit. ::
519-
520-
sage: from platform import system
521-
sage: ok = True
522-
sage: from sage.cpython.string import bytes_to_str
523-
sage: if system() == "Linux":
524-
....: P = subprocess.Popen(["sage", "-t", "--warn-long", "0", "--random-seed=0", "--memlimit=2000", "memlimit.rst"], stdout=subprocess.PIPE, **kwds)
525-
....: out, err = P.communicate()
526-
....: ok = ("MemoryError: failed to allocate" in bytes_to_str(out))
527-
sage: ok or out
528-
True
529-
530516
Test that random tests are reproducible::
531517
532518
sage: subprocess.call(["sage", "-t", "--warn-long", "0", "--random-seed=0", "random_seed.rst"], **kwds) # long time
@@ -560,5 +546,4 @@
560546
----------------------------------------------------------------------
561547
...
562548
0
563-
564549
"""

src/sage/doctest/tests/memlimit.rst

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/sage/matrix/matrix_mod2_dense.pyx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,6 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse
168168
169169
Large matrices fail gracefully::
170170
171-
sage: MatrixSpace(GF(2), 2^30)(1) # optional - memlimit
172-
Traceback (most recent call last):
173-
...
174-
RuntimeError: matrix allocation failed
175171
sage: MatrixSpace(GF(2), 1, 2^40).zero()
176172
Traceback (most recent call last):
177173
...
@@ -180,6 +176,26 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse
180176
Traceback (most recent call last):
181177
...
182178
OverflowError: ...
179+
180+
Allocation fails if a memory limit is set (Linux only) lower
181+
than is needed to construct a matrix but still high enough
182+
that it doesn't crash the rest of SageMath::
183+
184+
sage: from platform import system
185+
sage: import resource
186+
sage: orig_soft, orig_hard = resource.getrlimit(resource.RLIMIT_AS)
187+
sage: if system() != "Linux":
188+
....: raise RuntimeError("matrix allocation failed")
189+
....: else:
190+
....: four_GiB = 4*1024^3
191+
....: resource.setrlimit(resource.RLIMIT_AS, (four_GiB, orig_hard))
192+
....: MatrixSpace(GF(2), 2^30)(1)
193+
Traceback (most recent call last):
194+
...
195+
RuntimeError: matrix allocation failed
196+
sage: resource.setrlimit(resource.RLIMIT_AS, (orig_soft, orig_hard))
197+
sage: (orig_soft, orig_hard) == resource.getrlimit(resource.RLIMIT_AS)
198+
True
183199
"""
184200
# m4ri assumes that nrows and ncols are of type rci_t:
185201
# check for overflow

0 commit comments

Comments
 (0)