# HG changeset patch
# User J. H. Palmieri
# Date 1321130698 28800
# Node ID 36ba7d92845214da7ef4c0554a85d409537cb352
# Parent 8d81fcf27e1444bfa3778c5fe2cc231c7f84d50a
#12016: document make ptestlong  how to set NUM_THREADS
diff git a/doc/en/developer/doctesting.rst b/doc/en/developer/doctesting.rst
 a/doc/en/developer/doctesting.rst
+++ b/doc/en/developer/doctesting.rst
@@ 9,20 +9,20 @@ its documentation. Testing can be perfor
multiple threads. After compiling a source version of Sage, doctesting
can be run on the whole Sage library, on all modules under a given
directory, or on a specified module only. For the purposes of this
chapter, suppose we have compiled Sage 4.1.1 from source and the top
+chapter, suppose we have compiled Sage 4.8 from source and the top
level Sage directory is
::
 [mvngu@sage sage4.1.1]$ pwd
 /scratch/mvngu/build/sage4.1.1
+ [mvngu@sage sage4.8]$ pwd
+ /scratch/mvngu/build/sage4.8
See the section :ref:`chaptertesting` for information on Sage's
automated testing process. The general syntax for doctesting is as
follows. To doctest a module in the library of a version of Sage, use
this syntax::
 /path/to/sagex.y.z/sage t [long] /path/to/sagex.y.z/path/to/module.py[x]
+ /path/to/sagex.y.z/sage t [long] /path/to/sagex.y.z/path/to/module.py[x]
where ``long`` is an optional argument. The version of ``sage`` used must
match the version of Sage containing the module we want to doctest. A
@@ 39,7 +39,7 @@ Say we want to run all tests in the sudo
top level Sage directory of our local Sage installation. Now we can
start doctesting as demonstrated in the following terminal session::
 [mvngu@sage sage4.1.1]$ ./sage t devel/sagemain/sage/games/sudoku.py
+ [mvngu@sage sage4.8]$ ./sage t devel/sagemain/sage/games/sudoku.py
sage t "devel/sagemain/sage/games/sudoku.py"
[6.0 s]
@@ 52,18 +52,16 @@ takes about six seconds, while testing a
same amount of time. In this case, we only tested one module so it is
not surprising that the total testing time is approximately the same
as the time required to test only that one module. Notice that the
syntax is
+syntax is ::
::

 [mvngu@sage sage4.1.1]$ ./sage t devel/sagemain/sage/games/sudoku.py
+ [mvngu@sage sage4.8]$ ./sage t devel/sagemain/sage/games/sudoku.py
sage t "devel/sagemain/sage/games/sudoku.py"
[5.7 s]

All tests passed!
Total time for all tests: 5.7 seconds
 [mvngu@sage sage4.1.1]$ ./sage t "devel/sagemain/sage/games/sudoku.py"
+ [mvngu@sage sage4.8]$ ./sage t "devel/sagemain/sage/games/sudoku.py"
sage t "devel/sagemain/sage/games/sudoku.py"
[5.4 s]
@@ 71,11 +69,9 @@ syntax is
All tests passed!
Total time for all tests: 5.4 seconds
but not
+but not ::
::

 [mvngu@sage sage4.1.1]$ ./sage t sage/games/sudoku.py
+ [mvngu@sage sage4.8]$ ./sage t sage/games/sudoku.py
ERROR: File ./sage/games/sudoku.py is missing
exit code: 1
@@ 84,7 +80,7 @@ but not
./sage/games/sudoku.py
Total time for all tests: 0.0 seconds
 [mvngu@sage sage4.1.1]$ ./sage t "sage/games/sudoku.py"
+ [mvngu@sage sage4.8]$ ./sage t "sage/games/sudoku.py"
ERROR: File ./sage/games/sudoku.py is missing
exit code: 1
@@ 97,10 +93,10 @@ but not
We can also first ``cd`` to the directory containing the module
``sudoku.py`` and doctest that module as follows::
 [mvngu@sage sage4.1.1]$ cd devel/sagemain/sage/games/
+ [mvngu@sage sage4.8]$ cd devel/sagemain/sage/games/
[mvngu@sage games]$ ls
 all.py __init__.py sudoku_backtrack.pyx
 hexad.py sudoku_backtrack.c sudoku.py
+ __init__.py hexad.py sudoku.py sudoku_backtrack.pyx
+ all.py quantumino.py sudoku_backtrack.c
[mvngu@sage games]$ ../../../../sage t sudoku.py
sage t "devel/sagemain/sage/games/sudoku.py"
[5.1 s]
@@ 128,14 +124,14 @@ our system has multiple Sage installatio
syntax is acceptable because we explicitly specify the Sage
installation in the current ``SAGE_ROOT``::
 [mvngu@sage sage4.1.1]$ ./sage t devel/sagemain/sage/games/sudoku.py
+ [mvngu@sage sage4.8]$ ./sage t devel/sagemain/sage/games/sudoku.py
sage t "devel/sagemain/sage/games/sudoku.py"
[5.1 s]

All tests passed!
Total time for all tests: 5.1 seconds
 [mvngu@sage sage4.1.1]$ ./sage t "devel/sagemain/sage/games/sudoku.py"
+ [mvngu@sage sage4.8]$ ./sage t "devel/sagemain/sage/games/sudoku.py"
sage t "devel/sagemain/sage/games/sudoku.py"
[5.0 s]
@@ 143,17 +139,17 @@ installation in the current ``SAGE_ROOT`
All tests passed!
Total time for all tests: 5.0 seconds
With a regular user account, the following syntax is not recommended
as we are using a systemwide Sage installation (if it exists)::
+The following syntax is not recommended as we are using a systemwide
+Sage installation (if it exists)::
 [mvngu@sage sage4.1.1]$ sage t devel/sagemain/sage/games/sudoku.py
+ [mvngu@sage sage4.8]$ sage t devel/sagemain/sage/games/sudoku.py
Traceback (most recent call last):
File "/usr/local/sage/local/bin/sagetest", line 49, in
os.makedirs(TMP)
File "/usr/local/sage/local/lib/python/os.py", line 157, in makedirs
mkdir(name, mode)
OSError: [Errno 13] Permission denied: '/usr/local/sage/tmp/tmp'
 [mvngu@sage sage4.1.1]$ sage t "devel/sagemain/sage/games/sudoku.py"
+ [mvngu@sage sage4.8]$ sage t "devel/sagemain/sage/games/sudoku.py"
Traceback (most recent call last):
File "/usr/local/sage/local/bin/sagetest", line 49, in
os.makedirs(TMP)
@@ 171,7 +167,7 @@ regular user, we cannot write to directo
write permission. The following syntax is also discouraged when we
login as a regular user::
 [mvngu@sage sage4.1.1]$ cd
+ [mvngu@sage sage4.8]$ cd
[mvngu@sage ~]$ sage t devel/sagemain/sage/games/sudoku.py
Traceback (most recent call last):
File "/usr/local/sage/local/bin/sagetest", line 49, in
@@ 195,9 +191,9 @@ there. As a regular user, we do not usua
the directory ``/root`` nor do we have privileges to write to the root
directory::
 [mvngu@sage sage4.1.1]$ ls /root/
+ [mvngu@sage sage4.8]$ ls /root/
ls: cannot open directory /root/: Permission denied
 [mvngu@sage sage4.1.1]$ cd /
+ [mvngu@sage sage4.8]$ cd /
[mvngu@sage /]$ touch demo.txt
touch: cannot touch `demo.txt': Permission denied
@@ 219,7 +215,7 @@ and then using two threads. For this exa
all the modules under ``sage/crypto/``. We can use a syntax similar to
that shown above to achieve this::
 [mvngu@sage sage4.1.1]$ ./sage t devel/sagemain/sage/crypto/
+ [mvngu@sage sage4.8]$ ./sage t devel/sagemain/sage/crypto/
sage t "devel/sagemain/sage/crypto/lfsr.py"
[2.5 s]
sage t "devel/sagemain/sage/crypto/cryptosystem.py"
@@ 260,42 +256,42 @@ that shown above to achieve this::
Total time for all tests: 35.7 seconds
Now we do the same thing, but this time we also use the optional
argument ``long``::
+argument ``long``::
 [mvngu@sage sage4.1.1]$ ./sage t long devel/sagemain/sage/crypto/
 sage t long "devel/sagemain/sage/crypto/lfsr.py"
+ [mvngu@sage sage4.8]$ ./sage t long devel/sagemain/sage/crypto/
+ sage t long "devel/sagemain/sage/crypto/lfsr.py"
[1.9 s]
 sage t long "devel/sagemain/sage/crypto/cryptosystem.py"
+ sage t long "devel/sagemain/sage/crypto/cryptosystem.py"
[2.0 s]
 sage t long "devel/sagemain/sage/crypto/block_cipher/miniaes.py"
+ sage t long "devel/sagemain/sage/crypto/block_cipher/miniaes.py"
[2.6 s]
 sage t long "devel/sagemain/sage/crypto/block_cipher/all.py"
+ sage t long "devel/sagemain/sage/crypto/block_cipher/all.py"
[0.1 s]
 sage t long "devel/sagemain/sage/crypto/block_cipher/__init__.py"
+ sage t long "devel/sagemain/sage/crypto/block_cipher/__init__.py"
[0.1 s]
 sage t long "devel/sagemain/sage/crypto/classical.py"
+ sage t long "devel/sagemain/sage/crypto/classical.py"
[2.7 s]
 sage t long "devel/sagemain/sage/crypto/mq/mpolynomialsystem.py"
+ sage t long "devel/sagemain/sage/crypto/mq/mpolynomialsystem.py"
[8.7 s]
 sage t long "devel/sagemain/sage/crypto/mq/mpolynomialsystemgenerator.py"
+ sage t long "devel/sagemain/sage/crypto/mq/mpolynomialsystemgenerator.py"
[2.2 s]
 sage t long "devel/sagemain/sage/crypto/mq/__init__.py"
+ sage t long "devel/sagemain/sage/crypto/mq/__init__.py"
[0.1 s]
 sage t long "devel/sagemain/sage/crypto/mq/sbox.py"
+ sage t long "devel/sagemain/sage/crypto/mq/sbox.py"
[2.9 s]
 sage t long "devel/sagemain/sage/crypto/mq/sr.py"
+ sage t long "devel/sagemain/sage/crypto/mq/sr.py"
[56.6 s]
 sage t long "devel/sagemain/sage/crypto/stream_cipher.py"
+ sage t long "devel/sagemain/sage/crypto/stream_cipher.py"
[2.5 s]
 sage t long "devel/sagemain/sage/crypto/all.py"
+ sage t long "devel/sagemain/sage/crypto/all.py"
[0.1 s]
 sage t long "devel/sagemain/sage/crypto/stream.py"
+ sage t long "devel/sagemain/sage/crypto/stream.py"
[1.9 s]
 sage t long "devel/sagemain/sage/crypto/__init__.py"
+ sage t long "devel/sagemain/sage/crypto/__init__.py"
[0.1 s]
 sage t long "devel/sagemain/sage/crypto/classical_cipher.py"
+ sage t long "devel/sagemain/sage/crypto/classical_cipher.py"
[1.9 s]
 sage t long "devel/sagemain/sage/crypto/cipher.py"
+ sage t long "devel/sagemain/sage/crypto/cipher.py"
[1.9 s]

@@ 303,9 +299,9 @@ argument ``long``::
Total time for all tests: 88.0 seconds
Notice the time difference between the first set of tests and the
second set, which uses the optional argument ``long``. Many tests in the
+second set, which uses the optional argument ``long``. Many tests in the
Sage library are flagged with ``# long time`` because these are known to
take a long time to run through. Without using the optional ``long``
+take a long time to run through. Without using the optional ``long``
argument, the module ``sage/crypto/mq/sr.py`` took about five
seconds. With this optional argument, it required 57 seconds to run
through all tests in that module. Here is a snippet of a function in
@@ 315,9 +311,8 @@ as taking a long time::
def test_consistency(max_n=2, **kwargs):
r"""
Test all combinations of ``r``, ``c``, ``e`` and ``n`` in ``(1,
 2)`` for consistency of random encryptions and their polynomial
 systems. `\GF{2}` and `\GF{2^e}` systems are tested. This test
 takes
+ 2)`` for consistency of random encryptions and their polynomial
+ systems. `\GF{2}` and `\GF{2^e}` systems are tested. This test takes
a while.
INPUT:
@@ 328,20 +323,17 @@ as taking a long time::
TESTS::
sage: from sage.crypto.mq.sr import test_consistency
 sage: test_consistency(1) # long time  calling w/ max_n = 2 requires a LOT of RAM (>> 2GB, evidently). Calling w/ max_n = 1 is far more manageable.
+ sage: test_consistency(1) # long time (80s on sage.math, 2011)
True

 The above doctest used to fail on a machine with "only" 2GB RAM.
 Using ``max_n = 1`` appears to be a more reasonable memory usage.
"""
Now we doctest the same directory in parallel using two threads::
+Now we doctest the same directory in parallel using four threads::
 [mvngu@sage sage4.1.1]$ ./sage tp 2 devel/sagemain/sage/crypto/
+ [mvngu@sage sage4.8]$ ./sage tp 4 devel/sagemain/sage/crypto/
Global iterations: 1
File iterations: 1
Using cached timings to run longest doctests first.
 Doctesting 17 files doing 2 jobs in parallel
+ Doctesting 17 files doing 4 jobs in parallel
sage t devel/sagemain/sage/crypto/lfsr.py
[2.7 s]
sage t devel/sagemain/sage/crypto/cryptosystem.py
@@ 382,44 +374,44 @@ Now we doctest the same directory in par
Timings have been updated.
Total time for all tests: 19.3 seconds
 [mvngu@sage sage4.1.1]$ ./sage tp 2 long devel/sagemain/sage/crypto/
+ [mvngu@sage sage4.8]$ ./sage tp 4 long devel/sagemain/sage/crypto/
Global iterations: 1
File iterations: 1
No long cached timings exist; will create upon successful finish.
 Doctesting 17 files doing 2 jobs in parallel
 sage t long devel/sagemain/sage/crypto/cryptosystem.py
+ Doctesting 17 files doing 4 jobs in parallel
+ sage t long devel/sagemain/sage/crypto/cryptosystem.py
[2.7 s]
 sage t long devel/sagemain/sage/crypto/lfsr.py
+ sage t long devel/sagemain/sage/crypto/lfsr.py
[2.7 s]
 sage t long devel/sagemain/sage/crypto/stream_cipher.py
+ sage t long devel/sagemain/sage/crypto/stream_cipher.py
[2.2 s]
 sage t long devel/sagemain/sage/crypto/all.py
+ sage t long devel/sagemain/sage/crypto/all.py
[0.1 s]
 sage t long devel/sagemain/sage/crypto/classical.py
+ sage t long devel/sagemain/sage/crypto/classical.py
[3.0 s]
 sage t long devel/sagemain/sage/crypto/__init__.py
+ sage t long devel/sagemain/sage/crypto/__init__.py
[0.1 s]
 sage t long devel/sagemain/sage/crypto/stream.py
+ sage t long devel/sagemain/sage/crypto/stream.py
[2.1 s]
 sage t long devel/sagemain/sage/crypto/classical_cipher.py
+ sage t long devel/sagemain/sage/crypto/classical_cipher.py
[2.1 s]
 sage t long devel/sagemain/sage/crypto/cipher.py
+ sage t long devel/sagemain/sage/crypto/cipher.py
[2.1 s]
 sage t long devel/sagemain/sage/crypto/block_cipher/all.py
+ sage t long devel/sagemain/sage/crypto/block_cipher/all.py
[0.1 s]
 sage t long devel/sagemain/sage/crypto/block_cipher/__init__.py
+ sage t long devel/sagemain/sage/crypto/block_cipher/__init__.py
[0.1 s]
 sage t long devel/sagemain/sage/crypto/block_cipher/miniaes.py
+ sage t long devel/sagemain/sage/crypto/block_cipher/miniaes.py
[2.8 s]
 sage t long devel/sagemain/sage/crypto/mq/mpolynomialsystemgenerator.py
+ sage t long devel/sagemain/sage/crypto/mq/mpolynomialsystemgenerator.py
[2.0 s]
 sage t long devel/sagemain/sage/crypto/mq/__init__.py
+ sage t long devel/sagemain/sage/crypto/mq/__init__.py
[0.1 s]
 sage t long devel/sagemain/sage/crypto/mq/sbox.py
+ sage t long devel/sagemain/sage/crypto/mq/sbox.py
[3.1 s]
 sage t long devel/sagemain/sage/crypto/mq/mpolynomialsystem.py
+ sage t long devel/sagemain/sage/crypto/mq/mpolynomialsystem.py
[9.1 s]
 sage t long devel/sagemain/sage/crypto/mq/sr.py
+ sage t long devel/sagemain/sage/crypto/mq/sr.py
[56.0 s]

@@ 443,22 +435,26 @@ Parallel testing the whole Sage library
The main Sage library resides in the directory
``SAGE_ROOT/devel/sagemain/``. We can use the syntax described above
to doctest the main library using multiple threads. When doing release
management or patching the main Sage library, a release manager would
parallel test the library using ten or more threads::
+management or patching the main Sage library, a release manager might
+parallel test the library using ten threads with the following
+command::
 [mvngu@sage sage4.1.1]$ ./sage tp 10 long devel/sagemain/
+ [mvngu@sage sage4.8]$ ./sage tp 10 long devel/sagemain/
Another way is to edit the file ``Makefile`` in the top level Sage
directory so that the variable ``NUM_THREADS`` is set to ``10``::
+Another way is to run ``make ptestlong``, which builds Sage (if
+necessary), builds the Sage documentation (if necessary), and then
+runs parallel doctests. By default, this determines the number of
+threads by reading the environment variable :envvar:`MAKE`: if it is
+set to ``make j12``, then use 12 threads. If :envvar:`MAKE` is not
+set, then it uses ``min(8, cpu_count())``, where ``cpu_count()`` is
+the number of CPUs in the machine, as determined by the Python
+function ``multiprocessing.cpu_count()``. The number of threads can be
+overridden by setting the environment variable
+:envvar:`SAGE_NUM_THREADS`.
 # How many threads should be used when doing parallel testing (and
 # sometime in the future, parallel building)?
 NUM_THREADS=10
+In any case, this will test the Sage library with multiple threads::
After saving all changes to ``Makefile``, we can parallel test with the
``long`` option using ten threads::

 [mvngu@sage sage4.1.1]$ make ptestlong
+ [mvngu@sage sage4.8]$ make ptestlong
Any of the following commands would also doctest the Sage library or
one of its clones::
@@ 497,8 +493,7 @@ by the symbolic link ``devel/sage``.
* ``make ptest``  Similar to the commands ``make test`` and ``make
check``. However, doctesting is run with the number of threads as
 specified by the variable ``NUM_THREADS``. See the file
 ``SAGE_ROOT/Makefile`` for further details.
+ described above for ``make ptestlong``.
* ``make ptestlong``  Similar to the command ``make ptest``, but
using the optional argument ``long`` for doctesting.
@@ 507,108 +502,30 @@ by the symbolic link ``devel/sage``.
Beyond the Sage library
=======================
The doctesting scripts of a Sage installation currently have limited
support for doctesting of modules outside of the Sage library for
that version of Sage. We cannot use the doctesting scripts of Sage
4.1.1 to doctest modules in, say, Sage 4.1. Doing so would result
in errors::

 [mvngu@sage sage4.1.1]$ ./sage t ../sage4.1/devel/sagemain/sage/games/sudoku.py
 sage t "../sage4.1/devel/sagemain/sage/games/sudoku.py"
 File "./sudoku.py", line 18
 from ../sage4.1/devel/sagemain/sage/games/sudoku import *
 ^
 SyntaxError: invalid syntax

 [0.2 s]
 exit code: 1024

 
 The following tests failed:


 sage t "../sage4.1/devel/sagemain/sage/games/sudoku.py"
 Total time for all tests: 0.2 seconds

However, suppose we have a Python script called ``my_python_script.py``
that uses the Sage library. Our Python script has the following
content::
+Doctesting also works fine for files not in the Sage library. For
+example, suppose we have a Python script called
+``my_python_script.py``::
[mvngu@sage build]$ cat my_python_script.py
from sage.all_cmdline import * # import sage library
def square(n):
"""
 Return the square of n.
+ Return the square of n.
 EXAMPLES::
+ EXAMPLES::
sage: square(2)
4
"""
return n**2
We can use any version of Sage to doctest our Python script, so long
as that version of Sage has features that are used in our script. For
example, we can use both Sage 4.1.1 and 4.1 to doctest the above
Python script::
+Then we can doctest it just as with Sage library files::
 [mvngu@sage build]$ sage4.1/sage t my_python_script.py
+ [mvngu@sage build]$ sage4.8/sage t my_python_script.py
sage t "my_python_script.py"
[1.3 s]

All tests passed!
Total time for all tests: 1.3 seconds
 [mvngu@sage build]$ sage4.1.1/sage t my_python_script.py
 sage t "my_python_script.py"
 [1.4 s]

 
 All tests passed!
 Total time for all tests: 1.4 seconds

Doctesting can also be performed on Sage scripts. Say we have a Sage
script called ``my_sage_script.sage`` with the following content::

 [mvngu@sage build]$ cat my_sage_script.sage
 def cube(n):
 r"""
 Return the cube of n.

 EXAMPLES::

 sage: cube(2)
 8
 """
 return n**3

This must be converted to an equivalent Python script prior to
doctesting. First, we use Sage to convert ``my_sage_script.sage`` to
an equivalent Python script called ``my_sage_script.py``::

 [mvngu@sage build]$ sage4.1.1/sage my_sage_script.sage
 [mvngu@sage build]$ cat my_sage_script.py
 # This file was *autogenerated* from the file my_sage_script.sage.
 from sage.all_cmdline import * # import sage library
 _sage_const_3 = Integer(3)
 def cube(n):
 r"""
 Return the cube of n.

 EXAMPLES::

 sage: cube(2)
 8
 """
 return n**_sage_const_3

Doctesting is then performed on that equivalent Python script::

 [mvngu@sage build]$ sage4.1.1/sage t my_sage_script.py
 sage t "my_sage_script.py"
 [1.5 s]

 
 All tests passed!
 Total time for all tests: 1.5 seconds
diff git a/doc/en/installation/source.rst b/doc/en/installation/source.rst
 a/doc/en/installation/source.rst
+++ b/doc/en/installation/source.rst
@@ 588,6 +588,15 @@ process:
time. Alternatively, run "make buildserial" which sets this
environment variable for you.
+ :envvar:`SAGE_NUM_THREADS`  if this is set to a number, then when
+ building the documentation, parallel doctesting, or running ``sage
+ b``, use this many threads. If it is set to ``0``, then use as
+ many threads as seems sensible. If it is set to ``auto``, then
+ build the documentation serially, but parallel test or run ``sage
+ b`` using as many threads as seems sensible. If this is not set,
+ then determine the number of threads using the value of the
+ :envvar:`MAKE` variable, as above.
+
 :envvar:`SAGE_CHECK`  if this is set to "yes", then during the
build process, run the test suite for each package which has one.
diff git a/setup.py b/setup.py
 a/setup.py
+++ b/setup.py
@@ 292,34 +292,23 @@ def execute_list_of_commands(command_lis
OUTPUT:
For each entry in command_list, we attempt to run the command.
If it is a string, we call os.system. If it is a pair [f, v],
 we call f(v). On machines with more than 1 cpu the commands
 are run in parallel.
+ we call f(v). If the 'j' flag in 'MAKE' is set, run in parallel.
"""
t = time.time()
 cpu_count = number_of_threads() # try hard to determine the actual cpu count
 assert(cpu_count>=1)
 nthreads = 0 # number of threads to use; zero means don't know

 if os.environ.has_key('MAKE'): # usersupplied number of threads takes precedence
 MAKE = os.environ['MAKE']
 # from the manpage: If there is more than one j option, the last one is effective.
 pos = MAKE.rfind(' j')
 if pos>=0:
 try:
 if MAKE[pos+3] == '=': # make j=N is the same as make jN
 pos += 1
 nthreads = int(MAKE[pos+3:].split()[0])
 except IndexError, ValueError:
 # make j without number means unlimited threads
 nthreads = 2*cpu_count

 if nthreads==0:
 nthreads = cpu_count

 if nthreads > 2*cpu_count: # sanity check
 print "Warning: The number of threads ("+str(nthreads)+") seems impossibly large."
 nthreads = min(nthreads, cpu_count)
 print "I reduced it to "+str(nthreads)+"."
+ # Determine the number of threads from the environment variable
+ # SAGE_NUM_THREADS, which is set automatically by the script
+ # sageenv, using the setting of the variable MAKE.
+ NUM_THREADS = os.environ.get('SAGE_NUM_THREADS', 1)
+ try:
+ nthreads = int(NUM_THREADS)
+ except ValueError:
+ # NUM_THREADS might be 'auto', in which case use the number of
+ # cpus.
+ nthreads = 0
+ # If SAGE_NUM_THREADS is 0, use the number of cpus.
+ if nthreads == 0:
+ nthreads = number_of_threads()
+ assert(nthreads >= 1)
# normalize the command_list to handle strings correctly
command_list = [ [run_command, x] if isinstance(x, str) else x for x in command_list ]