Skip to content

Commit 7aa10f5

Browse files
committed
feat: moved memory limits from GB to MB
1 parent 415f2cb commit 7aa10f5

18 files changed

Lines changed: 131 additions & 130 deletions

File tree

docs/source/UserGuide/Tutorials/JobManagementAdvanced/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,9 @@ using the "setRAMRequirements" method of the API::
363363

364364
j = Job()
365365
...
366-
j.setRAMRequirements(2, 4)
366+
j.setRAMRequirements(2500, 4000)
367367

368-
Calling ``Job().setRAMRequirements()`` takes 2 values, where the first is the minimum required amount of RAM (in GB) that the job requests.
368+
Calling ``Job().setRAMRequirements()`` takes 2 values, where the first is the minimum required amount of RAM (in MB) that the job requests.
369369
The second value instead specifies the limit that should not be surpassed.
370370

371371

src/DIRAC/Interfaces/API/Job.py

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
"""
2-
Job Base Class
2+
Job Base Class
33
4-
This class provides generic job definition functionality suitable for any VO.
4+
This class provides generic job definition functionality suitable for any VO.
55
6-
Helper functions are documented with example usage for the DIRAC API. An example
7-
script (for a simple executable) would be::
6+
Helper functions are documented with example usage for the DIRAC API. An example
7+
script (for a simple executable) would be::
88
9-
from DIRAC.Interfaces.API.Dirac import Dirac
10-
from DIRAC.Interfaces.API.Job import Job
9+
from DIRAC.Interfaces.API.Dirac import Dirac
10+
from DIRAC.Interfaces.API.Job import Job
1111
12-
j = Job()
13-
j.setCPUTime(500)
14-
j.setExecutable('/bin/echo hello')
15-
j.setExecutable('yourPythonScript.py')
16-
j.setExecutable('/bin/echo hello again')
17-
j.setName('MyJobName')
12+
j = Job()
13+
j.setCPUTime(500)
14+
j.setExecutable('/bin/echo hello')
15+
j.setExecutable('yourPythonScript.py')
16+
j.setExecutable('/bin/echo hello again')
17+
j.setName('MyJobName')
1818
19-
dirac = Dirac()
20-
jobID = dirac.submitJob(j)
21-
print 'Submission Result: ',jobID
19+
dirac = Dirac()
20+
jobID = dirac.submitJob(j)
21+
print 'Submission Result: ',jobID
2222
23-
Note that several executables can be provided and wil be executed sequentially.
23+
Note that several executables can be provided and wil be executed sequentially.
2424
"""
25+
2526
import os
2627
import re
2728
import shlex
@@ -519,26 +520,26 @@ def setDestination(self, destination):
519520
#############################################################################
520521
def setRAMRequirements(self, ramRequired: int = 0, maxRAM: int = 0):
521522
"""Helper function.
522-
Specify the RAM requirements for the job. 0 (default) means no specific requirements.
523+
Specify the RAM requirements for the job, in MB. 0 (default) means no specific requirements.
523524
524525
Example usage:
525526
526527
>>> job = Job()
527-
>>> job.setRAMRequirements(ramRequired=2)
528+
>>> job.setRAMRequirements(ramRequired=2000)
528529
means that the job needs at least 2 GBs of RAM to work. This is taken into consideration at job's matching time.
529530
The job definition does not specify an upper limit.
530531
From a user's point of view this is fine (normally, not for admins).
531532
532-
>>> job.setRAMRequirements(ramRequired=2, maxRAM=4)
533-
means that the job needs 2 GBs of RAM to work. 4 GBs will then be the upper limit for CG2 limits.
533+
>>> job.setRAMRequirements(ramRequired=500, maxRAM=3800)
534+
means that the job needs 500 MBs of RAM to work. 3.8 GBs will then be the upper limit for CG2 limits.
534535
535-
>>> job.setRAMRequirements(ramRequired=4, maxRAM=4)
536-
means that we should match this job if there is at least 4 available GBs of run. At the same time, CG2 will not allow to use more than that.
536+
>>> job.setRAMRequirements(ramRequired=3200, maxRAM=3200)
537+
means that we should match this job if there is at least 3.2 available GBs of run. At the same time, CG2 will not allow to use more than that.
537538
538-
>>> job.setRAMRequirements(maxRAM=4)
539+
>>> job.setRAMRequirements(maxRAM=4000)
539540
means that the job does not set a min amount of RAM (so can match--run "everywhere"), but the 4 GBs will then be the upper limit for CG2 limits.
540541
541-
>>> job.setRAMRequirements(ramRequired=8, maxRAM=4)
542+
>>> job.setRAMRequirements(ramRequired=8000, maxRAM=4000)
542543
Makes no sense, an error will be raised
543544
"""
544545
if ramRequired and maxRAM and ramRequired > maxRAM:
@@ -550,15 +551,15 @@ def setRAMRequirements(self, ramRequired: int = 0, maxRAM: int = 0):
550551
"MinRAM",
551552
"JDL",
552553
ramRequired,
553-
"GBs of RAM requested",
554+
"MBs of RAM requested",
554555
)
555556
if maxRAM:
556557
self._addParameter(
557558
self.workflow,
558559
"MaxRAM",
559560
"JDL",
560561
maxRAM,
561-
"Max GBs of RAM to be used",
562+
"Max MBs of RAM to be used",
562563
)
563564

564565
def setNumberOfProcessors(self, numberOfProcessors=None, minNumberOfProcessors=None, maxNumberOfProcessors=None):
@@ -753,7 +754,7 @@ def setTag(self, tags):
753754
Example usage:
754755
755756
>>> job = Job()
756-
>>> job.setTag( ['WholeNode','8GB'] )
757+
>>> job.setTag( ['WholeNode'] )
757758
758759
:param tags: single tag string or a list of tags
759760
:type tags: str or python:list

src/DIRAC/Resources/Computing/ComputingElement.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ def getDescription(self):
408408
result = self.getCEStatus()
409409
if result["OK"]:
410410
ceDict["NumberOfProcessors"] = result.get("AvailableProcessors", result.get("NumberOfProcessors", 1))
411-
ceDict["MaxRAM"] = result.get("AvailableRAM", result.get("MaxRAM", 1))
411+
ceDict["MaxRAM"] = result.get("AvailableRAM", result.get("MaxRAM", 1024))
412412
else:
413413
self.log.error(
414414
"Failure getting CE status", "(we keep going without the number of waiting and running pilots/jobs)"

src/DIRAC/Resources/Computing/PoolComputingElement.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
""" The Pool Computing Element is an "inner" CE (meaning it's used by a jobAgent inside a pilot)
1+
"""The Pool Computing Element is an "inner" CE (meaning it's used by a jobAgent inside a pilot)
22
33
It's used running several jobs simultaneously in separate processes, managed by a ProcessPool.
44
@@ -19,6 +19,7 @@
1919
2020
**Code Documentation**
2121
"""
22+
2223
import concurrent.futures
2324
import functools
2425

@@ -64,7 +65,8 @@ def __init__(self, ceUniqueID):
6465
self.taskID = 0
6566
self.processorsPerTask = {}
6667
self.ram = (
67-
1024 # Available RAM for the node, in GB. The default value is an arbitrary large value in case of no limit
68+
1024
69+
* 1024 # Available RAM for the node, in MB. The default value is an arbitrary large value in case of no limit
6870
)
6971
self.ramPerTask = {}
7072

@@ -195,7 +197,7 @@ def _getMemoryForJobs(self, kwargs):
195197
"""helper function to get the memory that will be allocated for the job
196198
197199
:param kwargs: job parameters
198-
:return: memory in GB or None if not enough memory
200+
:return: memory in MB or None if not enough memory
199201
"""
200202

201203
# # job requirements
@@ -227,7 +229,7 @@ def finalizeJob(self, taskID, future):
227229

228230
result = future.result() # This would be the result of the e.g. InProcess.submitJob()
229231
if result["OK"]:
230-
self.log.info("Task finished successfully:", f"{taskID}; {nProc} processor(s) and {ram}GB freed")
232+
self.log.info("Task finished successfully:", f"{taskID}; {nProc} processor(s) and {ram}MB freed")
231233
else:
232234
self.log.error("Task failed submission:", f"{taskID}; message: {result['Message']}")
233235
self.taskResults[taskID] = result

src/DIRAC/Resources/Computing/SingularityComputingElement.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
""" SingularityCE is a type of "inner" CEs
2-
(meaning it's used by a jobAgent inside a pilot).
3-
A computing element class using singularity containers,
4-
where Singularity is supposed to be found on the WN.
1+
"""SingularityCE is a type of "inner" CEs
2+
(meaning it's used by a jobAgent inside a pilot).
3+
A computing element class using singularity containers,
4+
where Singularity is supposed to be found on the WN.
55
6-
The goal of this CE is to start the job in the container set by
7-
the "ContainerRoot" config option.
6+
The goal of this CE is to start the job in the container set by
7+
the "ContainerRoot" config option.
88
9-
DIRAC can be re-installed within the container.
9+
DIRAC can be re-installed within the container.
1010
11-
See the Configuration/Resources/Computing documention for details on
12-
where to set the option parameters.
11+
See the Configuration/Resources/Computing documention for details on
12+
where to set the option parameters.
1313
"""
14+
1415
import json
1516
import os
1617
import re
@@ -420,7 +421,7 @@ def submitJob(self, executableFile, proxy=None, **kwargs):
420421
# if there's a max RAM available to the job, use that
421422
if self.maxRAM:
422423
self.ceParameters["MemoryLimitMB"] = min(
423-
self.maxRAM * 1024, self.ceParameters.get("MemoryLimitMB", 1024 * 1024)
424+
self.maxRAM, self.ceParameters.get("MemoryLimitMB", 1024 * 1024)
424425
) # 1024 * 1024 is an arbitrary large number
425426
result = CG2Manager().systemCall(
426427
0, cmd, callbackFunction=self.sendOutput, env=self.__getEnv(), ceParameters=self.ceParameters

src/DIRAC/Resources/Computing/test/Test_InProcessComputingElement.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ def test_submitJob():
5454
maxNumberOfProcessors=8,
5555
wholeNode=False,
5656
mpTag=True,
57-
MinRAM=2,
58-
MaxRAM=4,
57+
MinRAM=2500,
58+
MaxRAM=4000,
5959
jobDesc={"jobParams": jobParams, "resourceParams": resourceParams, "optimizerParams": optimizerParams},
6060
)
6161
assert res["OK"] is True

src/DIRAC/Resources/Computing/test/Test_PoolComputingElement.py

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"""
33
tests for PoolComputingElement module
44
"""
5+
56
import os
67
import time
78

@@ -87,7 +88,7 @@ def createAndDelete():
8788
def test_submit_and_shutdown(createAndDelete):
8889
time.sleep(0.5)
8990

90-
ceParameters = {"WholeNode": True, "NumberOfProcessors": 4, "MaxRAM": 4}
91+
ceParameters = {"WholeNode": True, "NumberOfProcessors": 4, "MaxRAM": 3800}
9192
ce = PoolComputingElement("TestPoolCE")
9293
ce.setParameters(ceParameters)
9394

@@ -149,7 +150,7 @@ def test_executeJob_wholeNode4(createAndDelete):
149150
time.sleep(0.5)
150151
taskIDs = {}
151152

152-
ceParameters = {"WholeNode": True, "NumberOfProcessors": 4, "MaxRAM": 16}
153+
ceParameters = {"WholeNode": True, "NumberOfProcessors": 4, "MaxRAM": 16000}
153154
ce = PoolComputingElement("TestPoolCE")
154155
ce.setParameters(ceParameters)
155156

@@ -164,10 +165,10 @@ def test_executeJob_wholeNode4(createAndDelete):
164165
assert result["UsedProcessors"] == 1
165166
assert result["AvailableProcessors"] == 3
166167
assert result["UsedRAM"] == 0
167-
assert result["AvailableRAM"] == 16
168+
assert result["AvailableRAM"] == 16000
168169
assert result["RunningJobs"] == 1
169170

170-
jobParams = {"mpTag": True, "numberOfProcessors": 2, "MaxRAM": 4}
171+
jobParams = {"mpTag": True, "numberOfProcessors": 2, "MaxRAM": 4000}
171172
result = ce.submitJob("testPoolCEJob_1.py", None, **jobParams)
172173
assert result["OK"] is True
173174
taskID = result["Value"]
@@ -177,8 +178,8 @@ def test_executeJob_wholeNode4(createAndDelete):
177178
result = ce.getCEStatus()
178179
assert result["UsedProcessors"] == 3
179180
assert result["AvailableProcessors"] == 1
180-
assert result["UsedRAM"] == 4
181-
assert result["AvailableRAM"] == 12
181+
assert result["UsedRAM"] == 4000
182+
assert result["AvailableRAM"] == 12000
182183

183184
assert result["RunningJobs"] == 2
184185

@@ -203,7 +204,7 @@ def test_executeJob_wholeNode8(createAndDelete):
203204
time.sleep(0.5)
204205
taskIDs = {}
205206

206-
ceParameters = {"WholeNode": True, "NumberOfProcessors": 8, "MaxRAM": 32}
207+
ceParameters = {"WholeNode": True, "NumberOfProcessors": 8, "MaxRAM": 32000}
207208
ce = PoolComputingElement("TestPoolCE")
208209
ce.setParameters(ceParameters)
209210

@@ -227,9 +228,9 @@ def test_executeJob_wholeNode8(createAndDelete):
227228
result = ce.getCEStatus()
228229
assert result["UsedProcessors"] == 5
229230
assert result["UsedRAM"] == 0
230-
assert result["AvailableRAM"] == 32
231+
assert result["AvailableRAM"] == 32000
231232

232-
jobParams = {"numberOfProcessors": 2, "MinRAM": 4, "MaxRAM": 8} # This is same as asking for SP
233+
jobParams = {"numberOfProcessors": 2, "MinRAM": 4000, "MaxRAM": 8000} # This is same as asking for SP
233234
result = ce.submitJob("testPoolCEJob_4.py", None, **jobParams)
234235
assert result["OK"] is True
235236
taskID = result["Value"]
@@ -238,10 +239,10 @@ def test_executeJob_wholeNode8(createAndDelete):
238239

239240
result = ce.getCEStatus()
240241
assert result["UsedProcessors"] == 6
241-
assert result["UsedRAM"] == 8
242-
assert result["AvailableRAM"] == 24
242+
assert result["UsedRAM"] == 8000
243+
assert result["AvailableRAM"] == 24000
243244

244-
jobParams = {"MinRAM": 8, "MaxRAM": 8} # This is same as asking for SP
245+
jobParams = {"MinRAM": 8000, "MaxRAM": 8000} # This is same as asking for SP
245246
result = ce.submitJob("testPoolCEJob_5.py", None, **jobParams)
246247
assert result["OK"] is True
247248
taskID = result["Value"]
@@ -250,10 +251,10 @@ def test_executeJob_wholeNode8(createAndDelete):
250251

251252
result = ce.getCEStatus()
252253
assert result["UsedProcessors"] == 7
253-
assert result["UsedRAM"] == 16
254-
assert result["AvailableRAM"] == 16
254+
assert result["UsedRAM"] == 16000
255+
assert result["AvailableRAM"] == 16000
255256

256-
jobParams = {"MaxRAM": 24} # This will fail
257+
jobParams = {"MaxRAM": 24000} # This will fail
257258
result = ce.submitJob("testPoolCEJob_6.py", None, **jobParams)
258259
assert result["OK"] is True
259260
taskID = result["Value"]
@@ -262,8 +263,8 @@ def test_executeJob_wholeNode8(createAndDelete):
262263

263264
result = ce.getCEStatus()
264265
assert result["UsedProcessors"] == 7
265-
assert result["UsedRAM"] == 16
266-
assert result["AvailableRAM"] == 16
266+
assert result["UsedRAM"] == 16000
267+
assert result["AvailableRAM"] == 16000
267268

268269
# now trying again would fail
269270
jobParams = {"mpTag": True, "numberOfProcessors": 3}
@@ -413,31 +414,31 @@ def test_executeJob_WholeNodeJobs(createAndDelete):
413414
[
414415
(None, None, {}, 1, 0),
415416
(None, None, {"mpTag": False}, 1, 0),
416-
(None, None, {"mpTag": True, "MaxRAM": 8}, 1, 8),
417+
(None, None, {"mpTag": True, "MaxRAM": 8000}, 1, 8000),
417418
(None, None, {"mpTag": True, "wholeNode": True}, 16, 0),
418419
(None, None, {"mpTag": True, "wholeNode": False}, 1, 0),
419-
(None, None, {"mpTag": True, "numberOfProcessors": 4, "MinRAM": 2}, 4, 2),
420-
(None, None, {"mpTag": True, "numberOfProcessors": 4, "MaxRAM": 4}, 4, 4),
421-
(None, None, {"mpTag": True, "numberOfProcessors": 4, "MaxRAM": 36}, 4, None),
422-
(None, None, {"mpTag": True, "numberOfProcessors": 4, "MinRAM": 2, "MaxRAM": 4}, 4, 4),
420+
(None, None, {"mpTag": True, "numberOfProcessors": 4, "MinRAM": 2000}, 4, 2000),
421+
(None, None, {"mpTag": True, "numberOfProcessors": 4, "MaxRAM": 4000}, 4, 4000),
422+
(None, None, {"mpTag": True, "numberOfProcessors": 4, "MaxRAM": 36000}, 4, None),
423+
(None, None, {"mpTag": True, "numberOfProcessors": 4, "MinRAM": 2000, "MaxRAM": 4000}, 4, 4000),
423424
(None, None, {"mpTag": True, "numberOfProcessors": 4, "maxNumberOfProcessors": 8}, 8, 0),
424425
(None, None, {"mpTag": True, "numberOfProcessors": 4, "maxNumberOfProcessors": 32}, 16, 0),
425-
({1: 4}, {1: 4}, {"mpTag": True, "wholeNode": True}, 0, 0),
426-
({1: 4}, {1: 4}, {"mpTag": True, "wholeNode": False}, 1, 0),
427-
({1: 4}, {1: 4}, {"mpTag": True, "numberOfProcessors": 2, "MinRAM": 8}, 2, 8),
428-
({1: 4}, {1: 4}, {"mpTag": True, "numberOfProcessors": 16, "MinRAM": 8, "MaxRAM": 12}, 0, 12),
429-
({1: 4}, {1: 4}, {"mpTag": True, "maxNumberOfProcessors": 2, "MaxRAM": 16}, 2, 16),
430-
({1: 4}, {1: 4}, {"mpTag": True, "numberOfProcessors": 2, "MaxRAM": 8}, 2, 8),
431-
({1: 4}, {1: 4}, {"mpTag": True, "maxNumberOfProcessors": 16, "MaxRAM": 32}, 12, None),
432-
({1: 4, 2: 8}, {1: 4}, {"mpTag": True, "numberOfProcessors": 2}, 2, 0),
433-
({1: 4, 2: 8}, {1: 4}, {"mpTag": True, "numberOfProcessors": 4}, 4, 0),
434-
({1: 4, 2: 8, 3: 8}, {1: 4}, {"mpTag": True, "numberOfProcessors": 4}, 0, 0),
426+
({1: 4}, {1: 4000}, {"mpTag": True, "wholeNode": True}, 0, 0),
427+
({1: 4}, {1: 4000}, {"mpTag": True, "wholeNode": False}, 1, 0),
428+
({1: 4}, {1: 4000}, {"mpTag": True, "numberOfProcessors": 2, "MinRAM": 8000}, 2, 8000),
429+
({1: 4}, {1: 4000}, {"mpTag": True, "numberOfProcessors": 16, "MinRAM": 8000, "MaxRAM": 12000}, 0, 12000),
430+
({1: 4}, {1: 4000}, {"mpTag": True, "maxNumberOfProcessors": 2, "MaxRAM": 16000}, 2, 16000),
431+
({1: 4}, {1: 4000}, {"mpTag": True, "numberOfProcessors": 2, "MaxRAM": 8000}, 2, 8000),
432+
({1: 4}, {1: 4000}, {"mpTag": True, "maxNumberOfProcessors": 16, "MaxRAM": 32000}, 12, None),
433+
({1: 4, 2: 8}, {1: 4000}, {"mpTag": True, "numberOfProcessors": 2}, 2, 0),
434+
({1: 4, 2: 8}, {1: 4000}, {"mpTag": True, "numberOfProcessors": 4}, 4, 0),
435+
({1: 4, 2: 8, 3: 8}, {1: 4000}, {"mpTag": True, "numberOfProcessors": 4}, 0, 0),
435436
],
436437
)
437438
def test__getLimitsForJobs(processorsPerTask, ramPerTask, kwargs, expected_processors, expected_memory):
438439
ce = PoolComputingElement("TestPoolCE")
439440
ce.processors = 16
440-
ce.ram = 32
441+
ce.ram = 32000
441442

442443
if processorsPerTask:
443444
ce.processorsPerTask = processorsPerTask

src/DIRAC/WorkloadManagementSystem/Client/DownloadInputData.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
""" The Download Input Data module wraps around the Replica Management
2-
components to provide access to datasets by downloading locally
1+
"""The Download Input Data module wraps around the Replica Management
2+
components to provide access to datasets by downloading locally
33
"""
4+
45
import os
56
import random
67
import tempfile

0 commit comments

Comments
 (0)