toil 7.0.0__py3-none-any.whl → 8.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- toil/__init__.py +121 -83
- toil/batchSystems/__init__.py +1 -0
- toil/batchSystems/abstractBatchSystem.py +137 -77
- toil/batchSystems/abstractGridEngineBatchSystem.py +211 -101
- toil/batchSystems/awsBatch.py +237 -128
- toil/batchSystems/cleanup_support.py +22 -16
- toil/batchSystems/contained_executor.py +30 -26
- toil/batchSystems/gridengine.py +85 -49
- toil/batchSystems/htcondor.py +164 -87
- toil/batchSystems/kubernetes.py +622 -386
- toil/batchSystems/local_support.py +17 -12
- toil/batchSystems/lsf.py +132 -79
- toil/batchSystems/lsfHelper.py +13 -11
- toil/batchSystems/mesos/__init__.py +41 -29
- toil/batchSystems/mesos/batchSystem.py +288 -149
- toil/batchSystems/mesos/executor.py +77 -49
- toil/batchSystems/mesos/test/__init__.py +31 -23
- toil/batchSystems/options.py +38 -29
- toil/batchSystems/registry.py +53 -19
- toil/batchSystems/singleMachine.py +293 -123
- toil/batchSystems/slurm.py +489 -137
- toil/batchSystems/torque.py +46 -32
- toil/bus.py +141 -73
- toil/common.py +630 -359
- toil/cwl/__init__.py +1 -1
- toil/cwl/cwltoil.py +1114 -532
- toil/cwl/utils.py +17 -22
- toil/deferred.py +62 -41
- toil/exceptions.py +5 -3
- toil/fileStores/__init__.py +5 -5
- toil/fileStores/abstractFileStore.py +88 -57
- toil/fileStores/cachingFileStore.py +711 -247
- toil/fileStores/nonCachingFileStore.py +113 -75
- toil/job.py +988 -315
- toil/jobStores/abstractJobStore.py +387 -243
- toil/jobStores/aws/jobStore.py +727 -403
- toil/jobStores/aws/utils.py +161 -109
- toil/jobStores/conftest.py +1 -0
- toil/jobStores/fileJobStore.py +289 -151
- toil/jobStores/googleJobStore.py +137 -70
- toil/jobStores/utils.py +36 -15
- toil/leader.py +614 -269
- toil/lib/accelerators.py +115 -18
- toil/lib/aws/__init__.py +55 -28
- toil/lib/aws/ami.py +122 -87
- toil/lib/aws/iam.py +284 -108
- toil/lib/aws/s3.py +31 -0
- toil/lib/aws/session.py +193 -58
- toil/lib/aws/utils.py +238 -218
- toil/lib/bioio.py +13 -5
- toil/lib/compatibility.py +11 -6
- toil/lib/conversions.py +83 -49
- toil/lib/docker.py +131 -103
- toil/lib/ec2.py +322 -209
- toil/lib/ec2nodes.py +174 -106
- toil/lib/encryption/_dummy.py +5 -3
- toil/lib/encryption/_nacl.py +10 -6
- toil/lib/encryption/conftest.py +1 -0
- toil/lib/exceptions.py +26 -7
- toil/lib/expando.py +4 -2
- toil/lib/ftp_utils.py +217 -0
- toil/lib/generatedEC2Lists.py +127 -19
- toil/lib/humanize.py +6 -2
- toil/lib/integration.py +341 -0
- toil/lib/io.py +99 -11
- toil/lib/iterables.py +4 -2
- toil/lib/memoize.py +12 -8
- toil/lib/misc.py +65 -18
- toil/lib/objects.py +2 -2
- toil/lib/resources.py +19 -7
- toil/lib/retry.py +115 -77
- toil/lib/threading.py +282 -80
- toil/lib/throttle.py +15 -14
- toil/options/common.py +834 -401
- toil/options/cwl.py +175 -90
- toil/options/runner.py +50 -0
- toil/options/wdl.py +70 -19
- toil/provisioners/__init__.py +111 -46
- toil/provisioners/abstractProvisioner.py +322 -157
- toil/provisioners/aws/__init__.py +62 -30
- toil/provisioners/aws/awsProvisioner.py +980 -627
- toil/provisioners/clusterScaler.py +541 -279
- toil/provisioners/gceProvisioner.py +282 -179
- toil/provisioners/node.py +147 -79
- toil/realtimeLogger.py +34 -22
- toil/resource.py +137 -75
- toil/server/app.py +127 -61
- toil/server/celery_app.py +3 -1
- toil/server/cli/wes_cwl_runner.py +82 -53
- toil/server/utils.py +54 -28
- toil/server/wes/abstract_backend.py +64 -26
- toil/server/wes/amazon_wes_utils.py +21 -15
- toil/server/wes/tasks.py +121 -63
- toil/server/wes/toil_backend.py +142 -107
- toil/server/wsgi_app.py +4 -3
- toil/serviceManager.py +58 -22
- toil/statsAndLogging.py +148 -64
- toil/test/__init__.py +263 -179
- toil/test/batchSystems/batchSystemTest.py +438 -195
- toil/test/batchSystems/batch_system_plugin_test.py +18 -7
- toil/test/batchSystems/test_gridengine.py +173 -0
- toil/test/batchSystems/test_lsf_helper.py +67 -58
- toil/test/batchSystems/test_slurm.py +93 -47
- toil/test/cactus/test_cactus_integration.py +20 -22
- toil/test/cwl/cwlTest.py +271 -71
- toil/test/cwl/measure_default_memory.cwl +12 -0
- toil/test/cwl/not_run_required_input.cwl +29 -0
- toil/test/cwl/scatter_duplicate_outputs.cwl +40 -0
- toil/test/docs/scriptsTest.py +60 -34
- toil/test/jobStores/jobStoreTest.py +412 -235
- toil/test/lib/aws/test_iam.py +116 -48
- toil/test/lib/aws/test_s3.py +16 -9
- toil/test/lib/aws/test_utils.py +5 -6
- toil/test/lib/dockerTest.py +118 -141
- toil/test/lib/test_conversions.py +113 -115
- toil/test/lib/test_ec2.py +57 -49
- toil/test/lib/test_integration.py +104 -0
- toil/test/lib/test_misc.py +12 -5
- toil/test/mesos/MesosDataStructuresTest.py +23 -10
- toil/test/mesos/helloWorld.py +7 -6
- toil/test/mesos/stress.py +25 -20
- toil/test/options/options.py +7 -2
- toil/test/provisioners/aws/awsProvisionerTest.py +293 -140
- toil/test/provisioners/clusterScalerTest.py +440 -250
- toil/test/provisioners/clusterTest.py +81 -42
- toil/test/provisioners/gceProvisionerTest.py +174 -100
- toil/test/provisioners/provisionerTest.py +25 -13
- toil/test/provisioners/restartScript.py +5 -4
- toil/test/server/serverTest.py +188 -141
- toil/test/sort/restart_sort.py +137 -68
- toil/test/sort/sort.py +134 -66
- toil/test/sort/sortTest.py +91 -49
- toil/test/src/autoDeploymentTest.py +140 -100
- toil/test/src/busTest.py +20 -18
- toil/test/src/checkpointTest.py +8 -2
- toil/test/src/deferredFunctionTest.py +49 -35
- toil/test/src/dockerCheckTest.py +33 -26
- toil/test/src/environmentTest.py +20 -10
- toil/test/src/fileStoreTest.py +538 -271
- toil/test/src/helloWorldTest.py +7 -4
- toil/test/src/importExportFileTest.py +61 -31
- toil/test/src/jobDescriptionTest.py +32 -17
- toil/test/src/jobEncapsulationTest.py +2 -0
- toil/test/src/jobFileStoreTest.py +74 -50
- toil/test/src/jobServiceTest.py +187 -73
- toil/test/src/jobTest.py +120 -70
- toil/test/src/miscTests.py +19 -18
- toil/test/src/promisedRequirementTest.py +82 -36
- toil/test/src/promisesTest.py +7 -6
- toil/test/src/realtimeLoggerTest.py +6 -6
- toil/test/src/regularLogTest.py +71 -37
- toil/test/src/resourceTest.py +80 -49
- toil/test/src/restartDAGTest.py +36 -22
- toil/test/src/resumabilityTest.py +9 -2
- toil/test/src/retainTempDirTest.py +45 -14
- toil/test/src/systemTest.py +12 -8
- toil/test/src/threadingTest.py +44 -25
- toil/test/src/toilContextManagerTest.py +10 -7
- toil/test/src/userDefinedJobArgTypeTest.py +8 -5
- toil/test/src/workerTest.py +33 -16
- toil/test/utils/toilDebugTest.py +70 -58
- toil/test/utils/toilKillTest.py +4 -5
- toil/test/utils/utilsTest.py +239 -102
- toil/test/wdl/wdltoil_test.py +789 -148
- toil/test/wdl/wdltoil_test_kubernetes.py +37 -23
- toil/toilState.py +52 -26
- toil/utils/toilConfig.py +13 -4
- toil/utils/toilDebugFile.py +44 -27
- toil/utils/toilDebugJob.py +85 -25
- toil/utils/toilDestroyCluster.py +11 -6
- toil/utils/toilKill.py +8 -3
- toil/utils/toilLaunchCluster.py +251 -145
- toil/utils/toilMain.py +37 -16
- toil/utils/toilRsyncCluster.py +27 -14
- toil/utils/toilSshCluster.py +45 -22
- toil/utils/toilStats.py +75 -36
- toil/utils/toilStatus.py +226 -119
- toil/utils/toilUpdateEC2Instances.py +3 -1
- toil/version.py +11 -11
- toil/wdl/utils.py +5 -5
- toil/wdl/wdltoil.py +3513 -1052
- toil/worker.py +269 -128
- toil-8.0.0.dist-info/METADATA +173 -0
- toil-8.0.0.dist-info/RECORD +253 -0
- {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/WHEEL +1 -1
- toil-7.0.0.dist-info/METADATA +0 -158
- toil-7.0.0.dist-info/RECORD +0 -244
- {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/LICENSE +0 -0
- {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/entry_points.txt +0 -0
- {toil-7.0.0.dist-info → toil-8.0.0.dist-info}/top_level.txt +0 -0
|
@@ -24,36 +24,43 @@ from abc import ABCMeta, abstractmethod
|
|
|
24
24
|
from fractions import Fraction
|
|
25
25
|
from unittest import skipIf
|
|
26
26
|
|
|
27
|
-
from toil.batchSystems.abstractBatchSystem import (
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
from toil.batchSystems.abstractBatchSystem import (
|
|
28
|
+
AbstractBatchSystem,
|
|
29
|
+
BatchSystemSupport,
|
|
30
|
+
InsufficientSystemResources,
|
|
31
|
+
)
|
|
32
|
+
|
|
30
33
|
# Don't import any batch systems here that depend on extras
|
|
31
34
|
# in order to import properly. Import them later, in tests
|
|
32
35
|
# protected by annotations.
|
|
33
36
|
from toil.batchSystems.mesos.test import MesosTestSupport
|
|
34
|
-
from toil.batchSystems.registry import (
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
from toil.batchSystems.registry import (
|
|
38
|
+
add_batch_system_factory,
|
|
39
|
+
get_batch_system,
|
|
40
|
+
get_batch_systems,
|
|
41
|
+
restore_batch_system_plugin_state,
|
|
42
|
+
save_batch_system_plugin_state,
|
|
43
|
+
)
|
|
39
44
|
from toil.batchSystems.singleMachine import SingleMachineBatchSystem
|
|
40
45
|
from toil.common import Config, Toil
|
|
41
46
|
from toil.job import Job, JobDescription, Requirer
|
|
42
47
|
from toil.lib.retry import retry_flaky_test
|
|
43
48
|
from toil.lib.threading import cpu_count
|
|
44
|
-
from toil.test import (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
from toil.test import (
|
|
50
|
+
ToilTest,
|
|
51
|
+
needs_aws_batch,
|
|
52
|
+
needs_aws_s3,
|
|
53
|
+
needs_fetchable_appliance,
|
|
54
|
+
needs_gridengine,
|
|
55
|
+
needs_htcondor,
|
|
56
|
+
needs_kubernetes,
|
|
57
|
+
needs_kubernetes_installed,
|
|
58
|
+
needs_lsf,
|
|
59
|
+
needs_mesos,
|
|
60
|
+
needs_slurm,
|
|
61
|
+
needs_torque,
|
|
62
|
+
slow,
|
|
63
|
+
)
|
|
57
64
|
|
|
58
65
|
logger = logging.getLogger(__name__)
|
|
59
66
|
|
|
@@ -66,7 +73,10 @@ preemptible = False
|
|
|
66
73
|
|
|
67
74
|
# Since we aren't always attaching the config to the jobs for these tests, we
|
|
68
75
|
# need to use fully specified requirements.
|
|
69
|
-
defaultRequirements = dict(
|
|
76
|
+
defaultRequirements = dict(
|
|
77
|
+
memory=int(100e6), cores=1, disk=1000, preemptible=preemptible, accelerators=[]
|
|
78
|
+
)
|
|
79
|
+
|
|
70
80
|
|
|
71
81
|
class BatchSystemPluginTest(ToilTest):
|
|
72
82
|
"""
|
|
@@ -91,9 +101,10 @@ class BatchSystemPluginTest(ToilTest):
|
|
|
91
101
|
# add its arguments.
|
|
92
102
|
return SingleMachineBatchSystem
|
|
93
103
|
|
|
94
|
-
add_batch_system_factory(
|
|
95
|
-
assert
|
|
96
|
-
assert get_batch_system(
|
|
104
|
+
add_batch_system_factory("testBatchSystem", test_batch_system_factory)
|
|
105
|
+
assert "testBatchSystem" in get_batch_systems()
|
|
106
|
+
assert get_batch_system("testBatchSystem") == SingleMachineBatchSystem
|
|
107
|
+
|
|
97
108
|
|
|
98
109
|
class hidden:
|
|
99
110
|
"""
|
|
@@ -127,8 +138,9 @@ class hidden:
|
|
|
127
138
|
"""
|
|
128
139
|
config = Config()
|
|
129
140
|
from uuid import uuid4
|
|
141
|
+
|
|
130
142
|
config.workflowID = str(uuid4())
|
|
131
|
-
config.cleanWorkDir =
|
|
143
|
+
config.cleanWorkDir = "always"
|
|
132
144
|
return config
|
|
133
145
|
|
|
134
146
|
def _createConfig(self):
|
|
@@ -164,7 +176,7 @@ class hidden:
|
|
|
164
176
|
super().setUp()
|
|
165
177
|
self.config = self._createConfig()
|
|
166
178
|
self.batchSystem = self.createBatchSystem()
|
|
167
|
-
self.tempDir = self._createTempDir(
|
|
179
|
+
self.tempDir = self._createTempDir("testFiles")
|
|
168
180
|
|
|
169
181
|
def tearDown(self):
|
|
170
182
|
self.batchSystem.shutdown()
|
|
@@ -182,12 +194,20 @@ class hidden:
|
|
|
182
194
|
|
|
183
195
|
@retry_flaky_test(prepare=[tearDown, setUp])
|
|
184
196
|
def test_run_jobs(self):
|
|
185
|
-
jobDesc1 = self._mockJobDescription(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
197
|
+
jobDesc1 = self._mockJobDescription(
|
|
198
|
+
jobName="test1",
|
|
199
|
+
unitName=None,
|
|
200
|
+
jobStoreID="1",
|
|
201
|
+
requirements=defaultRequirements,
|
|
202
|
+
)
|
|
203
|
+
jobDesc2 = self._mockJobDescription(
|
|
204
|
+
jobName="test2",
|
|
205
|
+
unitName=None,
|
|
206
|
+
jobStoreID="2",
|
|
207
|
+
requirements=defaultRequirements,
|
|
208
|
+
)
|
|
209
|
+
job1 = self.batchSystem.issueBatchJob("sleep 1000", jobDesc1)
|
|
210
|
+
job2 = self.batchSystem.issueBatchJob("sleep 1000", jobDesc2)
|
|
191
211
|
|
|
192
212
|
issuedIDs = self._waitForJobsToIssue(2)
|
|
193
213
|
self.assertEqual(set(issuedIDs), {job1, job2})
|
|
@@ -202,7 +222,9 @@ class hidden:
|
|
|
202
222
|
# getUpdatedBatchJob, and the sleep time is longer than the time we
|
|
203
223
|
# should spend waiting for both to start, so if our cluster can
|
|
204
224
|
# only run one job at a time, we will fail the test.
|
|
205
|
-
runningJobIDs = self._waitForJobsToStart(
|
|
225
|
+
runningJobIDs = self._waitForJobsToStart(
|
|
226
|
+
2, tries=self.get_max_startup_seconds()
|
|
227
|
+
)
|
|
206
228
|
self.assertEqual(set(runningJobIDs), {job1, job2})
|
|
207
229
|
|
|
208
230
|
# Killing the jobs instead of allowing them to complete means this test can run very
|
|
@@ -216,13 +238,21 @@ class hidden:
|
|
|
216
238
|
# then check for it having happened, but we can't guarantee that
|
|
217
239
|
# the batch system will run against the same filesystem we are
|
|
218
240
|
# looking at.
|
|
219
|
-
jobDesc3 = self._mockJobDescription(
|
|
220
|
-
|
|
241
|
+
jobDesc3 = self._mockJobDescription(
|
|
242
|
+
jobName="test3",
|
|
243
|
+
unitName=None,
|
|
244
|
+
jobStoreID="3",
|
|
245
|
+
requirements=defaultRequirements,
|
|
246
|
+
)
|
|
221
247
|
job3 = self.batchSystem.issueBatchJob("mktemp -d", jobDesc3)
|
|
222
248
|
|
|
223
249
|
jobUpdateInfo = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
|
|
224
|
-
jobID, exitStatus, wallTime =
|
|
225
|
-
|
|
250
|
+
jobID, exitStatus, wallTime = (
|
|
251
|
+
jobUpdateInfo.jobID,
|
|
252
|
+
jobUpdateInfo.exitStatus,
|
|
253
|
+
jobUpdateInfo.wallTime,
|
|
254
|
+
)
|
|
255
|
+
logger.info(f"Third job completed: {jobID} {exitStatus} {wallTime}")
|
|
226
256
|
|
|
227
257
|
# Since the first two jobs were killed, the only job in the updated jobs queue should
|
|
228
258
|
# be job 3. If the first two jobs were (incorrectly) added to the queue, this will
|
|
@@ -242,46 +272,68 @@ class hidden:
|
|
|
242
272
|
|
|
243
273
|
def test_set_env(self):
|
|
244
274
|
# Start with a relatively safe script
|
|
245
|
-
script_shell =
|
|
275
|
+
script_shell = (
|
|
276
|
+
'if [ "x${FOO}" == "xbar" ] ; then exit 23 ; else exit 42 ; fi'
|
|
277
|
+
)
|
|
246
278
|
|
|
247
279
|
# Escape the semicolons
|
|
248
|
-
script_protected = script_shell.replace(
|
|
280
|
+
script_protected = script_shell.replace(";", r"\;")
|
|
249
281
|
|
|
250
282
|
# Turn into a string which convinces bash to take all args and paste them back together and run them
|
|
251
|
-
command =
|
|
252
|
-
jobDesc4 = self._mockJobDescription(
|
|
253
|
-
|
|
283
|
+
command = 'bash -c "\\${@}" bash eval ' + script_protected
|
|
284
|
+
jobDesc4 = self._mockJobDescription(
|
|
285
|
+
jobName="test4",
|
|
286
|
+
unitName=None,
|
|
287
|
+
jobStoreID="4",
|
|
288
|
+
requirements=defaultRequirements,
|
|
289
|
+
)
|
|
254
290
|
job4 = self.batchSystem.issueBatchJob(command, jobDesc4)
|
|
255
291
|
jobUpdateInfo = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
|
|
256
|
-
jobID, exitStatus, wallTime =
|
|
292
|
+
jobID, exitStatus, wallTime = (
|
|
293
|
+
jobUpdateInfo.jobID,
|
|
294
|
+
jobUpdateInfo.exitStatus,
|
|
295
|
+
jobUpdateInfo.wallTime,
|
|
296
|
+
)
|
|
257
297
|
self.assertEqual(exitStatus, 42)
|
|
258
298
|
self.assertEqual(jobID, job4)
|
|
259
299
|
# Now set the variable and ensure that it is present
|
|
260
|
-
self.batchSystem.setEnv(
|
|
261
|
-
jobDesc5 = self._mockJobDescription(
|
|
262
|
-
|
|
300
|
+
self.batchSystem.setEnv("FOO", "bar")
|
|
301
|
+
jobDesc5 = self._mockJobDescription(
|
|
302
|
+
jobName="test5",
|
|
303
|
+
unitName=None,
|
|
304
|
+
jobStoreID="5",
|
|
305
|
+
requirements=defaultRequirements,
|
|
306
|
+
)
|
|
263
307
|
job5 = self.batchSystem.issueBatchJob(command, jobDesc5)
|
|
264
308
|
jobUpdateInfo = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
|
|
265
309
|
self.assertEqual(jobUpdateInfo.exitStatus, 23)
|
|
266
310
|
self.assertEqual(jobUpdateInfo.jobID, job5)
|
|
267
311
|
|
|
268
312
|
def test_set_job_env(self):
|
|
269
|
-
"""
|
|
313
|
+
"""Test the mechanism for setting per-job environment variables to batch system jobs."""
|
|
270
314
|
script = 'if [ "x${FOO}" == "xbar" ] ; then exit 23 ; else exit 42 ; fi'
|
|
271
|
-
command =
|
|
315
|
+
command = 'bash -c "\\${@}" bash eval ' + script.replace(";", r"\;")
|
|
272
316
|
|
|
273
317
|
# Issue a job with a job environment variable
|
|
274
|
-
job_desc_6 = self._mockJobDescription(
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
318
|
+
job_desc_6 = self._mockJobDescription(
|
|
319
|
+
jobName="test6",
|
|
320
|
+
unitName=None,
|
|
321
|
+
jobStoreID="6",
|
|
322
|
+
requirements=defaultRequirements,
|
|
323
|
+
)
|
|
324
|
+
job6 = self.batchSystem.issueBatchJob(
|
|
325
|
+
command, job_desc_6, job_environment={"FOO": "bar"}
|
|
326
|
+
)
|
|
279
327
|
job_update_info = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
|
|
280
328
|
self.assertEqual(job_update_info.exitStatus, 23) # this should succeed
|
|
281
329
|
self.assertEqual(job_update_info.jobID, job6)
|
|
282
330
|
# Now check that the environment variable doesn't exist for other jobs
|
|
283
|
-
job_desc_7 = self._mockJobDescription(
|
|
284
|
-
|
|
331
|
+
job_desc_7 = self._mockJobDescription(
|
|
332
|
+
jobName="test7",
|
|
333
|
+
unitName=None,
|
|
334
|
+
jobStoreID="7",
|
|
335
|
+
requirements=defaultRequirements,
|
|
336
|
+
)
|
|
285
337
|
job7 = self.batchSystem.issueBatchJob(command, job_desc_7)
|
|
286
338
|
job_update_info = self.batchSystem.getUpdatedBatchJob(maxWait=1000)
|
|
287
339
|
self.assertEqual(job_update_info.exitStatus, 42)
|
|
@@ -291,34 +343,67 @@ class hidden:
|
|
|
291
343
|
if isinstance(self.batchSystem, BatchSystemSupport):
|
|
292
344
|
check_resource_request = self.batchSystem.check_resource_request
|
|
293
345
|
# Assuming we have <2000 cores, this should be too many cores
|
|
294
|
-
self.assertRaises(
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
346
|
+
self.assertRaises(
|
|
347
|
+
InsufficientSystemResources,
|
|
348
|
+
check_resource_request,
|
|
349
|
+
Requirer(dict(memory=1000, cores=2000, disk="1G", accelerators=[])),
|
|
350
|
+
)
|
|
351
|
+
self.assertRaises(
|
|
352
|
+
InsufficientSystemResources,
|
|
353
|
+
check_resource_request,
|
|
354
|
+
Requirer(dict(memory=5, cores=2000, disk="1G", accelerators=[])),
|
|
355
|
+
)
|
|
298
356
|
|
|
299
357
|
# This should be too much memory
|
|
300
|
-
self.assertRaises(
|
|
301
|
-
|
|
358
|
+
self.assertRaises(
|
|
359
|
+
InsufficientSystemResources,
|
|
360
|
+
check_resource_request,
|
|
361
|
+
Requirer(dict(memory="5000G", cores=1, disk="1G", accelerators=[])),
|
|
362
|
+
)
|
|
302
363
|
|
|
303
364
|
# This should be too much disk
|
|
304
|
-
self.assertRaises(
|
|
305
|
-
|
|
365
|
+
self.assertRaises(
|
|
366
|
+
InsufficientSystemResources,
|
|
367
|
+
check_resource_request,
|
|
368
|
+
Requirer(dict(memory=5, cores=1, disk="2G", accelerators=[])),
|
|
369
|
+
)
|
|
306
370
|
|
|
307
371
|
# This should be an accelerator we don't have.
|
|
308
372
|
# All the batch systems need code to know they don't have these accelerators.
|
|
309
|
-
self.assertRaises(
|
|
310
|
-
|
|
373
|
+
self.assertRaises(
|
|
374
|
+
InsufficientSystemResources,
|
|
375
|
+
check_resource_request,
|
|
376
|
+
Requirer(
|
|
377
|
+
dict(
|
|
378
|
+
memory=5,
|
|
379
|
+
cores=1,
|
|
380
|
+
disk=100,
|
|
381
|
+
accelerators=[{"kind": "turbo-encabulator", "count": 1}],
|
|
382
|
+
)
|
|
383
|
+
),
|
|
384
|
+
)
|
|
311
385
|
|
|
312
386
|
# These should be missing attributes
|
|
313
|
-
self.assertRaises(
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
387
|
+
self.assertRaises(
|
|
388
|
+
AttributeError,
|
|
389
|
+
check_resource_request,
|
|
390
|
+
Requirer(dict(memory=5, cores=1, disk=1000)),
|
|
391
|
+
)
|
|
392
|
+
self.assertRaises(
|
|
393
|
+
AttributeError,
|
|
394
|
+
check_resource_request,
|
|
395
|
+
Requirer(dict(cores=1, disk=1000, accelerators=[])),
|
|
396
|
+
)
|
|
397
|
+
self.assertRaises(
|
|
398
|
+
AttributeError,
|
|
399
|
+
check_resource_request,
|
|
400
|
+
Requirer(dict(memory=10, disk=1000, accelerators=[])),
|
|
401
|
+
)
|
|
319
402
|
|
|
320
403
|
# This should actually work
|
|
321
|
-
check_resource_request(
|
|
404
|
+
check_resource_request(
|
|
405
|
+
Requirer(dict(memory=10, cores=1, disk=100, accelerators=[]))
|
|
406
|
+
)
|
|
322
407
|
|
|
323
408
|
def testScalableBatchSystem(self):
|
|
324
409
|
# If instance of scalable batch system
|
|
@@ -345,7 +430,7 @@ class hidden:
|
|
|
345
430
|
# prevent an endless loop, give it a few tries
|
|
346
431
|
for it in range(tries):
|
|
347
432
|
running = self.batchSystem.getRunningBatchJobIDs()
|
|
348
|
-
logger.info(f
|
|
433
|
+
logger.info(f"Running jobs now: {running}")
|
|
349
434
|
runningIDs = list(running.keys())
|
|
350
435
|
if len(runningIDs) == numJobs:
|
|
351
436
|
break
|
|
@@ -360,7 +445,7 @@ class hidden:
|
|
|
360
445
|
|
|
361
446
|
cpuCount = cpu_count()
|
|
362
447
|
allocatedCores = sorted({1, 2, cpuCount})
|
|
363
|
-
sleepTime =
|
|
448
|
+
sleepTime = 30
|
|
364
449
|
|
|
365
450
|
@abstractmethod
|
|
366
451
|
def getBatchSystemName(self):
|
|
@@ -395,18 +480,26 @@ class hidden:
|
|
|
395
480
|
Tests that the batch system is allocating core resources properly for concurrent tasks.
|
|
396
481
|
"""
|
|
397
482
|
for coresPerJob in self.allocatedCores:
|
|
398
|
-
tempDir = self._createTempDir(
|
|
483
|
+
tempDir = self._createTempDir("testFiles")
|
|
399
484
|
options = self.getOptions(tempDir)
|
|
400
485
|
|
|
401
|
-
counterPath = os.path.join(tempDir,
|
|
486
|
+
counterPath = os.path.join(tempDir, "counter")
|
|
402
487
|
resetCounters(counterPath)
|
|
403
488
|
value, maxValue = getCounters(counterPath)
|
|
404
489
|
assert (value, maxValue) == (0, 0)
|
|
405
490
|
|
|
406
491
|
root = Job()
|
|
407
492
|
for _ in range(self.cpuCount):
|
|
408
|
-
root.addFollowOn(
|
|
409
|
-
|
|
493
|
+
root.addFollowOn(
|
|
494
|
+
Job.wrapFn(
|
|
495
|
+
measureConcurrency,
|
|
496
|
+
counterPath,
|
|
497
|
+
self.sleepTime,
|
|
498
|
+
cores=coresPerJob,
|
|
499
|
+
memory="1M",
|
|
500
|
+
disk="1Mi",
|
|
501
|
+
)
|
|
502
|
+
)
|
|
410
503
|
with Toil(options) as toil:
|
|
411
504
|
toil.start(root)
|
|
412
505
|
_, maxValue = getCounters(counterPath)
|
|
@@ -420,18 +513,24 @@ class hidden:
|
|
|
420
513
|
# mapping of the number of cores to the OMP_NUM_THREADS value
|
|
421
514
|
0.1: "1",
|
|
422
515
|
1: "1",
|
|
423
|
-
2: "2"
|
|
516
|
+
2: "2",
|
|
424
517
|
}
|
|
425
518
|
|
|
426
519
|
temp_dir = self._createTempDir()
|
|
427
520
|
options = self.getOptions(temp_dir)
|
|
428
521
|
|
|
429
522
|
for cores, expected_omp_threads in test_cases.items():
|
|
430
|
-
if os.environ.get(
|
|
431
|
-
expected_omp_threads = os.environ.get(
|
|
432
|
-
logger.info(
|
|
523
|
+
if os.environ.get("OMP_NUM_THREADS"):
|
|
524
|
+
expected_omp_threads = os.environ.get("OMP_NUM_THREADS")
|
|
525
|
+
logger.info(
|
|
526
|
+
f"OMP_NUM_THREADS is set. Using OMP_NUM_THREADS={expected_omp_threads} instead."
|
|
527
|
+
)
|
|
433
528
|
with Toil(options) as toil:
|
|
434
|
-
output = toil.start(
|
|
529
|
+
output = toil.start(
|
|
530
|
+
Job.wrapFn(
|
|
531
|
+
get_omp_threads, memory="1Mi", cores=cores, disk="1Mi"
|
|
532
|
+
)
|
|
533
|
+
)
|
|
435
534
|
self.assertEqual(output, expected_omp_threads)
|
|
436
535
|
|
|
437
536
|
class AbstractGridEngineBatchSystemTest(AbstractBatchSystemTest):
|
|
@@ -444,9 +543,10 @@ class hidden:
|
|
|
444
543
|
config = super()._createConfig()
|
|
445
544
|
config.statePollingWait = 0.5 # Reduce polling wait so tests run faster
|
|
446
545
|
# can't use _getTestJobStorePath since that method removes the directory
|
|
447
|
-
config.jobStore =
|
|
546
|
+
config.jobStore = "file:" + self._createTempDir("jobStore")
|
|
448
547
|
return config
|
|
449
548
|
|
|
549
|
+
|
|
450
550
|
@needs_kubernetes
|
|
451
551
|
@needs_aws_s3
|
|
452
552
|
@needs_fetchable_appliance
|
|
@@ -461,8 +561,11 @@ class KubernetesBatchSystemTest(hidden.AbstractBatchSystemTest):
|
|
|
461
561
|
def createBatchSystem(self):
|
|
462
562
|
# We know we have Kubernetes so we can import the batch system
|
|
463
563
|
from toil.batchSystems.kubernetes import KubernetesBatchSystem
|
|
464
|
-
|
|
465
|
-
|
|
564
|
+
|
|
565
|
+
return KubernetesBatchSystem(
|
|
566
|
+
config=self.config, maxCores=numCores, maxMemory=1e9, maxDisk=2001
|
|
567
|
+
)
|
|
568
|
+
|
|
466
569
|
|
|
467
570
|
@needs_kubernetes_installed
|
|
468
571
|
class KubernetesBatchSystemBenchTest(ToilTest):
|
|
@@ -486,7 +589,9 @@ class KubernetesBatchSystemBenchTest(ToilTest):
|
|
|
486
589
|
constraints = KubernetesBatchSystem.Placement()
|
|
487
590
|
constraints.set_preemptible(False)
|
|
488
591
|
constraints.apply(normal_spec)
|
|
489
|
-
self.assertEqual(
|
|
592
|
+
self.assertEqual(
|
|
593
|
+
textwrap.dedent(
|
|
594
|
+
"""
|
|
490
595
|
{'node_affinity': {'preferred_during_scheduling_ignored_during_execution': None,
|
|
491
596
|
'required_during_scheduling_ignored_during_execution': {'node_selector_terms': [{'match_expressions': [{'key': 'eks.amazonaws.com/capacityType',
|
|
492
597
|
'operator': 'NotIn',
|
|
@@ -497,14 +602,19 @@ class KubernetesBatchSystemBenchTest(ToilTest):
|
|
|
497
602
|
'match_fields': None}]}},
|
|
498
603
|
'pod_affinity': None,
|
|
499
604
|
'pod_anti_affinity': None}
|
|
500
|
-
"""
|
|
605
|
+
"""
|
|
606
|
+
).strip(),
|
|
607
|
+
str(normal_spec.affinity),
|
|
608
|
+
)
|
|
501
609
|
self.assertEqual(str(normal_spec.tolerations), "None")
|
|
502
610
|
|
|
503
611
|
spot_spec = V1PodSpec(containers=[])
|
|
504
612
|
constraints = KubernetesBatchSystem.Placement()
|
|
505
613
|
constraints.set_preemptible(True)
|
|
506
614
|
constraints.apply(spot_spec)
|
|
507
|
-
self.assertEqual(
|
|
615
|
+
self.assertEqual(
|
|
616
|
+
textwrap.dedent(
|
|
617
|
+
"""
|
|
508
618
|
{'node_affinity': {'preferred_during_scheduling_ignored_during_execution': [{'preference': {'match_expressions': [{'key': 'eks.amazonaws.com/capacityType',
|
|
509
619
|
'operator': 'In',
|
|
510
620
|
'values': ['SPOT']}],
|
|
@@ -518,14 +628,22 @@ class KubernetesBatchSystemBenchTest(ToilTest):
|
|
|
518
628
|
'required_during_scheduling_ignored_during_execution': None},
|
|
519
629
|
'pod_affinity': None,
|
|
520
630
|
'pod_anti_affinity': None}
|
|
521
|
-
"""
|
|
522
|
-
|
|
631
|
+
"""
|
|
632
|
+
).strip(),
|
|
633
|
+
str(spot_spec.affinity),
|
|
634
|
+
)
|
|
635
|
+
self.assertEqual(
|
|
636
|
+
textwrap.dedent(
|
|
637
|
+
"""
|
|
523
638
|
[{'effect': None,
|
|
524
639
|
'key': 'cloud.google.com/gke-preemptible',
|
|
525
640
|
'operator': None,
|
|
526
641
|
'toleration_seconds': None,
|
|
527
642
|
'value': 'true'}]
|
|
528
|
-
"""
|
|
643
|
+
"""
|
|
644
|
+
).strip(),
|
|
645
|
+
str(spot_spec.tolerations),
|
|
646
|
+
)
|
|
529
647
|
|
|
530
648
|
def test_label_constraints(self):
|
|
531
649
|
"""
|
|
@@ -541,11 +659,13 @@ class KubernetesBatchSystemBenchTest(ToilTest):
|
|
|
541
659
|
|
|
542
660
|
spec = V1PodSpec(containers=[])
|
|
543
661
|
constraints = KubernetesBatchSystem.Placement()
|
|
544
|
-
constraints.required_labels = [(
|
|
545
|
-
constraints.desired_labels = [(
|
|
546
|
-
constraints.prohibited_labels = [(
|
|
662
|
+
constraints.required_labels = [("GottaBeSetTo", ["This"])]
|
|
663
|
+
constraints.desired_labels = [("OutghtToBeSetTo", ["That"])]
|
|
664
|
+
constraints.prohibited_labels = [("CannotBe", ["ABadThing"])]
|
|
547
665
|
constraints.apply(spec)
|
|
548
|
-
self.assertEqual(
|
|
666
|
+
self.assertEqual(
|
|
667
|
+
textwrap.dedent(
|
|
668
|
+
"""
|
|
549
669
|
{'node_affinity': {'preferred_during_scheduling_ignored_during_execution': [{'preference': {'match_expressions': [{'key': 'OutghtToBeSetTo',
|
|
550
670
|
'operator': 'In',
|
|
551
671
|
'values': ['That']}],
|
|
@@ -560,7 +680,10 @@ class KubernetesBatchSystemBenchTest(ToilTest):
|
|
|
560
680
|
'match_fields': None}]}},
|
|
561
681
|
'pod_affinity': None,
|
|
562
682
|
'pod_anti_affinity': None}
|
|
563
|
-
"""
|
|
683
|
+
"""
|
|
684
|
+
).strip(),
|
|
685
|
+
str(spec.affinity),
|
|
686
|
+
)
|
|
564
687
|
self.assertEqual(str(spec.tolerations), "None")
|
|
565
688
|
|
|
566
689
|
|
|
@@ -576,13 +699,16 @@ class AWSBatchBatchSystemTest(hidden.AbstractBatchSystemTest):
|
|
|
576
699
|
|
|
577
700
|
def createBatchSystem(self):
|
|
578
701
|
from toil.batchSystems.awsBatch import AWSBatchBatchSystem
|
|
579
|
-
|
|
580
|
-
|
|
702
|
+
|
|
703
|
+
return AWSBatchBatchSystem(
|
|
704
|
+
config=self.config, maxCores=numCores, maxMemory=1e9, maxDisk=2001
|
|
705
|
+
)
|
|
581
706
|
|
|
582
707
|
def get_max_startup_seconds(self) -> int:
|
|
583
708
|
# AWS Batch may need to scale out the compute environment.
|
|
584
709
|
return 300
|
|
585
710
|
|
|
711
|
+
|
|
586
712
|
@slow
|
|
587
713
|
@needs_mesos
|
|
588
714
|
class MesosBatchSystemTest(hidden.AbstractBatchSystemTest, MesosTestSupport):
|
|
@@ -597,7 +723,7 @@ class MesosBatchSystemTest(hidden.AbstractBatchSystemTest, MesosTestSupport):
|
|
|
597
723
|
private IP address
|
|
598
724
|
"""
|
|
599
725
|
config = super().createConfig()
|
|
600
|
-
config.mesos_endpoint =
|
|
726
|
+
config.mesos_endpoint = "localhost:5050"
|
|
601
727
|
return config
|
|
602
728
|
|
|
603
729
|
def supportsWallTime(self):
|
|
@@ -606,19 +732,25 @@ class MesosBatchSystemTest(hidden.AbstractBatchSystemTest, MesosTestSupport):
|
|
|
606
732
|
def createBatchSystem(self):
|
|
607
733
|
# We know we have Mesos so we can import the batch system
|
|
608
734
|
from toil.batchSystems.mesos.batchSystem import MesosBatchSystem
|
|
735
|
+
|
|
609
736
|
self._startMesos(numCores)
|
|
610
|
-
return MesosBatchSystem(
|
|
611
|
-
|
|
737
|
+
return MesosBatchSystem(
|
|
738
|
+
config=self.config, maxCores=numCores, maxMemory=1e9, maxDisk=1001
|
|
739
|
+
)
|
|
612
740
|
|
|
613
741
|
def tearDown(self):
|
|
614
742
|
self._stopMesos()
|
|
615
743
|
super().tearDown()
|
|
616
744
|
|
|
617
745
|
def testIgnoreNode(self):
|
|
618
|
-
self.batchSystem.ignoreNode(
|
|
619
|
-
jobDesc = self._mockJobDescription(
|
|
620
|
-
|
|
621
|
-
|
|
746
|
+
self.batchSystem.ignoreNode("localhost")
|
|
747
|
+
jobDesc = self._mockJobDescription(
|
|
748
|
+
jobName="test2",
|
|
749
|
+
unitName=None,
|
|
750
|
+
jobStoreID="1",
|
|
751
|
+
requirements=defaultRequirements,
|
|
752
|
+
)
|
|
753
|
+
job = self.batchSystem.issueBatchJob("sleep 1000", jobDesc)
|
|
622
754
|
|
|
623
755
|
issuedID = self._waitForJobsToIssue(1)
|
|
624
756
|
self.assertEqual(set(issuedID), {job})
|
|
@@ -635,7 +767,7 @@ def write_temp_file(s: str, temp_dir: str) -> str:
|
|
|
635
767
|
"""
|
|
636
768
|
fd, path = tempfile.mkstemp(dir=temp_dir)
|
|
637
769
|
try:
|
|
638
|
-
encoded = s.encode(
|
|
770
|
+
encoded = s.encode("utf-8")
|
|
639
771
|
assert os.write(fd, encoded) == len(encoded)
|
|
640
772
|
except:
|
|
641
773
|
os.unlink(path)
|
|
@@ -655,8 +787,9 @@ class SingleMachineBatchSystemTest(hidden.AbstractBatchSystemTest):
|
|
|
655
787
|
return True
|
|
656
788
|
|
|
657
789
|
def createBatchSystem(self) -> AbstractBatchSystem:
|
|
658
|
-
return SingleMachineBatchSystem(
|
|
659
|
-
|
|
790
|
+
return SingleMachineBatchSystem(
|
|
791
|
+
config=self.config, maxCores=numCores, maxMemory=1e9, maxDisk=2001
|
|
792
|
+
)
|
|
660
793
|
|
|
661
794
|
def testProcessEscape(self, hide: bool = False) -> None:
|
|
662
795
|
"""
|
|
@@ -677,14 +810,18 @@ class SingleMachineBatchSystemTest(hidden.AbstractBatchSystemTest):
|
|
|
677
810
|
from typing import Any
|
|
678
811
|
|
|
679
812
|
def handle_signal(sig: Any, frame: Any) -> None:
|
|
680
|
-
sys.stderr.write(f
|
|
813
|
+
sys.stderr.write(f"{os.getpid()} ignoring signal {sig}\n")
|
|
681
814
|
|
|
682
|
-
if hasattr(signal,
|
|
815
|
+
if hasattr(signal, "valid_signals"):
|
|
683
816
|
# We can just ask about the signals
|
|
684
817
|
all_signals = signal.valid_signals()
|
|
685
818
|
else:
|
|
686
819
|
# Fish them out by name
|
|
687
|
-
all_signals = [
|
|
820
|
+
all_signals = [
|
|
821
|
+
getattr(signal, n)
|
|
822
|
+
for n in dir(signal)
|
|
823
|
+
if n.startswith("SIG") and not n.startswith("SIG_")
|
|
824
|
+
]
|
|
688
825
|
|
|
689
826
|
for sig in all_signals:
|
|
690
827
|
# Set up to ignore all signals we can and generally be obstinate
|
|
@@ -706,7 +843,7 @@ class SingleMachineBatchSystemTest(hidden.AbstractBatchSystemTest):
|
|
|
706
843
|
fd = os.open(sys.argv[1], os.O_RDONLY)
|
|
707
844
|
fcntl.lockf(fd, fcntl.LOCK_SH)
|
|
708
845
|
|
|
709
|
-
sys.stderr.write(f
|
|
846
|
+
sys.stderr.write(f"{os.getpid()} waiting...\n")
|
|
710
847
|
|
|
711
848
|
while True:
|
|
712
849
|
# Wait around forever
|
|
@@ -718,27 +855,26 @@ class SingleMachineBatchSystemTest(hidden.AbstractBatchSystemTest):
|
|
|
718
855
|
script_path = write_temp_file(self._getScriptSource(script), temp_dir)
|
|
719
856
|
|
|
720
857
|
# We will have all the job processes try and lock this file shared while they are alive.
|
|
721
|
-
lockable_path = write_temp_file(
|
|
858
|
+
lockable_path = write_temp_file("", temp_dir)
|
|
722
859
|
|
|
723
860
|
try:
|
|
724
|
-
command = f
|
|
861
|
+
command = f"{sys.executable} {script_path} {lockable_path}"
|
|
725
862
|
if hide:
|
|
726
863
|
# Tell the children to stop the first child and hide out in the
|
|
727
864
|
# process group it made.
|
|
728
|
-
command +=
|
|
865
|
+
command += " hide"
|
|
729
866
|
|
|
730
867
|
# Start the job
|
|
731
868
|
self.batchSystem.issueBatchJob(
|
|
732
|
-
command,
|
|
869
|
+
command,
|
|
733
870
|
self._mockJobDescription(
|
|
734
|
-
jobName=
|
|
735
|
-
|
|
736
|
-
requirements=defaultRequirements)
|
|
871
|
+
jobName="fork", jobStoreID="1", requirements=defaultRequirements
|
|
872
|
+
),
|
|
737
873
|
)
|
|
738
874
|
# Wait
|
|
739
875
|
time.sleep(10)
|
|
740
876
|
|
|
741
|
-
lockfile = open(lockable_path,
|
|
877
|
+
lockfile = open(lockable_path, "w")
|
|
742
878
|
|
|
743
879
|
if not hide:
|
|
744
880
|
# In hiding mode the job will finish, and the batch system will
|
|
@@ -793,13 +929,14 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
|
|
|
793
929
|
|
|
794
930
|
# Write initial value of counter file containing a tuple of two integers (i, n) where i
|
|
795
931
|
# is the number of currently executing tasks and n the maximum observed value of i
|
|
796
|
-
self.counterPath = write_temp_file(
|
|
932
|
+
self.counterPath = write_temp_file("0,0", temp_dir)
|
|
797
933
|
|
|
798
934
|
def script() -> None:
|
|
799
935
|
import fcntl
|
|
800
936
|
import os
|
|
801
937
|
import sys
|
|
802
938
|
import time
|
|
939
|
+
|
|
803
940
|
def count(delta: int) -> None:
|
|
804
941
|
"""
|
|
805
942
|
Adjust the first integer value in a file by the given amount. If the result
|
|
@@ -809,13 +946,14 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
|
|
|
809
946
|
try:
|
|
810
947
|
fcntl.flock(fd, fcntl.LOCK_EX)
|
|
811
948
|
try:
|
|
812
|
-
s = os.read(fd, 10).decode(
|
|
813
|
-
value, maxValue = list(map(int, s.split(
|
|
949
|
+
s = os.read(fd, 10).decode("utf-8")
|
|
950
|
+
value, maxValue = list(map(int, s.split(",")))
|
|
814
951
|
value += delta
|
|
815
|
-
if value > maxValue:
|
|
952
|
+
if value > maxValue:
|
|
953
|
+
maxValue = value
|
|
816
954
|
os.lseek(fd, 0, 0)
|
|
817
955
|
os.ftruncate(fd, 0)
|
|
818
|
-
os.write(fd, f
|
|
956
|
+
os.write(fd, f"{value},{maxValue}".encode())
|
|
819
957
|
finally:
|
|
820
958
|
fcntl.flock(fd, fcntl.LOCK_UN)
|
|
821
959
|
finally:
|
|
@@ -839,7 +977,7 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
|
|
|
839
977
|
os.unlink(self.counterPath)
|
|
840
978
|
|
|
841
979
|
def scriptCommand(self) -> str:
|
|
842
|
-
return
|
|
980
|
+
return " ".join([sys.executable, self.scriptPath, self.counterPath])
|
|
843
981
|
|
|
844
982
|
@retry_flaky_test(prepare=[tearDown, setUp])
|
|
845
983
|
def test(self):
|
|
@@ -851,7 +989,13 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
|
|
|
851
989
|
minCores = F(1, 10)
|
|
852
990
|
self.assertEqual(float(minCores), SingleMachineBatchSystem.minCores)
|
|
853
991
|
for maxCores in {F(minCores), minCores * 10, F(1), F(numCores, 2), F(numCores)}:
|
|
854
|
-
for coresPerJob in {
|
|
992
|
+
for coresPerJob in {
|
|
993
|
+
F(minCores),
|
|
994
|
+
F(minCores * 10),
|
|
995
|
+
F(1),
|
|
996
|
+
F(maxCores, 2),
|
|
997
|
+
F(maxCores),
|
|
998
|
+
}:
|
|
855
999
|
for load in (F(1, 10), F(1), F(10)):
|
|
856
1000
|
jobs = int(maxCores / coresPerJob * load)
|
|
857
1001
|
if jobs >= 1 and minCores <= coresPerJob < maxCores:
|
|
@@ -861,7 +1005,8 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
|
|
|
861
1005
|
maxCores=float(maxCores),
|
|
862
1006
|
# Ensure that memory or disk requirements don't get in the way.
|
|
863
1007
|
maxMemory=jobs * 10,
|
|
864
|
-
maxDisk=jobs * 10
|
|
1008
|
+
maxDisk=jobs * 10,
|
|
1009
|
+
)
|
|
865
1010
|
try:
|
|
866
1011
|
jobIds = set()
|
|
867
1012
|
for i in range(0, int(jobs)):
|
|
@@ -871,48 +1016,62 @@ class MaxCoresSingleMachineBatchSystemTest(ToilTest):
|
|
|
871
1016
|
memory=1,
|
|
872
1017
|
disk=1,
|
|
873
1018
|
accelerators=[],
|
|
874
|
-
preemptible=preemptible
|
|
1019
|
+
preemptible=preemptible,
|
|
875
1020
|
),
|
|
876
1021
|
jobName=str(i),
|
|
877
|
-
unitName=
|
|
1022
|
+
unitName="",
|
|
878
1023
|
)
|
|
879
1024
|
jobIds.add(bs.issueBatchJob(self.scriptCommand(), desc))
|
|
880
1025
|
self.assertEqual(len(jobIds), jobs)
|
|
881
1026
|
while jobIds:
|
|
882
1027
|
job = bs.getUpdatedBatchJob(maxWait=10)
|
|
883
1028
|
self.assertIsNotNone(job)
|
|
884
|
-
jobId, status, wallTime =
|
|
1029
|
+
jobId, status, wallTime = (
|
|
1030
|
+
job.jobID,
|
|
1031
|
+
job.exitStatus,
|
|
1032
|
+
job.wallTime,
|
|
1033
|
+
)
|
|
885
1034
|
self.assertEqual(status, 0)
|
|
886
1035
|
# would raise KeyError on absence
|
|
887
1036
|
jobIds.remove(jobId)
|
|
888
1037
|
finally:
|
|
889
1038
|
bs.shutdown()
|
|
890
|
-
concurrentTasks, maxConcurrentTasks = getCounters(
|
|
1039
|
+
concurrentTasks, maxConcurrentTasks = getCounters(
|
|
1040
|
+
self.counterPath
|
|
1041
|
+
)
|
|
891
1042
|
self.assertEqual(concurrentTasks, 0)
|
|
892
|
-
logger.info(
|
|
893
|
-
|
|
894
|
-
|
|
1043
|
+
logger.info(
|
|
1044
|
+
f"maxCores: {maxCores}, "
|
|
1045
|
+
f"coresPerJob: {coresPerJob}, "
|
|
1046
|
+
f"load: {load}"
|
|
1047
|
+
)
|
|
895
1048
|
# This is the key assertion: we shouldn't run too many jobs.
|
|
896
1049
|
# Because of nondeterminism we can't guarantee hitting the limit.
|
|
897
1050
|
expectedMaxConcurrentTasks = min(maxCores // coresPerJob, jobs)
|
|
898
|
-
self.assertLessEqual(
|
|
1051
|
+
self.assertLessEqual(
|
|
1052
|
+
maxConcurrentTasks, expectedMaxConcurrentTasks
|
|
1053
|
+
)
|
|
899
1054
|
resetCounters(self.counterPath)
|
|
900
1055
|
|
|
901
|
-
@skipIf(
|
|
1056
|
+
@skipIf(
|
|
1057
|
+
SingleMachineBatchSystem.numCores < 3,
|
|
1058
|
+
"Need at least three cores to run this test",
|
|
1059
|
+
)
|
|
902
1060
|
def testServices(self):
|
|
903
1061
|
options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
|
|
904
1062
|
options.logLevel = "DEBUG"
|
|
905
1063
|
options.maxCores = 3
|
|
906
1064
|
self.assertTrue(options.maxCores <= SingleMachineBatchSystem.numCores)
|
|
907
1065
|
Job.Runner.startToil(Job.wrapJobFn(parentJob, self.scriptCommand()), options)
|
|
908
|
-
with open(self.counterPath,
|
|
1066
|
+
with open(self.counterPath, "r+") as f:
|
|
909
1067
|
s = f.read()
|
|
910
|
-
logger.info(
|
|
1068
|
+
logger.info("Counter is %s", s)
|
|
911
1069
|
self.assertEqual(getCounters(self.counterPath), (0, 3))
|
|
912
1070
|
|
|
913
1071
|
|
|
914
1072
|
# Toil can use only top-level functions so we have to add them here:
|
|
915
1073
|
|
|
1074
|
+
|
|
916
1075
|
def parentJob(job, cmd):
|
|
917
1076
|
job.addChildJobFn(childJob, cmd)
|
|
918
1077
|
|
|
@@ -939,13 +1098,13 @@ class Service(Job.Service):
|
|
|
939
1098
|
self.cmd = cmd
|
|
940
1099
|
|
|
941
1100
|
def start(self, fileStore):
|
|
942
|
-
subprocess.check_call(self.cmd +
|
|
1101
|
+
subprocess.check_call(self.cmd + " 1", shell=True)
|
|
943
1102
|
|
|
944
1103
|
def check(self):
|
|
945
1104
|
return True
|
|
946
1105
|
|
|
947
1106
|
def stop(self, fileStore):
|
|
948
|
-
subprocess.check_call(self.cmd +
|
|
1107
|
+
subprocess.check_call(self.cmd + " -1", shell=True)
|
|
949
1108
|
|
|
950
1109
|
|
|
951
1110
|
@slow
|
|
@@ -957,14 +1116,17 @@ class GridEngineBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
|
|
|
957
1116
|
|
|
958
1117
|
def createBatchSystem(self) -> AbstractBatchSystem:
|
|
959
1118
|
from toil.batchSystems.gridengine import GridEngineBatchSystem
|
|
960
|
-
|
|
961
|
-
|
|
1119
|
+
|
|
1120
|
+
return GridEngineBatchSystem(
|
|
1121
|
+
config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
|
|
1122
|
+
)
|
|
962
1123
|
|
|
963
1124
|
def tearDown(self):
|
|
964
1125
|
super().tearDown()
|
|
965
1126
|
# Cleanup GridEngine output log file from qsub
|
|
966
1127
|
from glob import glob
|
|
967
|
-
|
|
1128
|
+
|
|
1129
|
+
for f in glob("toil_job*.o*"):
|
|
968
1130
|
os.unlink(f)
|
|
969
1131
|
|
|
970
1132
|
|
|
@@ -977,14 +1139,17 @@ class SlurmBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
|
|
|
977
1139
|
|
|
978
1140
|
def createBatchSystem(self) -> AbstractBatchSystem:
|
|
979
1141
|
from toil.batchSystems.slurm import SlurmBatchSystem
|
|
980
|
-
|
|
981
|
-
|
|
1142
|
+
|
|
1143
|
+
return SlurmBatchSystem(
|
|
1144
|
+
config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
|
|
1145
|
+
)
|
|
982
1146
|
|
|
983
1147
|
def tearDown(self):
|
|
984
1148
|
super().tearDown()
|
|
985
1149
|
# Cleanup 'slurm-%j.out' produced by sbatch
|
|
986
1150
|
from glob import glob
|
|
987
|
-
|
|
1151
|
+
|
|
1152
|
+
for f in glob("slurm-*.out"):
|
|
988
1153
|
os.unlink(f)
|
|
989
1154
|
|
|
990
1155
|
|
|
@@ -994,10 +1159,13 @@ class LSFBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
|
|
|
994
1159
|
"""
|
|
995
1160
|
Tests against the LSF batch system
|
|
996
1161
|
"""
|
|
1162
|
+
|
|
997
1163
|
def createBatchSystem(self) -> AbstractBatchSystem:
|
|
998
1164
|
from toil.batchSystems.lsf import LSFBatchSystem
|
|
999
|
-
|
|
1000
|
-
|
|
1165
|
+
|
|
1166
|
+
return LSFBatchSystem(
|
|
1167
|
+
config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
|
|
1168
|
+
)
|
|
1001
1169
|
|
|
1002
1170
|
|
|
1003
1171
|
@slow
|
|
@@ -1010,19 +1178,22 @@ class TorqueBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
|
|
|
1010
1178
|
def _createDummyConfig(self):
|
|
1011
1179
|
config = super()._createDummyConfig()
|
|
1012
1180
|
# can't use _getTestJobStorePath since that method removes the directory
|
|
1013
|
-
config.jobStore = self._createTempDir(
|
|
1181
|
+
config.jobStore = self._createTempDir("jobStore")
|
|
1014
1182
|
return config
|
|
1015
1183
|
|
|
1016
1184
|
def createBatchSystem(self) -> AbstractBatchSystem:
|
|
1017
1185
|
from toil.batchSystems.torque import TorqueBatchSystem
|
|
1018
|
-
|
|
1019
|
-
|
|
1186
|
+
|
|
1187
|
+
return TorqueBatchSystem(
|
|
1188
|
+
config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
|
|
1189
|
+
)
|
|
1020
1190
|
|
|
1021
1191
|
def tearDown(self):
|
|
1022
1192
|
super().tearDown()
|
|
1023
1193
|
# Cleanup 'toil_job-%j.out' produced by sbatch
|
|
1024
1194
|
from glob import glob
|
|
1025
|
-
|
|
1195
|
+
|
|
1196
|
+
for f in glob("toil_job_*.[oe]*"):
|
|
1026
1197
|
os.unlink(f)
|
|
1027
1198
|
|
|
1028
1199
|
|
|
@@ -1035,8 +1206,10 @@ class HTCondorBatchSystemTest(hidden.AbstractGridEngineBatchSystemTest):
|
|
|
1035
1206
|
|
|
1036
1207
|
def createBatchSystem(self) -> AbstractBatchSystem:
|
|
1037
1208
|
from toil.batchSystems.htcondor import HTCondorBatchSystem
|
|
1038
|
-
|
|
1039
|
-
|
|
1209
|
+
|
|
1210
|
+
return HTCondorBatchSystem(
|
|
1211
|
+
config=self.config, maxCores=numCores, maxMemory=1000e9, maxDisk=1e9
|
|
1212
|
+
)
|
|
1040
1213
|
|
|
1041
1214
|
def tearDown(self):
|
|
1042
1215
|
super().tearDown()
|
|
@@ -1051,46 +1224,71 @@ class SingleMachineBatchSystemJobTest(hidden.AbstractBatchSystemJobTest):
|
|
|
1051
1224
|
return "single_machine"
|
|
1052
1225
|
|
|
1053
1226
|
@slow
|
|
1054
|
-
@retry_flaky_test(
|
|
1227
|
+
@retry_flaky_test(
|
|
1228
|
+
prepare=[
|
|
1229
|
+
hidden.AbstractBatchSystemJobTest.tearDown,
|
|
1230
|
+
hidden.AbstractBatchSystemJobTest.setUp,
|
|
1231
|
+
]
|
|
1232
|
+
)
|
|
1055
1233
|
def testConcurrencyWithDisk(self):
|
|
1056
1234
|
"""
|
|
1057
1235
|
Tests that the batch system is allocating disk resources properly
|
|
1058
1236
|
"""
|
|
1059
|
-
tempDir = self._createTempDir(
|
|
1237
|
+
tempDir = self._createTempDir("testFiles")
|
|
1060
1238
|
|
|
1061
1239
|
options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
|
|
1062
1240
|
options.workDir = tempDir
|
|
1063
1241
|
from toil import physicalDisk
|
|
1242
|
+
|
|
1064
1243
|
availableDisk = physicalDisk(options.workDir)
|
|
1065
|
-
logger.info(
|
|
1244
|
+
logger.info("Testing disk concurrency limits with %s disk space", availableDisk)
|
|
1066
1245
|
# More disk might become available by the time Toil starts, so we limit it here
|
|
1067
1246
|
options.maxDisk = availableDisk
|
|
1068
1247
|
options.batchSystem = self.batchSystemName
|
|
1069
1248
|
|
|
1070
|
-
counterPath = os.path.join(tempDir,
|
|
1249
|
+
counterPath = os.path.join(tempDir, "counter")
|
|
1071
1250
|
resetCounters(counterPath)
|
|
1072
1251
|
value, maxValue = getCounters(counterPath)
|
|
1073
1252
|
assert (value, maxValue) == (0, 0)
|
|
1074
1253
|
|
|
1075
1254
|
half_disk = availableDisk // 2
|
|
1076
1255
|
more_than_half_disk = half_disk + 500
|
|
1077
|
-
logger.info(
|
|
1256
|
+
logger.info("Dividing into parts of %s and %s", half_disk, more_than_half_disk)
|
|
1078
1257
|
|
|
1079
1258
|
root = Job()
|
|
1080
1259
|
# Physically, we're asking for 50% of disk and 50% of disk + 500bytes in the two jobs. The
|
|
1081
1260
|
# batchsystem should not allow the 2 child jobs to run concurrently.
|
|
1082
|
-
root.addChild(
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1261
|
+
root.addChild(
|
|
1262
|
+
Job.wrapFn(
|
|
1263
|
+
measureConcurrency,
|
|
1264
|
+
counterPath,
|
|
1265
|
+
self.sleepTime,
|
|
1266
|
+
cores=1,
|
|
1267
|
+
memory="1M",
|
|
1268
|
+
disk=half_disk,
|
|
1269
|
+
)
|
|
1270
|
+
)
|
|
1271
|
+
root.addChild(
|
|
1272
|
+
Job.wrapFn(
|
|
1273
|
+
measureConcurrency,
|
|
1274
|
+
counterPath,
|
|
1275
|
+
self.sleepTime,
|
|
1276
|
+
cores=1,
|
|
1277
|
+
memory="1M",
|
|
1278
|
+
disk=more_than_half_disk,
|
|
1279
|
+
)
|
|
1280
|
+
)
|
|
1086
1281
|
Job.Runner.startToil(root, options)
|
|
1087
1282
|
_, maxValue = getCounters(counterPath)
|
|
1088
1283
|
|
|
1089
|
-
logger.info(
|
|
1284
|
+
logger.info("After run: %s disk space", physicalDisk(options.workDir))
|
|
1090
1285
|
|
|
1091
1286
|
self.assertEqual(maxValue, 1)
|
|
1092
1287
|
|
|
1093
|
-
@skipIf(
|
|
1288
|
+
@skipIf(
|
|
1289
|
+
SingleMachineBatchSystem.numCores < 4,
|
|
1290
|
+
"Need at least four cores to run this test",
|
|
1291
|
+
)
|
|
1094
1292
|
@slow
|
|
1095
1293
|
def testNestedResourcesDoNotBlock(self):
|
|
1096
1294
|
"""
|
|
@@ -1098,39 +1296,80 @@ class SingleMachineBatchSystemJobTest(hidden.AbstractBatchSystemJobTest):
|
|
|
1098
1296
|
Test that unavailability of cpus for one job that is scheduled does not block another job
|
|
1099
1297
|
that can run.
|
|
1100
1298
|
"""
|
|
1101
|
-
tempDir = self._createTempDir(
|
|
1299
|
+
tempDir = self._createTempDir("testFiles")
|
|
1102
1300
|
|
|
1103
1301
|
options = Job.Runner.getDefaultOptions(self._getTestJobStorePath())
|
|
1104
1302
|
options.workDir = tempDir
|
|
1105
1303
|
options.maxCores = 4
|
|
1106
1304
|
from toil import physicalMemory
|
|
1305
|
+
|
|
1107
1306
|
availableMemory = physicalMemory()
|
|
1108
1307
|
options.batchSystem = self.batchSystemName
|
|
1109
1308
|
|
|
1110
|
-
outFile = os.path.join(tempDir,
|
|
1111
|
-
open(outFile,
|
|
1309
|
+
outFile = os.path.join(tempDir, "counter")
|
|
1310
|
+
open(outFile, "w").close()
|
|
1112
1311
|
|
|
1113
1312
|
root = Job()
|
|
1114
1313
|
|
|
1115
|
-
blocker = Job.wrapFn(
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1314
|
+
blocker = Job.wrapFn(
|
|
1315
|
+
_resourceBlockTestAuxFn,
|
|
1316
|
+
outFile=outFile,
|
|
1317
|
+
sleepTime=30,
|
|
1318
|
+
writeVal="b",
|
|
1319
|
+
cores=2,
|
|
1320
|
+
memory="1M",
|
|
1321
|
+
disk="1M",
|
|
1322
|
+
)
|
|
1323
|
+
firstJob = Job.wrapFn(
|
|
1324
|
+
_resourceBlockTestAuxFn,
|
|
1325
|
+
outFile=outFile,
|
|
1326
|
+
sleepTime=5,
|
|
1327
|
+
writeVal="fJ",
|
|
1328
|
+
cores=1,
|
|
1329
|
+
memory="1M",
|
|
1330
|
+
disk="1M",
|
|
1331
|
+
)
|
|
1332
|
+
secondJob = Job.wrapFn(
|
|
1333
|
+
_resourceBlockTestAuxFn,
|
|
1334
|
+
outFile=outFile,
|
|
1335
|
+
sleepTime=10,
|
|
1336
|
+
writeVal="sJ",
|
|
1337
|
+
cores=1,
|
|
1338
|
+
memory="1M",
|
|
1339
|
+
disk="1M",
|
|
1340
|
+
)
|
|
1121
1341
|
|
|
1122
1342
|
# Should block off 50% of memory while waiting for it's 3 cores
|
|
1123
|
-
firstJobChild = Job.wrapFn(
|
|
1124
|
-
|
|
1343
|
+
firstJobChild = Job.wrapFn(
|
|
1344
|
+
_resourceBlockTestAuxFn,
|
|
1345
|
+
outFile=outFile,
|
|
1346
|
+
sleepTime=0,
|
|
1347
|
+
writeVal="fJC",
|
|
1348
|
+
cores=3,
|
|
1349
|
+
memory=int(availableMemory // 2),
|
|
1350
|
+
disk="1M",
|
|
1351
|
+
)
|
|
1125
1352
|
|
|
1126
1353
|
# These two shouldn't be able to run before B because there should be only
|
|
1127
1354
|
# (50% of memory - 1M) available (firstJobChild should be blocking 50%)
|
|
1128
|
-
secondJobChild = Job.wrapFn(
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1355
|
+
secondJobChild = Job.wrapFn(
|
|
1356
|
+
_resourceBlockTestAuxFn,
|
|
1357
|
+
outFile=outFile,
|
|
1358
|
+
sleepTime=5,
|
|
1359
|
+
writeVal="sJC",
|
|
1360
|
+
cores=2,
|
|
1361
|
+
memory=int(availableMemory // 1.5),
|
|
1362
|
+
disk="1M",
|
|
1363
|
+
)
|
|
1364
|
+
secondJobGrandChild = Job.wrapFn(
|
|
1365
|
+
_resourceBlockTestAuxFn,
|
|
1366
|
+
outFile=outFile,
|
|
1367
|
+
sleepTime=5,
|
|
1368
|
+
writeVal="sJGC",
|
|
1369
|
+
cores=2,
|
|
1370
|
+
memory=int(availableMemory // 1.5),
|
|
1371
|
+
disk="1M",
|
|
1372
|
+
)
|
|
1134
1373
|
|
|
1135
1374
|
root.addChild(blocker)
|
|
1136
1375
|
root.addChild(firstJob)
|
|
@@ -1160,9 +1399,11 @@ class SingleMachineBatchSystemJobTest(hidden.AbstractBatchSystemJobTest):
|
|
|
1160
1399
|
outString = oFH.read()
|
|
1161
1400
|
# The ordering of b, fJ and sJ is non-deterministic since they are scheduled at the same
|
|
1162
1401
|
# time. We look for all possible permutations.
|
|
1163
|
-
possibleStarts = tuple(
|
|
1402
|
+
possibleStarts = tuple(
|
|
1403
|
+
"".join(x) for x in itertools.permutations(["b", "fJ", "sJ"])
|
|
1404
|
+
)
|
|
1164
1405
|
assert outString.startswith(possibleStarts)
|
|
1165
|
-
assert outString.endswith(
|
|
1406
|
+
assert outString.endswith("sJCsJGCfJC")
|
|
1166
1407
|
|
|
1167
1408
|
|
|
1168
1409
|
def _resourceBlockTestAuxFn(outFile, sleepTime, writeVal):
|
|
@@ -1172,7 +1413,7 @@ def _resourceBlockTestAuxFn(outFile, sleepTime, writeVal):
|
|
|
1172
1413
|
:param int sleepTime: Time to sleep for
|
|
1173
1414
|
:param str writeVal: Character to write
|
|
1174
1415
|
"""
|
|
1175
|
-
with open(outFile,
|
|
1416
|
+
with open(outFile, "a") as oFH:
|
|
1176
1417
|
fcntl.flock(oFH, fcntl.LOCK_EX)
|
|
1177
1418
|
oFH.write(writeVal)
|
|
1178
1419
|
time.sleep(sleepTime)
|
|
@@ -1184,9 +1425,10 @@ class MesosBatchSystemJobTest(hidden.AbstractBatchSystemJobTest, MesosTestSuppor
|
|
|
1184
1425
|
"""
|
|
1185
1426
|
Tests Toil workflow against the Mesos batch system
|
|
1186
1427
|
"""
|
|
1428
|
+
|
|
1187
1429
|
def getOptions(self, tempDir):
|
|
1188
1430
|
options = super().getOptions(tempDir)
|
|
1189
|
-
options.mesos_endpoint =
|
|
1431
|
+
options.mesos_endpoint = "localhost:5050"
|
|
1190
1432
|
return options
|
|
1191
1433
|
|
|
1192
1434
|
def getBatchSystemName(self):
|
|
@@ -1227,12 +1469,13 @@ def count(delta, file_path):
|
|
|
1227
1469
|
fcntl.flock(fd, fcntl.LOCK_EX)
|
|
1228
1470
|
try:
|
|
1229
1471
|
s = os.read(fd, 10)
|
|
1230
|
-
value, maxValue = (int(i) for i in s.decode(
|
|
1472
|
+
value, maxValue = (int(i) for i in s.decode("utf-8").split(","))
|
|
1231
1473
|
value += delta
|
|
1232
|
-
if value > maxValue:
|
|
1474
|
+
if value > maxValue:
|
|
1475
|
+
maxValue = value
|
|
1233
1476
|
os.lseek(fd, 0, 0)
|
|
1234
1477
|
os.ftruncate(fd, 0)
|
|
1235
|
-
os.write(fd, f
|
|
1478
|
+
os.write(fd, f"{value},{maxValue}".encode())
|
|
1236
1479
|
finally:
|
|
1237
1480
|
fcntl.flock(fd, fcntl.LOCK_UN)
|
|
1238
1481
|
finally:
|
|
@@ -1241,8 +1484,8 @@ def count(delta, file_path):
|
|
|
1241
1484
|
|
|
1242
1485
|
|
|
1243
1486
|
def getCounters(path):
|
|
1244
|
-
with open(path,
|
|
1245
|
-
concurrentTasks, maxConcurrentTasks = (int(i) for i in f.read().split(
|
|
1487
|
+
with open(path, "r+") as f:
|
|
1488
|
+
concurrentTasks, maxConcurrentTasks = (int(i) for i in f.read().split(","))
|
|
1246
1489
|
return concurrentTasks, maxConcurrentTasks
|
|
1247
1490
|
|
|
1248
1491
|
|
|
@@ -1253,4 +1496,4 @@ def resetCounters(path):
|
|
|
1253
1496
|
|
|
1254
1497
|
|
|
1255
1498
|
def get_omp_threads() -> str:
|
|
1256
|
-
return os.environ[
|
|
1499
|
+
return os.environ["OMP_NUM_THREADS"]
|