Skip to content

Commit 15b7db5

Browse files
committed
[core] submitter : retrieve job on node update + fix some ui issues
1 parent 3223261 commit 15b7db5

File tree

11 files changed

+100
-62
lines changed

11 files changed

+100
-62
lines changed

bin/meshroom_compute

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ if args.node:
8282
print(f"Error: Node {node} has been submitted before chunks have been created." \
8383
"See file: \"{node.nodeStatusFile}\".")
8484
sys.exit(-1)
85+
86+
if node._isInputNode():
87+
print(f"InputNode: No computation to do.")
8588

8689
if not args.forceStatus and not args.forceCompute:
8790
if args.iteration != -1:

bin/meshroom_createChunks

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ meshroom.setupEnvironment()
2323

2424
import meshroom.core
2525
import meshroom.core.graph
26-
from meshroom.core.submitter import jobManager
2726
from meshroom.core import submitters
2827
from meshroom.core.submitter import SubmitterOptionsEnum
2928
from meshroom.core.node import Status

meshroom/core/graph.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import meshroom.core
1616
from meshroom.common import BaseObject, DictModel, Slot, Signal, Property
1717
from meshroom.core import Version
18+
from meshroom.core import submitters
1819
from meshroom.core.attribute import Attribute, ListAttribute, GroupAttribute
1920
from meshroom.core.exception import GraphCompatibilityError, StopGraphVisit, StopBranchVisit
2021
from meshroom.core.graphIO import GraphIO, GraphSerializer, TemplateGraphSerializer, PartialGraphSerializer
@@ -1457,6 +1458,19 @@ def updateNodesPerUid(self):
14571458
# Now, update each individual node
14581459
for node in self.nodes:
14591460
node.updateDuplicates(nodesPerUid)
1461+
1462+
def updateJobManagerWithNode(self, node):
1463+
if node._uid in jobManager._nodeToJob.keys():
1464+
return
1465+
jobInfos = node._nodeStatus.jobInfos
1466+
if not jobInfos:
1467+
return
1468+
jid, subName = jobInfos.get("jid"), jobInfos.get("submitterName")
1469+
for _subName, sub in submitters.items():
1470+
if _subName == subName:
1471+
job = sub.retrieveJob(int(jid))
1472+
jobManager.addJob(job, [node])
1473+
break
14601474

14611475
def update(self):
14621476
if not self._updateEnabled:
@@ -1469,6 +1483,7 @@ def update(self):
14691483
self.updateStatusFromCache()
14701484
for node in self.nodes:
14711485
node.dirty = False
1486+
self.updateJobManagerWithNode(node)
14721487

14731488
self.updateNodesPerUid()
14741489

@@ -1718,6 +1733,7 @@ def submitGraph(graph, submitter, toNodes=None, submitLabel="{projectName}"):
17181733

17191734
for node in nodesToProcess:
17201735
node.initStatusOnSubmit()
1736+
jobManager.resetNodeJob(node)
17211737

17221738
try:
17231739
res = sub.submit(nodesToProcess, edgesToProcess, graph.filepath, submitLabel=submitLabel)

meshroom/core/node.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -94,54 +94,54 @@ def resetDynamicValues(self):
9494
self.execMode: ExecMode = ExecMode.NONE
9595
self.jobInfos: dict = {}
9696

97+
def setNodeType(self, node):
98+
"""
99+
Set the node type and package information from the given node.
100+
We do not set the name in this method as it may vary if there are duplicates.
101+
"""
102+
self.nodeType = node.nodeType
103+
self.packageName = node.packageName
104+
self.packageVersion = node.packageVersion
105+
self.mrNodeType = node.getMrNodeType()
106+
97107
def setNode(self, node):
98108
""" Set the node information from one node instance. """
99109
self.nodeName = node.name
100110
self.setNodeType(node)
101111

102-
def initExternSubmit(self):
103-
"""
104-
When submitting a node, we reset the status information to ensure that we do not keep
105-
outdated information.
106-
"""
107-
self.resetDynamicValues()
108-
self.submitterSessionUid = meshroom.core.sessionUid
109-
self.status = Status.SUBMITTED
110-
self.execMode = ExecMode.EXTERN
111-
112112
def setJob(self, jid, submitterName):
113113
""" Set Job infos on the node so that """
114114
self.jobInfos = {
115115
"jid": str(jid),
116116
"submitterName": str(submitterName),
117117
}
118-
118+
119119
@property
120120
def jobName(self):
121121
if self.jobInfos:
122122
return f"{self.jobInfos['submitterName']}<{self.jobInfos['jid']}>"
123123
else:
124124
return "UNKNOWN"
125125

126-
def initLocalSubmit(self):
126+
def initExternSubmit(self):
127127
"""
128128
When submitting a node, we reset the status information to ensure that we do not keep
129129
outdated information.
130130
"""
131131
self.resetDynamicValues()
132132
self.submitterSessionUid = meshroom.core.sessionUid
133133
self.status = Status.SUBMITTED
134-
self.execMode = ExecMode.LOCAL
134+
self.execMode = ExecMode.EXTERN
135135

136-
def setNodeType(self, node):
136+
def initLocalSubmit(self):
137137
"""
138-
Set the node type and package information from the given node.
139-
We do not set the name in this method as it may vary if there are duplicates.
138+
When submitting a node, we reset the status information to ensure that we do not keep
139+
outdated information.
140140
"""
141-
self.nodeType = node.nodeType
142-
self.packageName = node.packageName
143-
self.packageVersion = node.packageVersion
144-
self.mrNodeType = node.getMrNodeType()
141+
self.resetDynamicValues()
142+
self.submitterSessionUid = meshroom.core.sessionUid
143+
self.status = Status.SUBMITTED
144+
self.execMode = ExecMode.LOCAL
145145

146146
def toDict(self):
147147
keys = list(self.__slots__) or []
@@ -1348,7 +1348,6 @@ def isExtern(self):
13481348
if not self._chunksCreated:
13491349
if self._nodeStatus.execMode == ExecMode.EXTERN:
13501350
return True
1351-
# TODO : use sessionID
13521351
elif self._nodeStatus.execMode == ExecMode.LOCAL and self._nodeStatus.status in (Status.SUBMITTED, Status.RUNNING):
13531352
return meshroom.core.sessionUid != self._nodeStatus.submitterSessionUid
13541353
return False
@@ -1621,6 +1620,7 @@ def initStatusOnCompute(self, forceCompute=False):
16211620
hasChunkToLaunch = True
16221621
for chunk in self._chunks:
16231622
if forceCompute or (chunk._status.status not in (Status.RUNNING, Status.SUCCESS)):
1623+
hasChunkToLaunch = True
16241624
chunk._status.setNode(self)
16251625
chunk._status.initLocalSubmit()
16261626
chunk.upgradeStatusFile()
@@ -2046,6 +2046,9 @@ def _hasDisplayableShape(self):
20462046
nodeType = Property(str, nodeType.fget, constant=True)
20472047
documentation = Property(str, getDocumentation, constant=True)
20482048
nodeInfos = Property(Variant, getNodeInfos, constant=True)
2049+
nodeStatusChanged = Signal()
2050+
nodeStatus = Property(Variant, lambda self: self._nodeStatus, notify=nodeStatusChanged)
2051+
nodeStatusNodeName = Property(str, lambda self: self._nodeStatus.nodeName, notify=nodeStatusChanged)
20492052
positionChanged = Signal()
20502053
position = Property(Variant, position.fget, position.fset, notify=positionChanged)
20512054
x = Property(float, lambda self: self._position.x, notify=positionChanged)

meshroom/core/submitter.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ def addJob(self, job: BaseSubmittedJob, nodes):
150150
# Update the node status file to store the job ID
151151
node.setJobId(jid, job.submitterName)
152152

153+
def resetNodeJob(self, node):
154+
node._nodeStatus.jobInfos = {}
155+
if node._uid in self._nodeToJob:
156+
del self._nodeToJob[node._uid]
157+
153158
def getJob(self, jobId: str) -> Optional[BaseSubmittedJob]:
154159
return self._jobs.get(jobId)
155160

meshroom/core/taskManager.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ def submit(self, graph, submitter=None, toNodes=None, submitLabel="{projectName}
525525
for node in nodesToProcess:
526526
node.destroyed.connect(lambda obj=None, name=node.name: self.onNodeDestroyed(obj, name))
527527
node.initStatusOnSubmit()
528+
jobManager.resetNodeJob(node)
528529

529530
graph.updateMonitoredFiles()
530531

meshroom/ui/graph.py

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ def compareFilesTimes(self, times):
203203
# update chunk status if last modification time has changed since previous record
204204
if fileModTime != chunk.statusFileLastModTime:
205205
chunk.updateStatusFromCache()
206-
if chunk.status.status == Status.SUCCESS:
206+
if chunk._status.status == Status.SUCCESS:
207207
hasChangesAndSuccess = True
208208
elif _type == "node":
209209
node = _item
@@ -715,17 +715,14 @@ def pauseJob(self, node: Node):
715715
try:
716716
job.pauseJob()
717717
except Exception as e:
718-
self.parent().showMessage(f"Paused node {node.label} on farm")
719718
logging.warning(f"Error on pauseJob :\n{e}")
720-
else:
721-
for chunk in self._sortedDFSChunks:
722-
if jobManager.getNodeJob(chunk.node) == job:
723-
chunk.updateStatusFromCache()
724-
chunk.upgradeStatusTo(Status.NONE)
725719
self.parent().showMessage(f"Failed to pause the job for node {node}", "error")
720+
else:
721+
self.parent().showMessage(f"Paused node {node.label} on farm")
722+
elif not node.isExtern():
723+
self.parent().showMessage(f"PauseJob is only available in local computation mode !", "warning")
726724
else:
727-
self._taskManager.clear()
728-
self.parent().showMessage(f"Cleared the task manager")
725+
self.parent().showMessage(f"Cannot retrieve the job", "error")
729726

730727
@Slot(Node)
731728
def resumeJob(self, node: Node):
@@ -740,11 +737,7 @@ def resumeJob(self, node: Node):
740737
self.parent().showMessage(f"Failed to rsume node {node.label} on farm")
741738
logging.warning(f"Error on resumeJob :\n{e}")
742739
else:
743-
for chunk in self._sortedDFSChunks:
744-
if jobManager.getNodeJob(chunk.node) == job:
745-
chunk.updateStatusFromCache()
746-
chunk.upgradeStatusTo(Status.SUBMITTED)
747-
self.parent().showMessage(f"Resumed the job for node {node}", "error")
740+
self.parent().showMessage(f"Resumed the job for node {node}")
748741
else:
749742
# In this case user can just relaunch the node computation
750743
# Could be implemented if we had a paused state on the task manager
@@ -765,17 +758,21 @@ def interruptJob(self, node: Node):
765758
else:
766759
for chunk in self._sortedDFSChunks:
767760
if jobManager.getNodeJob(chunk.node) == job:
768-
chunk.updateStatusFromCache()
769-
chunk.upgradeStatusTo(Status.STOPPED)
770-
# TODO : Also nodes without chunks ?
761+
if chunk._status.status in (Status.SUBMITTED, Status.RUNNING):
762+
chunk.updateStatusFromCache()
763+
chunk.upgradeStatusTo(Status.STOPPED)
764+
for node in self._graph.dfsOnFinish(None)[0]:
765+
if not node._chunksCreated and node._nodeStatus.status in (Status.SUBMITTED, Status.RUNNING):
766+
node.upgradeStatusTo(Status.STOPPED)
771767
self.parent().showMessage(f"Interrupted the job for node {node}")
772-
else:
768+
elif not node.isExtern():
773769
self._taskManager.clear()
774770
for chunk in node._chunks:
775771
if chunk._status.status == Status.RUNNING and not chunk.isExtern():
776772
chunk.stopProcess()
777-
778773
self.parent().showMessage(f"Cleared the task manager")
774+
else:
775+
self.parent().showMessage(f"Could not retrieve job for node {node}", "error")
779776

780777
@Slot(Node)
781778
def restartJobErrorTasks(self, node: Node):
@@ -790,7 +787,9 @@ def restartJobErrorTasks(self, node: Node):
790787
continue
791788
if jobManager.getNodeJob(chunk.node) == job:
792789
chunk.upgradeStatusTo(Status.SUBMITTED)
793-
# TODO : Also nodes without chunks ?
790+
for node in self._graph.dfsOnFinish(None)[0]:
791+
if not node._chunksCreated and node._nodeStatus.status in (Status.ERROR, Status.STOPPED, Status.KILLED):
792+
node.upgradeStatusTo(Status.SUBMITTED)
794793
job.restartErrorTasks()
795794
job.resumeJob()
796795
except Exception as e:

meshroom/ui/qml/GraphEditor/NodeChunks.qml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ ListView {
4545
color: root.targetNode !== null
4646
? (root.targetNode.globalStatus === "NONE"
4747
? Colors.darkpurple
48-
: Colors.statusColors[root.targetNode.globalStatus])
48+
: Colors.getNodeColor(root.targetNode, { "NONE": root.defaultColor }))
4949
: "transparent"
5050
enabled: modelSize == 0
5151
visible: enabled

meshroom/ui/qml/GraphEditor/NodeEditor.qml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,9 @@ Panel {
284284
// The list of chunks
285285
ChunksListView {
286286
id: chunksLV
287-
enabled: root.node.chunksCreated
287+
enabled: root.node ? root.node.chunksCreated : false
288+
chunks: root.node ? root.node.chunks : null
288289
visible: enabled && (tabBar.currentIndex >= 1 && tabBar.currentIndex <= 3)
289-
chunks: root.node.chunks
290290
SplitView.preferredWidth: 55
291291
SplitView.minimumWidth: 20
292292
}

meshroom/ui/qml/GraphEditor/TaskManager.qml

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -436,30 +436,25 @@ Item {
436436
property var node: object
437437

438438
spacing: 3
439-
439+
440440
delegate: Loader {
441441
id: chunkDelegate
442-
width: ListView.view.model ? (ListView.view.width / ListView.view.model.count) - 3 : 0
443-
height: ListView.view.height
442+
// width: ListView.view.model
443+
// ? ListView.view.width / ListView.view.model.count - chunkList.spacing
444+
// : 0
445+
width: ListView.view.model
446+
? (ListView.view.width - (ListView.view.model.count - 1) * chunkList.spacing) / ListView.view.model.count
447+
: 0
444448

445-
function getChunkBorderColor() {
446-
if (chunkList.node === uigraph.selectedNode) {
447-
if (root.selectedChunk == object)
448-
return Colors.sysPalette.text
449-
else
450-
return Qt.darker(Colors.sysPalette.text, 1.3)
451-
} else {
452-
return "transparent"
453-
}
454-
}
449+
height: ListView.view.height
455450

456451
sourceComponent: Label {
457452
anchors.fill: parent
458453
background: Rectangle {
459454
color: Colors.getChunkColor(object, {"NONE": bgColor})
460455
radius: 3
461456
border.width: 2
462-
border.color: chunkDelegate.getChunkBorderColor()
457+
border.color: (root.selectedChunk == object) ? Qt.darker(color, 1.3) : "transparent"
463458
}
464459

465460
MouseArea {
@@ -478,10 +473,11 @@ Item {
478473
visible: enabled
479474
anchors.fill: parent
480475
background: Rectangle {
481-
color: chunkList.node.globalStatus == "NONE" ? Colors.darkpurple : Colors.statusColors[chunkList.node.globalStatus]
476+
color: Colors.darkpurple
477+
// color: Colors.getNodeColor(chunkList.node, {"NONE": Colors.darkpurple})
482478
radius: 3
483479
border.width: 2
484-
border.color: chunkList.node === uigraph.selectedNode ? Colors.sysPalette.text : "transparent"
480+
border.color: (chunkList.node === uigraph.selectedNode) ? Qt.lighter(color, 1.3) : "transparent"
485481
}
486482

487483
MouseArea {

0 commit comments

Comments
 (0)