From 5b571fe565cd80db15dd6ae41abe33c57e4d05e3 Mon Sep 17 00:00:00 2001 From: Andrew Kaufman Date: Tue, 2 Sep 2014 16:18:11 -0700 Subject: [PATCH 1/4] Adding TaskList This can be used to collect Executable tasks for dispatching all at once --- python/Gaffer/TaskList.py | 63 +++++++++++++++++++++++++++ python/Gaffer/__init__.py | 1 + python/GafferTest/TaskListTest.py | 71 +++++++++++++++++++++++++++++++ python/GafferTest/__init__.py | 1 + python/GafferUI/TaskListUI.py | 46 ++++++++++++++++++++ startup/gui/menus.py | 1 + 6 files changed, 183 insertions(+) create mode 100644 python/Gaffer/TaskList.py create mode 100644 python/GafferTest/TaskListTest.py create mode 100644 python/GafferUI/TaskListUI.py diff --git a/python/Gaffer/TaskList.py b/python/Gaffer/TaskList.py new file mode 100644 index 00000000000..6ebcadd414c --- /dev/null +++ b/python/Gaffer/TaskList.py @@ -0,0 +1,63 @@ +########################################################################## +# +# Copyright (c) 2014, Image Engine Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with +# the distribution. +# +# * Neither the name of John Haddon nor the names of +# any other contributors to this software may be used to endorse or +# promote products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +########################################################################## + +import os +import subprocess + +import IECore + +import Gaffer + +# Used to collect Executable tasks for dispatching all at once +class TaskList( Gaffer.ExecutableNode ) : + + def __init__( self, name = "TaskList" ) : + + Gaffer.ExecutableNode.__init__( self, name ) + + def hash( self, context ) : + + h = Gaffer.ExecutableNode.hash( self, context ) + # we don't want different TaskLists to look like the same task + h.append( self.relativeName( self.ancestor( Gaffer.ScriptNode ) ) ) + + return h + + def execute( self ) : + + pass + +IECore.registerRunTimeTyped( TaskList, typeName = "Gaffer::TaskList" ) diff --git a/python/Gaffer/__init__.py b/python/Gaffer/__init__.py index d5c76e717b4..aeee2f2f736 100644 --- a/python/Gaffer/__init__.py +++ b/python/Gaffer/__init__.py @@ -66,5 +66,6 @@ from OutputRedirection import OutputRedirection from LocalDispatcher import LocalDispatcher from SystemCommand import SystemCommand +from TaskList import TaskList __import__( "IECore" ).loadConfig( "GAFFER_STARTUP_PATHS", {}, subdirectory = "Gaffer" ) diff --git a/python/GafferTest/TaskListTest.py b/python/GafferTest/TaskListTest.py new file mode 100644 index 00000000000..2542a601989 --- /dev/null +++ b/python/GafferTest/TaskListTest.py @@ -0,0 +1,71 @@ +########################################################################## +# +# Copyright (c) 2014, Image Engine Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with +# the distribution. +# +# * Neither the name of John Haddon nor the names of +# any other contributors to this software may be used to endorse or +# promote products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +########################################################################## + +import os +import unittest + +import IECore + +import Gaffer +import GafferTest + +class TaskListTest( GafferTest.TestCase ) : + + def test( self ) : + + n = Gaffer.TaskList() + c = Gaffer.Context() + c2 = Gaffer.Context() + c2["frame"] = 10.0 + self.assertEqual( n.hash( c ), n.hash( c2 ) ) + + n2 = Gaffer.TaskList( "TaskList2" ) + self.assertNotEqual( n.hash( c ), n2.hash( c ) ) + self.assertNotEqual( n.hash( c2 ), n2.hash( c2 ) ) + + def setUp( self ) : + + for f in [ "/tmp/systemCommandTest.txt" ] : + if os.path.exists( f ) : + os.remove( f ) + + def tearDown( self ) : + + self.setUp() + +if __name__ == "__main__": + unittest.main() + diff --git a/python/GafferTest/__init__.py b/python/GafferTest/__init__.py index 9bbe353f771..6b1981b1690 100644 --- a/python/GafferTest/__init__.py +++ b/python/GafferTest/__init__.py @@ -136,6 +136,7 @@ def wrapper( self ) : from MetadataTest import MetadataTest from StringAlgoTest import StringAlgoTest from SystemCommandTest import SystemCommandTest +from TaskListTest import TaskListTest if __name__ == "__main__": import unittest diff --git a/python/GafferUI/TaskListUI.py b/python/GafferUI/TaskListUI.py new file mode 100644 index 00000000000..1b2c92029cf --- /dev/null +++ b/python/GafferUI/TaskListUI.py @@ -0,0 +1,46 @@ +########################################################################## +# +# Copyright (c) 2014, Image Engine Design Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided with +# the distribution. +# +# * Neither the name of John Haddon nor the names of +# any other contributors to this software may be used to endorse or +# promote products derived from this software without specific prior +# written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +########################################################################## + +import Gaffer +import GafferUI + +Gaffer.Metadata.registerNodeDescription( + +Gaffer.TaskList, + +"""Used to collect Executable tasks for dispatching all at once""", + +) diff --git a/startup/gui/menus.py b/startup/gui/menus.py index f3d813c7683..4cfc188ab82 100644 --- a/startup/gui/menus.py +++ b/startup/gui/menus.py @@ -280,3 +280,4 @@ def __shaderNodeCreator( nodeName, shaderName ) : nodeMenu.append( "/Utility/Reference", GafferUI.ReferenceUI.nodeMenuCreateCommand ) nodeMenu.definition().append( "/Utility/Backdrop", { "command" : GafferUI.BackdropUI.nodeMenuCreateCommand } ) nodeMenu.append( "/Utility/System Command", Gaffer.SystemCommand, searchText = "SystemCommand" ) +nodeMenu.append( "/Utility/Task List", Gaffer.TaskList, searchText = "TaskList" ) From 53361c8919977dbe73158844955458e38063eda7 Mon Sep 17 00:00:00 2001 From: Andrew Kaufman Date: Wed, 8 Oct 2014 16:50:23 -0700 Subject: [PATCH 2/4] LocalDispatcher outputs an info message for TaskLists. Fixes #947. --- python/Gaffer/LocalDispatcher.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/Gaffer/LocalDispatcher.py b/python/Gaffer/LocalDispatcher.py index 43fd76f7187..fb231bf2cbd 100644 --- a/python/Gaffer/LocalDispatcher.py +++ b/python/Gaffer/LocalDispatcher.py @@ -109,6 +109,10 @@ def __backgroundDispatch( self, batch, scriptFile, messageTitle ) : script = batch.node().scriptNode() + if isinstance( batch.node(), Gaffer.TaskList ) : + IECore.msg( IECore.MessageHandler.Level.Info, messageTitle, "Finished " + batch.node().relativeName( script ) ) + return + taskContext = batch.context() frames = str( IECore.frameListFromList( [ int(x) for x in batch.frames() ] ) ) From 5febf1e42291cb2fa5dedee795dcbce621ce9812 Mon Sep 17 00:00:00 2001 From: Andrew Kaufman Date: Thu, 9 Oct 2014 17:48:06 -0700 Subject: [PATCH 3/4] TaskList returns an empty hash --- python/Gaffer/TaskList.py | 6 +----- python/GafferTest/TaskListTest.py | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/python/Gaffer/TaskList.py b/python/Gaffer/TaskList.py index 6ebcadd414c..ea4030066a5 100644 --- a/python/Gaffer/TaskList.py +++ b/python/Gaffer/TaskList.py @@ -50,11 +50,7 @@ def __init__( self, name = "TaskList" ) : def hash( self, context ) : - h = Gaffer.ExecutableNode.hash( self, context ) - # we don't want different TaskLists to look like the same task - h.append( self.relativeName( self.ancestor( Gaffer.ScriptNode ) ) ) - - return h + return IECore.MurmurHash() def execute( self ) : diff --git a/python/GafferTest/TaskListTest.py b/python/GafferTest/TaskListTest.py index 2542a601989..fbb4f8343e6 100644 --- a/python/GafferTest/TaskListTest.py +++ b/python/GafferTest/TaskListTest.py @@ -53,8 +53,8 @@ def test( self ) : self.assertEqual( n.hash( c ), n.hash( c2 ) ) n2 = Gaffer.TaskList( "TaskList2" ) - self.assertNotEqual( n.hash( c ), n2.hash( c ) ) - self.assertNotEqual( n.hash( c2 ), n2.hash( c2 ) ) + self.assertEqual( n.hash( c ), n2.hash( c ) ) + self.assertEqual( n.hash( c2 ), n2.hash( c2 ) ) def setUp( self ) : From 423a1b26cbfa7b36069b28f44bcb232302b2fc1a Mon Sep 17 00:00:00 2001 From: Andrew Kaufman Date: Thu, 9 Oct 2014 18:04:09 -0700 Subject: [PATCH 4/4] Dispatcher no longer collapses tasks with an empty hash. --- src/Gaffer/Dispatcher.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Gaffer/Dispatcher.cpp b/src/Gaffer/Dispatcher.cpp index 639104dd31a..36b2d94fbd6 100644 --- a/src/Gaffer/Dispatcher.cpp +++ b/src/Gaffer/Dispatcher.cpp @@ -402,14 +402,22 @@ Dispatcher::TaskBatchPtr Dispatcher::acquireBatch( const ExecutableNode::Task &t } } - tasksToBatches[taskHash] = batch; + if ( taskHash != MurmurHash() ) + { + tasksToBatches[taskHash] = batch; + } + return batch; } } TaskBatchPtr batch = new TaskBatch( task ); currentBatches[hash] = batch; - tasksToBatches[taskHash] = batch; + if ( taskHash != MurmurHash() ) + { + tasksToBatches[taskHash] = batch; + } + return batch; }