diff --git a/ParforProgMon.m b/ParforProgMon.m new file mode 100644 index 0000000..4a0d0f6 --- /dev/null +++ b/ParforProgMon.m @@ -0,0 +1,157 @@ +% ParforProgMon - CLASS Progress monitor for `parfor` loops +% +% Usage +% Begin by creating a parallel pool. +% +% Then construct a ParforProgMon object: +% ppm = ParforProgMon(strWindowTitle, nNumIterations <, nProgressStepSize, nWidth, nHeight, nMinIterations>); +% +% 'strWindowTitle' is a string containing the title of the progress bar +% window. 'nNumIterations' is an integer with the total number of +% iterations in the loop. +% +% Optional arguments 'nProgressStepSize' specifies how +% many loop iterations should correspond to a single call to 'increment()'. +% 'nWidth' and 'nHeight' specify the size of the progress window. +% +% Within the parfor loop +% parfor (nIndex = 1:nNumIterations) +% if (mod(nIndex, nProgressStepSize) == 0) +% ppm.increment(); +% end +% end +% +% Modified from ParforProgMonv2. + +classdef ParforProgMon < handle + + properties ( GetAccess = private, SetAccess = private ) + Port + HostName + strAttachedFilesFolder + end + + properties (Transient, GetAccess = private, SetAccess = private) + JavaBit + end + + methods ( Static ) + function o = loadobj( X ) + % loadobj - METHOD REconstruct a ParforProgMon object + + % Once we've been loaded, we need to reconstruct ourselves correctly as a + % worker-side object. + % fprintf('Worker: Starting with {%s, %f, %s}\n', X.HostName, X.Port, X.strAttachedFilesFolder); + o = ParforProgMon( {X.HostName, X.Port, X.strAttachedFilesFolder} ); + end + end + + methods + function o = ParforProgMon(strWindowTitle, nNumIterations, nProgressStepSize, nWidth, nHeight, nMinIterations) + % ParforProgMon - CONSTRUCTOR Create a ParforProgMon object + % + % Usage: ppm = ParforProgMon(strWindowTitle, nNumIterations <, nProgressStepSize, nWidth, nHeight>) + % + % 'strWindowTitle' is a string containing the title of the + % progress bar window. 'nNumIterations' is an integer with the + % total number of iterations in the loop. 'nProgressStepSize' + % indicates that one update (call to 'increment') corresponds to + % this many iterations. 'nWidth' indicates the width of the + % progress window. 'nHeight' indicates the width of the progress + % window. + + if (~exist('nMinIterations', 'var') || isempty(nMinIterations)) + nMinIterations = 0; + end + + % - Are we a worker or a server? + if ((nargin == 1) && iscell(strWindowTitle)) + % - Worker constructor + % Get attached files + o.strAttachedFilesFolder = getAttachedFilesFolder(strWindowTitle{3}); + % fprintf('Worker: Attached files folder on worker is [%s]\n', o.strAttachedFilesFolder); + + % Add to java path + w = warning('off', 'MATLAB:Java:DuplicateClass'); + javaaddpath(o.strAttachedFilesFolder); + warning(w); + + % "Private" constructor used on the workers + o.JavaBit = ParforProgressMonitor.createWorker(strWindowTitle{1}, strWindowTitle{2}); + o.Port = []; + + elseif (nargin > 1) && (nNumIterations >= nMinIterations) + % - Server constructor + % Check arguments + if (~exist('nProgressStepSize', 'var') || isempty(nProgressStepSize)) + nProgressStepSize = 1; + end + + if (~exist('nWidth', 'var') || ~exist('nHeight', 'var') || isempty(nHeight) || isempty(nWidth)) + nWidth = 400; + nHeight = 80; + end + + % Check for an existing pool + pPool = gcp('nocreate'); + if (isempty(pPool)) + error('ParforProgMon:NeedPool', ... + '*** ParforProgMon: You must construct a pool before creating a ParforProgMon object.'); + end + + % Amend java path + strPath = fileparts(which('ParforProgMon')); + o.strAttachedFilesFolder = fullfile(strPath, 'java'); + % fprintf('Server: JAVA class folder is [%s]\n', o.strAttachedFilesFolder); + w = warning('off', 'MATLAB:Java:DuplicateClass'); + javaaddpath(o.strAttachedFilesFolder); + warning(w); + + % Distribute class to pool + if (ismember(pPool.AttachedFiles, o.strAttachedFilesFolder)) + pPool.updateAttachedFiles(); + else + pPool.addAttachedFiles(o.strAttachedFilesFolder); + end + + % Normal construction + o.JavaBit = ParforProgressMonitor.createServer( strWindowTitle, nNumIterations, nProgressStepSize, nWidth, nHeight ); + o.Port = double( o.JavaBit.getPort() ); + % Get the client host name from pctconfig + cfg = pctconfig; + o.HostName = cfg.hostname; + end + end + + function X = saveobj( o ) + % saveobj - METHOD Save a ParforProgMon object for serialisations + + % Only keep the Port, HostName and strAttachedFilesFolder + X.Port = o.Port; + X.HostName = o.HostName; + X.strAttachedFilesFolder = o.strAttachedFilesFolder; + end + + function increment( o ) + % increment - METHOD Indicate that a single loop execution has finished + + % Update the UI + if (~isempty(o.JavaBit)) + o.JavaBit.increment(); + end + end + + function delete( o ) + % delete - METHOD Delete a ParforProgMon object + + % - Make sure that any other threads that may have closed + % the UI down have a chance to do it first + pause(.01); + + % Close the UI + if (~isempty(o.JavaBit)) + o.JavaBit.done(); + end + end + end +end diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..4c37ee0 --- /dev/null +++ b/Readme.md @@ -0,0 +1,31 @@ +# Parfor progress monitor + + +## A Java-based `Matlab` class for progress monitoring during a `parfor` loop + +### Usage +Begin by creating a parallel pool. + +Then construct a ParforProgMon object: + + ppm = ParforProgMon(strWindowTitle, nNumIterations <, nProgressStepSize, nWidth, nHeight>); + + `strWindowTitle` is a string containing the title of the progress bar + window. `nNumIterations` is an integer with the total number of + iterations in the loop. + +#### Optional arguments + `nProgressStepSize` specifies to update the progress bar every time this + number of steps passes. `nWidth` and `nHeight` specify the size of the + progress window. + +Within the `parfor` loop: + + parfor (nIndex = 1:nNumIterations) + ppm.increment(); + end + +### Credits +[Parfor Progress monitor](https://www.mathworks.com/matlabcentral/fileexchange/24594-parfor-progress-monitor) + +[Parfor Progress monitor v2](https://www.mathworks.com/matlabcentral/fileexchange/31673-parfor-progress-monitor-v2) diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..68eb73a --- /dev/null +++ b/license.txt @@ -0,0 +1,29 @@ +Copyright (c) 2016, Dylan Muir +Copyright (c) 2011, Willem-Jan de Goeij +Copyright (c) 2009, The MathWorks, 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 the The MathWorks, Inc. nor the names + of its contributors 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. diff --git a/progress_bar.png b/progress_bar.png new file mode 100644 index 0000000..8fc476c Binary files /dev/null and b/progress_bar.png differ