Skip to content

Commit 683424a

Browse files
committed
[core] pre/post tasks : fix logs & processing issues
1 parent 9b35cf5 commit 683424a

10 files changed

Lines changed: 109 additions & 69 deletions

File tree

bin/meshroom_compute

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ meshroom.setupEnvironment()
1818
import meshroom.core
1919
import meshroom.core.graph
2020
from meshroom.core.node import Status
21+
from meshroom.core.node import ChunkIndex
2122

2223

2324
parser = argparse.ArgumentParser(description='Execute a Graph of processes.')
@@ -49,11 +50,17 @@ parser.add_argument('-v', '--verbose',
4950
default=os.environ.get('MESHROOM_VERBOSE', 'info'),
5051
choices=['fatal', 'error', 'warning', 'info', 'debug', 'trace'])
5152

52-
parser.add_argument('-i', '--iteration', type=int,
53-
default=-1, help='')
53+
parser.add_argument('-i', '--iteration', type=int, default=ChunkIndex.NONE, help='')
54+
parser.add_argument('--preprocess', help='Execute preprocess chunk', action='store_true')
55+
parser.add_argument('--postprocess', help='Execute postprocess chunk', action='store_true')
5456

5557
args = parser.parse_args()
5658

59+
if args.preprocess:
60+
args.iteration = ChunkIndex.PREPROCESS
61+
elif args.postprocess:
62+
args.iteration = ChunkIndex.POSTPROCESS
63+
5764
# Setup the verbose level
5865
if args.extern:
5966
# For extern computation, we want to focus on the node computation log.
@@ -111,11 +118,16 @@ if args.node:
111118
print(f"InputNode: No computation to do.")
112119
sys.exit(0)
113120

121+
if args.iteration == ChunkIndex.NONE:
122+
chunks = node.chunks
123+
elif args.preprocess:
124+
chunks = [node._preprocessChunk]
125+
elif args.postprocess:
126+
chunks = [node._postprocessChunk]
127+
else:
128+
chunks = [node.chunks[args.iteration]]
129+
114130
if not args.forceStatus and not args.forceCompute:
115-
if args.iteration != -1:
116-
chunks = [node.chunks[args.iteration]]
117-
else:
118-
chunks = node.chunks
119131
for chunk in chunks:
120132
if chunk.status.status in submittedStatuses:
121133
# Particular case for the local isolated, the node status is set to RUNNING by the submitter directly.
@@ -129,24 +141,28 @@ if args.node:
129141
if args.extern:
130142
# Restore the log level
131143
logging.getLogger().setLevel(meshroom.logStringToPython[args.verbose])
132-
133-
node.prepareLogger(args.iteration)
134-
node.preprocess()
135-
if args.iteration != -1:
136-
chunk = node.chunks[args.iteration]
137-
if chunk._status.status == Status.STOPPED:
138-
print(f"Chunk {chunk}: status is STOPPED")
139-
killRunningJob(node)
140-
chunk.process(args.forceCompute, args.inCurrentEnv)
141-
else:
144+
145+
if args.iteration == ChunkIndex.NONE:
146+
# Process the whole node
142147
if node.nodeStatus.status == Status.STOPPED:
143148
print(f"Node {node}: status is STOPPED")
144149
killRunningJob(node)
150+
node.preprocess(args.forceCompute, args.inCurrentEnv)
151+
node.prepareLogger(args.iteration)
145152
node.process(args.forceCompute, args.inCurrentEnv)
146-
node.postprocess()
147-
node.restoreLogger()
153+
node.restoreLogger()
154+
node.postprocess(args.forceCompute, args.inCurrentEnv)
155+
else:
156+
chunk = chunks[0]
157+
if chunk._status.status == Status.STOPPED:
158+
print(f"Chunk {chunk}: status is STOPPED")
159+
killRunningJob(node)
160+
node.prepareLogger(args.iteration)
161+
chunk.process(args.forceCompute, args.inCurrentEnv)
162+
node.restoreLogger()
163+
148164
else:
149-
if args.iteration != -1:
165+
if args.iteration != ChunkIndex.NONE:
150166
print('Error: "--iteration" only makes sense when used with "--node".')
151167
sys.exit(-1)
152168
toNodes = None

bin/meshroom_createChunks

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,13 @@ if not args.forceStatus and not args.forceCompute:
129129
f"submitterSessionUid: {node._nodeStatus.submitterSessionUid}")
130130

131131
if chunksToProcess:
132-
node.prepareLogger()
133132
node.preprocess()
133+
node.prepareLogger()
134134
for chunk in chunksToProcess:
135135
logging.info(f"[MeshroomCreateChunks] process chunk {chunk}")
136136
chunk.process(args.forceCompute, args.inCurrentEnv)
137-
node.postprocess()
138137
node.restoreLogger()
138+
node.postprocess()
139139
else:
140140
logging.info(f"[MeshroomCreateChunks] -> create job to process chunks {[c for c in node.chunks]}")
141141
submitter.createChunkTask(node, graphFile=args.graphFile, cache=args.cache,

meshroom/core/desc/node.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# desc/node.py
2+
13
import enum
24
from inspect import getfile
35
from pathlib import Path
@@ -420,8 +422,11 @@ def processChunkInEnvironment(self, chunk):
420422
meshroomComputeCmd = f"{chunk.node.nodeDesc.pythonExecutable} {_MESHROOM_COMPUTE}" + \
421423
f" \"{chunk.node.graph.filepath}\" --node {chunk.node.name}" + \
422424
" --extern --inCurrentEnv"
423-
424-
if len(chunk.node.getChunks()) > 1:
425+
if chunk.isPreprocess:
426+
meshroomComputeCmd += f" --preprocess"
427+
elif chunk.isPostprocess:
428+
meshroomComputeCmd += f" --postprocess"
429+
elif len(chunk.node.getChunks()) >= 1:
425430
meshroomComputeCmd += f" --iteration {chunk.range.iteration}"
426431

427432
runtimeEnv = chunk.node.nodeDesc.plugin.runtimeEnv

meshroom/core/graph.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,25 +1775,32 @@ def executeGraph(graph, toNodes=None, forceCompute=False, forceStatus=False):
17751775
node.initStatusOnCompute(forceCompute)
17761776

17771777
for n, node in enumerate(nodes):
1778+
print(f"(executeGraph) {n} {node}")
17781779
try:
17791780
# If the node is in compatibility mode, it cannot be computed
17801781
if node.isCompatibilityNode:
17811782
logging.warning(f"{node.name} is in Compatibility Mode and cannot be computed: {node.issueDetails}.")
17821783
continue
17831784

1784-
node.preprocess()
1785+
print("A")
1786+
node.preprocess(forceCompute)
17851787
if not node._chunksCreated:
1788+
print("B create chunks")
17861789
node.createChunks()
17871790
multiChunks = len(node.chunks) > 1
1791+
print("C")
17881792
for c, chunk in enumerate(node.chunks):
1793+
print("D", c, chunk)
17891794
if multiChunks:
17901795
print('\n[{node}/{nbNodes}]({chunk}/{nbChunks}) {nodeName}'.format(
17911796
node=n+1, nbNodes=len(nodes),
17921797
chunk=c+1, nbChunks=len(node.chunks), nodeName=node.nodeType))
17931798
else:
17941799
print(f'\n[{n + 1}/{len(nodes)}] {node.nodeType}')
1800+
print("E")
17951801
chunk.process(forceCompute)
1796-
node.postprocess()
1802+
print("F")
1803+
node.postprocess(forceCompute)
17971804
except Exception as exc:
17981805
logging.error(f"Error on node computation: {exc}")
17991806
graph.clearSubmittedNodes()

meshroom/core/node.py

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
#!/usr/bin/env python
2+
3+
# core/node.py
4+
25
import sys
36
import atexit
47
import copy
@@ -62,6 +65,7 @@ class ExecMode(Enum):
6265

6366

6467
class ChunkIndex(IntEnum):
68+
NONE=-3
6569
PREPROCESS=-2
6670
POSTPROCESS=-1
6771
# Standard chunks are indexed from 0
@@ -404,25 +408,22 @@ def makeProgressBar(self, end, message=''):
404408

405409
f.close()
406410

407-
with open(self.logFile) as f:
411+
with open(self.logFile, "r") as f:
408412
content = f.read()
409413
self.progressBarPosition = content.rfind('\n')
410414

411-
f.close()
412-
413415
def updateProgressBar(self, value):
414416
assert self.progressBar
415417
assert value <= self.progressEnd
416418

417419
tics = round((value/self.progressEnd)*51)
418420

419-
with open(self.logFile, 'r+') as f:
421+
with open(self.logFile, "r+") as f:
420422
text = f.read()
421423
for i in range(tics-self.currentProgressTics):
422424
text = text[:self.progressBarPosition]+'*'+text[self.progressBarPosition:]
423425
f.seek(0)
424426
f.write(text)
425-
f.close()
426427

427428
self.currentProgressTics = tics
428429

@@ -657,13 +658,6 @@ def isFinished(self):
657658
return self._status.status == Status.SUCCESS
658659

659660
def process(self, forceCompute=False, inCurrentEnv=False):
660-
if self.isPreprocess:
661-
return self.node.nodeDesc.preprocess(self.node)
662-
if self.isPostprocess:
663-
return self.node.nodeDesc.postprocess(self.node)
664-
return self._process(forceCompute, inCurrentEnv)
665-
666-
def _process(self, forceCompute=False, inCurrentEnv=False):
667661
if not forceCompute and self._status.status == Status.SUCCESS:
668662
logging.info(f"Node chunk already computed: {self.name}")
669663
return
@@ -685,8 +679,12 @@ def _process(self, forceCompute=False, inCurrentEnv=False):
685679
self.statThread.start()
686680

687681
try:
688-
logging.info(f"[Process chunk] Start processing...")
689-
self.node.nodeDesc.processChunk(self)
682+
if self.isPreprocess:
683+
self.node.nodeDesc.preprocess(self.node)
684+
elif self.isPostprocess:
685+
self.node.nodeDesc.postprocess(self.node)
686+
else:
687+
self.node.nodeDesc.processChunk(self)
690688
# NOTE: this assumes saving the output attributes for each chunk
691689
self.node.saveOutputAttr()
692690
executionStatus = Status.SUCCESS
@@ -712,7 +710,6 @@ def _process(self, forceCompute=False, inCurrentEnv=False):
712710
self.statistics = stats.Statistics()
713711
del runningProcesses[self.name]
714712

715-
716713
def _processInIsolatedEnvironment(self):
717714
"""
718715
Process this node chunk in the isolated environment defined in the environment
@@ -1704,42 +1701,47 @@ def initStatusOnCompute(self, forceCompute=False):
17041701
chunkPlaceholder._status.status = self._nodeStatus.status
17051702
self._chunkPlaceholder.setObjectList([chunkPlaceholder])
17061703
self.chunksChanged.emit()
1704+
1705+
def getChunkName(self, iteration: int):
1706+
if iteration >= 0:
1707+
return str(self.chunks[iteration].index)
1708+
elif iteration == ChunkIndex.PREPROCESS:
1709+
return "preprocess"
1710+
elif iteration == ChunkIndex.POSTPROCESS:
1711+
return "postprocess"
1712+
return "0"
17071713

17081714
def processIteration(self, iteration):
17091715
self._chunks[iteration].process()
17101716

1711-
def preprocess(self):
1717+
def preprocess(self, forceCompute=False, inCurrentEnv=False):
17121718
""" Prepare the node processing """
1713-
print("(preprocess)")
1719+
self.prepareLogger(ChunkIndex.PREPROCESS)
17141720
if self.nodeDesc._hasPreprocess:
1715-
print("-> has preprocess")
1716-
# self.nodeDesc.preprocess(self)
1717-
self._preprocessChunk.process()
1721+
self._preprocessChunk.process(forceCompute, inCurrentEnv)
1722+
self.restoreLogger()
17181723

17191724
def process(self, forceCompute=False, inCurrentEnv=False):
1720-
print("(process)")
17211725
for chunk in self._chunks:
1722-
print("-> chunk", chunk)
17231726
chunk.process(forceCompute, inCurrentEnv)
17241727

1725-
def postprocess(self):
1728+
def postprocess(self, forceCompute=False, inCurrentEnv=False):
17261729
"""
17271730
Invoke the post process on Client Node to execute after the processing on the
17281731
node is completed
17291732
"""
1730-
print("(postprocess)")
1733+
self.prepareLogger(ChunkIndex.POSTPROCESS)
17311734
if self.nodeDesc._hasPostprocess:
1732-
print("-> has postprocess")
1733-
# self.nodeDesc.postprocess(self)
1734-
self._postprocessChunk.process()
1735+
self._postprocessChunk.process(forceCompute, inCurrentEnv)
1736+
self.restoreLogger()
17351737

17361738
def getLogHandlers(self):
17371739
return self._handlers
17381740

1739-
def prepareLogger(self, iteration=-1):
1741+
def prepareLogger(self, iteration=ChunkIndex.NONE):
17401742
# Get file handler path
1741-
chunkIndex = self.chunks[iteration].index if iteration != -1 else 0
1742-
logFileName = f"{chunkIndex}.log"
1743+
chunkName = self.getChunkName(iteration)
1744+
logFileName = f"{chunkName}.log"
17431745
logFile = os.path.join(self.internalFolder, logFileName)
17441746
# Setup logger
17451747
rootLogger = logging.getLogger()
@@ -2319,10 +2321,14 @@ def _resetChunks(self):
23192321
""" Set chunks on the node.
23202322
# TODO : Maybe don't delete chunks if we will recreate them as before ?
23212323
"""
2322-
if self.isInputNode:
2324+
if not self.isComputableType:
23232325
self._chunksCreated = True
23242326
return
23252327
# Disconnect signals
2328+
if self._preprocessChunk:
2329+
self._preprocessChunk.statusChanged.disconnect(self.globalStatusChanged)
2330+
if self._postprocessChunk:
2331+
self._postprocessChunk.statusChanged.disconnect(self.globalStatusChanged)
23262332
for chunk in self._chunks:
23272333
chunk.statusChanged.disconnect(self.globalStatusChanged)
23282334
# Empty list
@@ -2358,7 +2364,18 @@ def _resetChunks(self):
23582364
self._chunksCreated = False
23592365
self.setSize(0)
23602366
self._chunkPlaceholder.setObjectList([NodeChunk(self, desc.computation.Range())])
2361-
2367+
# Pre/post process
2368+
if self.nodeDesc._hasPreprocess:
2369+
self._preprocessChunk = NodeChunk(self, desc.Range(ChunkIndex.PREPROCESS))
2370+
self._preprocessChunk.statusChanged.connect(self.globalStatusChanged)
2371+
else:
2372+
self._preprocessChunk = None
2373+
if self.nodeDesc._hasPostprocess:
2374+
self._postprocessChunk = NodeChunk(self, desc.Range(ChunkIndex.POSTPROCESS))
2375+
self._postprocessChunk.statusChanged.connect(self.globalStatusChanged)
2376+
else:
2377+
self._postprocessChunk = None
2378+
23622379
# Create chunks when possible
23632380
self.chunksCreatedChanged.emit()
23642381
self.chunksChanged.emit()

meshroom/core/taskManager.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,9 @@ def run(self):
9595
multiChunks = len(node.chunks) > 1
9696
except TypeError:
9797
continue
98+
9899

99-
node.preprocess()
100+
node.preprocess(self.forceCompute)
100101
for cId, chunk in enumerate(node.chunks):
101102
if chunk.isFinishedOrRunning() or not self.isRunning():
102103
continue
@@ -128,7 +129,7 @@ def run(self):
128129
# Node already removed (for instance a global clear of _nodesToProcess)
129130
pass
130131
n.clearSubmittedChunks()
131-
node.postprocess()
132+
node.postprocess(self.forceCompute)
132133

133134
if stopAndRestart:
134135
break

meshroom/ui/qml/GraphEditor/ChunksListView.qml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ ColumnLayout {
2222
property int currentIndex: 0
2323

2424
function getCurrentChunkIndex() {
25-
console.log("(getCurrentChunkIndex)", currentIndex, chunks.length)
2625
if ( currentIndex == undefined || !chunks || currentIndex == ChunksListView.IndexItems.NULL ) { return -1 }
2726
let hasPreprocess = chunks.some(function(chk) { return chk.chunkIndex == ChunksListView.IndexItems.PREPROCESS })
2827
let hasPostprocess = chunks.some(function(chk) { return chk.chunkIndex == ChunksListView.IndexItems.POSTPROCESS })
@@ -33,7 +32,7 @@ ColumnLayout {
3332

3433
property int currentItemIndex: getCurrentChunkIndex()
3534

36-
property variant currentChunk: (currentItemIndex >= 0 && chunks && chunks.length > currentItemIndex) ? chunks[currentItemIndex].chunk : null
35+
property variant currentChunk: (currentItemIndex >= 0 && chunks && chunks.length > currentItemIndex) ? chunks[currentItemIndex].chunk : undefined
3736

3837
onChunksChanged: {
3938
// When the list changes, ensure the current index is in the new range
@@ -95,7 +94,6 @@ ColumnLayout {
9594
width: ListView.view.width
9695
leftPadding: 8
9796
onClicked: {
98-
console.log("clicked on chunk", chunkIndex, "(", text, ")")
9997
chunksLV.forceActiveFocus()
10098
root.currentIndex = chunkIndex
10199
}

meshroom/ui/qml/GraphEditor/NodeLog.qml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ FocusScope {
1717
property int currentChunkIndex
1818
property variant currentChunk
1919

20-
onCurrentChunkIndexChanged: {
21-
console.log("[log] changed chunk :", currentChunkIndex, root.currentChunk.logFile)
22-
}
23-
2420
Layout.fillWidth: true
2521
Layout.fillHeight: true
2622

0 commit comments

Comments
 (0)