POV-Ray : Newsgroups : povray.general : Scripts for Parallel Rendering of Animations Server Time
28 Dec 2024 19:50:11 EST (-0500)
  Scripts for Parallel Rendering of Animations (Message 1 to 5 of 5)  
From: Verklagekasper
Subject: Scripts for Parallel Rendering of Animations
Date: 27 Oct 2011 08:25:01
Message: <web.4ea94ce98e2d0576ac8986340@news.povray.org>
Hi, I just wanted to share this.

Rendering a complex animation with Povray can easily take weeks if only a single
processor core is at hand. Even with Povray 3.7, which supports multiple cores,
the power of one multi-core system may not be enough to finish an animation in
acceptable time. The obivious solution would be to let several machines render
the frames in parallel. Povray doesn't have native support for this, but it can
be done by the help of scripts. In this article, I'm going to present such
scripts for parallel processing of Povray animations under Windows and Linux.

The scripts in the article are tailored for the following example situation:
We have an animation described by a scene file named landscape.pov and an .ini
file landscape.ini such that, if Povray was started with landscape.ini as input,
it would render all frames of the animation in one go. Also, we assume that the
order in which the frames are rendered does not matter, ie. there is no data
transfer from one frame to the next frame.
The animation shall be 458 seconds long at 30 frames per second. That is,
landscape.ini looks similar to this:

;
; landscape.ini
;
Input_File_Name=landscape.pov
Output_File_Type=N ; image format is png
Jitter=Off
Antialias=Off
Width=1920
Height=1080
Initial_Clock=0
Final_Clock=458
Initial_Frame=1
;
; Final_Frame = (Final_Clock - Initial_Clock) * FPS + Initial_Frame
; = 458 * 30 + 1 = 13741
;
Final_Frame=13741

Started with this .ini file, Povray would render the images landscape00001.png
till landscape13741.png. Now, to make rendering faster, we'd like to have
several instances of Povray rendering in parallel. This can be achieved by
applying the following scripts.

Windows
=======

The first script presented, builder.bat, runs on Windows. It should be placed in
the same folder as the .ini and .pov file and works like this:

1. The script searches the current folder for the image files landscape00001.png
till landscape13741.png.
2. When it detects that an image file does not exist, it starts an instance of
Povray to render that image file (only that file, none else).
3. When Povray finishes, the script looks for the next non-existing image file,
starts Povray to render it, and so forth.

To achieve parallel rendering, you simply start builder.bat several times. For
instance, when using Povray 3.6 on a machine with four CPU cores, you'd click
builder.bat four times. Or you could run several Povray instances on different
machines, working on the same folder shared through the network.

To prepare the script to your needs, you just have to define some variables at
its beginning:

----------------------------------------
@rem builder.bat
@rem
@rem Variables to be defined:
@rem povray  - The path of the Povray executable.
@rem povname - The name of the scene to render, without extension.
@rem digits  - The number of digits in the index of the image files.
@rem suffix  - The extension of the image files, eg. png.
@rem s       - Number of the initial frame.
@rem e       - Number of the final frame.
@rem
@rem Author: Burkhard Reike, 2011-10-26

@echo off
setLocal EnableDelayedExpansion

set povray="C:\Users\Burk\AppData\Roaming\POV-Ray\v3.6\bin\pvengine-sse2.exe"
set povname=landscape
set digits=5
set suffix=png
set s=1
set e=13741

echo Starting: %computername% %date% %time% >> render.log

for /L %%c in (%s%,1,%e%) do (
  set padcntr=0000000000%%c
  set filename=!povname!!padcntr:~-%digits%!
  if not exist !filename!.%suffix% (
    type NUL > !filename!.%suffix%
    call :GetTime
    set starttime=!cseconds!
    start /WAIT /min "Render" %povray% -d +SF%%c +EF%%c /exit +I %povname%.ini
    call :GetTime
    set endtime=!cseconds!
    if !endtime! LSS !starttime! set /a endtime+=8640000
    set /a elapsed=!endtime!-!starttime!
    set /a elapsed/=100
    echo !filename!.%suffix% !elapsed! %computername% >> render.log
  )
)

echo Finished: %computername% %date% %time% >> render.log
goto:eof

:GetTime
for /f "usebackq tokens=1-4 delims=:., " %%f in (`echo.%time%`) do (
  set temp=%%f %%g %%h %%i
)
for /f "usebackq tokens=1-4" %%f in (`echo %temp: 0= %`) do (
  set /a cseconds=%%f*360000+%%g*6000+%%h*100+%%i
)
----------------------------------------

Along with the image files, the script generates the file render.log with
information about the rendering process, eg. when the scripts were started,
finished, and how many seconds each image file took to render.
For each script instance started, a DOS shell window will open, and it starts
Povray instances one after another. Each time a Povray instance starts, you will
see a splash screen. This cannot be avoided. Still, the Povray window does not
pop up owing to the "-d" option.
If you want to stop rendering for a longer time, you just have to kill the dos
shell windows. Each currently running Povray instance will stay alive till it
has finished rendering the current frame.

If, for some reason, you have killed Povray instances, the images they had been
rendering will remain unfinished. Starting new instances of builder.bat will not
rerender them unless the files have been removed. To identify such image files,
the following script, broken_files.bat, comes in handy.
It prints the names of all image files which exist in the current folder but
which are not mentioned in the log file. Typically, those are broken image files
whose Povray instances were killed prematurely. broken_files.bat should be
placed in the same folder as the .ini, .pov, and builder.bat file.

----------------------------------------
@rem broken_files.bat
@rem
@rem Variables to be defined:
@rem suffix  - The extension of the image files, eg. png.
@rem
@rem Author: Burkhard Reike, 2011-10-26

@echo off
setlocal EnableDelayedExpansion

set suffix=png

for %%f in (*.%suffix%) do set allfiles=!allfiles! %%f
for /f "tokens=1 delims= " %%f in (render.log) do set logged=!logged! %%f
for %%g in (!allfiles!) do (
    set found=0
    for %%h in (!logged!) do if "%%g"=="%%h" set found=1
    if !found! EQU 0 echo %%g
)
pause
----------------------------------------

Linux (Ubuntu)
==============

There are several good reasons to use Linux for Povray rendering. Linux requires
few disk space, few RAM, and renting a Linux server is usually cheaper than
renting a Windows server since you don't have to pay for a license. The
following scripts were created for the Ubuntu 8.04 Linux distribution. The
scripts builder.sh and broken_files.sh are equivalent to the Windows scripts
described above. Additionally, the script add_render_process.sh will be
presented which can automatically mount a folder from a remote machine through
SSHFS such that you can start Povray instances on several machines, all
instances rendering into the same shared folder. All operations can be executed
from a login shell, you don't need a desktop environment like KDE or so.

For sharing a remote render folder, you need to have SSH/SFTP support installed
(most Linux distributions, even the minimal ones, come with it already
installed), and the SSH port of each machine used should be open such that
remote mounting can be applied. SSH is actually the only connection you will
need since it's also the connection of choice for remote login and file transfer
(eg. with the Windows programs PuTTY and WinSCP), since it's encrypted. Apart
from SSH/SFTP support, you should have the Screen tool installed. Screen will
enable you to logout from a machine without hanging up the render and mount
processes. You just have to execute Screen to open a new shell, start the
scripts, detach from Screen, and logout. Screen will stay alive, and so will the
sshfs and render processes started from it.
To install Screen in Ubuntu, type:
$ sudo apt-get install screen

Let's assume that you have a user account called "john" on each machine. Then
you should organize the render folders and scripts as follows.
On each machine, put the add_render_process.sh script into a certain folder, eg.
a folder inside your home directory called "povray":

/home/john/povray/add_render_process.sh

One machine, which we call master, must also contain the render folder. The
render folder contains the .ini, .pov, and remaining .sh files. Besides, it is
the folder into which the image files will be rendered:

/home/john/povray/render/builder.sh
/home/john/povray/render/broken_files.sh
/home/john/povray/render/landscape.ini
/home/john/povray/render/landscape.pov

All other machines, which we call clients, do not have a render folder
preinstalled. Instead, they will mount it from the master machine by the help of
the add_render_process.sh script.
For this purpose you will need to know the IP-address of the master machine. You
can find it out while logged in on the master machine with
$ ifconfig eth0
or
$ ifconfig eth1
depending on the hardware configuration. Inspect the output of the ifconfig
command. The number right of the "inet address:" entry is your IP-address.
Possibly you have two IPs, one public IP, and one private IP to be used for
inter-server communication. If so, you should pick the private IP of the master
machine.

So much for the setup. Now for starting the render processes.

You don't necessarily have to start render processes on the master machine since
its main purpose is to keep the render folder. But if you also want to use it
for rendering, proceed like this. First, login on the master machine (as "john")
and go to the povray folder. Then run Screen. Let's assume that each machine has
four cores, so run add_render_process.sh four times (with the render folder path
and the builder script name as arguments). By this, four builder.sh scripts will
be started, which again start Povray instances to render image files. Finally,
and detach from Screen. Then you can logout. The render processes will keep
running in the Screen shell:

$ cd povray
$ screen
$ ./add_render_process.sh /home/john/povray/render builder.sh
$ ./add_render_process.sh /home/john/povray/render builder.sh
$ ./add_render_process.sh /home/john/povray/render builder.sh
$ ./add_render_process.sh /home/john/povray/render builder.sh
[Now press "Ctrl+A" and then "D" to detach from Screen.]
$ logout

Now for starting render processes on the client machines. On each client
machine, you basically perform the same steps as on the master machine. The only
difference is that the calls of the add_render_process.sh will have two
additional arguments, namely the name of the user on the master machine who owns
the render folder, and the IP-address of the master machine. Let's say the
IP-address is 12.34.56.789. Then the commands to be executed on each client
machine look like this (again, let's assume we want to run four Povray instances
in parallel):

$ cd povray
$ screen
$ ./add_render_process.sh /home/john/povray/render builder.sh john 12.34.56.789
$ ./add_render_process.sh /home/john/povray/render builder.sh john 12.34.56.789
$ ./add_render_process.sh /home/john/povray/render builder.sh john 12.34.56.789
$ ./add_render_process.sh /home/john/povray/render builder.sh john 12.34.56.789
[Now press "Ctrl+A" and then "D" to detach from Screen.]
$ logout

The add_render_process.sh script will automatically install the SSHFS package,
add the user to the fuse group such that he can start remote connections, mount
the render folder and start the builder.sh script.
You will probaly be asked two times for passwords. The first time occurs when
the first "sudo" command in the add_render_process.sh script is executed. Then
you will have to enter the root password of the client machine. The second time
you will have to enter the password of user "john" on the master machine, in
order to establish the remote connection through sshfs. When connecting for the
first time to the master machine from the client machine, you'll also have to
confirm that you want to establish the connection.
Here are the scripts:

----------------------------------------
#!/bin/bash
# add_render_process.sh <full-path-of-render-directory> <name-of-renderscript>
#                       [<remote-user-name> <remote-host-address>]
#
# Author: Burkhard Reike, 2011-10-21

if [ $# -ne 2 -a $# -ne 4 ]; then
    echo "Usage: $0 <full-path-of-render-directory> <name-of-renderscript>"
    echo "       [<remote-user-name> <remote-host-address>]"
    exit 1
else
    RENDERDIR=$1
    if [ $RENDERDIR != */ ]; then
        RENDERDIR="$RENDERDIR"/
    fi
    RENDERSCRIPT=$2
    if [ $# -eq 4 ]; then
        USER=$3
        HOST=$4
        ISMASTER=false
    else
        USER=''
        HOST=''
        ISMASTER=true
    fi
fi

if [ -d "$RENDERDIR" -a -n "$(ls -A $RENDERDIR 2> /dev/null)" ]; then
    # Render directory already exists and is non-empty, so don't mount it.
    if [ !$ISMASTER ]; then
        echo "$0: Render directory seems already mounted. Mounting omitted."
    fi
else
    # Render directory doesn't exist or it's empty. Try to mount it.
    if [ !$ISMASTER ]; then
        if [ ! -d "$RENDERDIR" ]; then
            mkdir $RENDERDIR
        fi

        #
        # Mounting the render directory via sshfs
        #
        sudo chown `whoami`:`whoami` $RENDERDIR # Fix the render dir ownership
        sudo apt-get install sshfs # Install the sshfs package. This may have
                                   # to be adjusted, depending on your Linux
                                   # distribution.
        sudo modprobe fuse                      # Load the fuse module
        sudo adduser `whoami` fuse              # Add us to the fuser group
        sudo chown root:fuse /dev/fuse          # Fix /dev/fuse ownership
        sshfs -o ServerAliveInterval=15 $USER@$HOST:$RENDERDIR $RENDERDIR

        # Wait till the render directory is non-empty
        echo "$0: Waiting for content in the render directory..."
        until [ -d "$RENDERDIR" -a -n "$(ls -A $RENDERDIR 2> /dev/null)" ]; do
            sleep 2
        done
        echo "$0: Render directory was mounted sucessfully."

    else
        # The master process needs a non-empty render directory,
        # but could not find it.
        echo "$0: Could not find script $RENDERDIR$RENDERSCRIPT. Exiting."
        exit 1
    fi
fi

echo "$0: Starting background render script $RENDERDIR$RENDERSCRIPT"
cd $RENDERDIR
../$RENDERSCRIPT &>/dev/null &

----------------------------------------

#!/bin/bash
# builder.sh
#
# Variables to be defined:
# POVNAME - The name of the scene to render, without extension.
# DIGITS  - The number of digits in the index of the image files.
# SUFFIX  - The extension of the image files, eg. png.
# S       - Number of the initial frame.
# E       - Number of the final frame.
#
# Author: Burkhard Reike, 2011-10-21

echo "Starting: `hostname` `date`" >> render.log

POVNAME=landscape
DIGITS=5
SUFFIX=png
S=1
E=13741

while [ $S -le $E ]; do
    INDEX=`printf "%0"$DIGITS"d" ${S}`
    FILENAME=$POVNAME$INDEX.$SUFFIX
    if [ ! -f $FILENAME ]; then
        touch $FILENAME
        BEFORE="$(date +%s)"
        povray +SF$S +EF$S -d +I $POVNAME.ini &> /dev/null
        AFTER="$(date +%s)"
        ELAPSED="$(expr $AFTER - $BEFORE)"
        echo "$FILENAME $ELAPSED `hostname`" >> render.log
    fi
    S=$(($S+1))
done
echo "Finished: `hostname` `date`" >> render.log

----------------------------------------

#!/bin/bash
# broken_files.sh
#
# Author: Burkhard Reike, 2011-10-21

for F in *.png
do
    GREPOUTPUT="$(grep $F render.log)"
    if [ -z "$GREPOUTPUT" ]; then
        echo $F
    fi
done

----------------------------------------

That's it! I hope you will find all this useful.
For updates and other stuff, visit http://www.verklagekasper.de/video

Cheers,
Burkhard


Post a reply to this message

From: Mike the Elder
Subject: Re: Scripts for Parallel Rendering of Animations
Date: 27 Oct 2011 09:45:01
Message: <web.4ea96003f89e5a3f85627c70@news.povray.org>
"Verklagekasper" <mop### [at] verklagekasperde> wrote:
> Hi, I just wanted to share this.
>
....
> Cheers,
> Burkhard

Thanks! Although, since I am in the middle of moving (and am also a chronic
procrastinator), it will be a while before I can actually get around to making
use of this, I anticipate that it will come in quite handy indeed.

Best Regards,

Mike C.


Post a reply to this message

From: Dave
Subject: Re: Scripts for Parallel Rendering of Animations
Date: 27 Oct 2011 11:10:55
Message: <4ea9747f$1@news.povray.org>
On 10/27/2011 7:22 AM, Verklagekasper wrote:
>    if not exist !filename!.%suffix% (

Note that there is a race condition here both on a single 
multi-processor PC or when using multiple PC's referencing a network
shared folder. In practice you >will< wind up with two or more
PC/core's rendering the same image.

In the unix world, "mkdir" is typically used as a lock mechanism
to serialize this test since "mkdir" is serialized by the underlying
file system both on a single PC or on the PC upon which the folder is
shared:

lock() {
   while ! mkdir lock
   do
     sleep 1
   done
}
unlock() {
   rm -fr lock
}

This would be used:

lock
if [ ! -f $FILENAME ]
then
   touch $FILENAME
   unlock
   :
   :
else
   unlock
fi


I don't know enough windows bat syntax to translate the above to windows.


Post a reply to this message

From: Verklagekasper
Subject: Re: Scripts for Parallel Rendering of Animations
Date: 27 Oct 2011 11:55:02
Message: <web.4ea97e55f89e5a3fa72194e50@news.povray.org>
Dave <use### [at] iamdaveATglidefreecom> wrote:
> On 10/27/2011 7:22 AM, Verklagekasper wrote:
> >    if not exist !filename!.%suffix% (
>
> Note that there is a race condition here both on a single
> multi-processor PC or when using multiple PC's referencing a network
> shared folder. In practice you >will< wind up with two or more
> PC/core's rendering the same image.

For that reason, the first thing that the scripts - both on Windows and Linux -
do when they detect a non-existing file, is to create the file before starting
Povray. By this, the chance that two processes render the same image, is
considerably low. And even if it happens, it is not harmful. The resulting image
file will be ok.
However, I haven't rendered with more than 32 concurrent Povray instances so
far. With a lot more instances, more collisions may occur, affecting efficiency
negatively. So I will consider to build in better lock mechanisms.

Cheers,
Burkhard


Post a reply to this message

From: Verklagekasper
Subject: Re: Scripts for Parallel Rendering of Animations
Date: 28 Oct 2011 12:40:00
Message: <web.4eaad98df89e5a3fa72d194a0@news.povray.org>
Hi Dave,

I just figured out the equivalent of the locking mechanism in DOS. I thought it
was impossible, but then I found that the mkdir command provides feedback on its
succes through setting the "errorlevel" environment variable, which is local in
each DOS shell:

:lock
md lockdir
if errorlevel 1 (
   rem ping seems the only "sleep" command availabe on all Windows versions
   ping -n 2 127.0.0.1 >NUL
   goto lock
)
goto:eof

:unlock
rd lockdir
goto:eof

I tested it with Windows XP, Windows Vista, and Windows 7, and it works.

Here are the new versions of the builder scripts that include the lock mechanism
to prevent processes from rendering the same image file:

------------------------------------------
@rem builder.bat
@rem
@rem Variables to be defined:
@rem povray  - The path of the Povray executable.
@rem povname - The name of the scene to render, without extension.
@rem digits  - The number of digits in the index of the image files.
@rem suffix  - The extension of the image files, eg. png.
@rem s       - Number of the initial frame.
@rem e       - Number of the final frame.
@rem
@rem Author: Burkhard Reike, 2011-10-28

@echo off
setLocal EnableDelayedExpansion

set
povray="C:\Users\Burkhard\AppData\Roaming\POV-Ray\v3.6\bin\pvengine-sse2.exe"
set povname=landscape
set digits=5
set suffix=png
set s=1
set e=13741

echo Starting: %computername% %date% %time% >> render.log
set lockdir=%povname%.lck
for /L %%c in (%s%,1,%e%) do (
  set padcntr=0000000000%%c
  set filename=!povname!!padcntr:~-%digits%!
  call :Lock
  if not exist !filename!.%suffix% (
    type NUL > !filename!.%suffix%
    call :Unlock
    call :GetTime
    set starttime=!cseconds!
    start /WAIT /min "Render" %povray% -d +SF%%c +EF%%c /exit +I %povname%.ini
    call :GetTime
    set endtime=!cseconds!
    if !endtime! LSS !starttime! set /a endtime+=8640000
    set /a elapsed=!endtime!-!starttime!
    set /a elapsed/=100
    echo !filename!.%suffix% !elapsed! %computername% >> render.log
  ) else (
    call :Unlock
  )
)

echo Finished: %computername% %date% %time% >> render.log
goto:eof

:GetTime
for /f "usebackq tokens=1-4 delims=:., " %%f in (`echo.%time%`) do (
  set temp=%%f %%g %%h %%i
)
for /f "usebackq tokens=1-4" %%f in (`echo %temp: 0= %`) do (
  set /a cseconds=%%f*360000+%%g*6000+%%h*100+%%i
)
goto:eof

:Lock
md %lockdir%
if errorlevel 1 (
   rem ping seems the only "sleep" command availabe on all Windows versions
   ping -n 2 127.0.0.1 >NUL
   goto Lock
)
goto:eof

:Unlock
rd %lockdir%
goto:eof

------------------------------------------
#!/bin/bash
# builder.sh
#
# Variables to be defined:
# POVNAME - The name of the scene to render, without extension.
# DIGITS  - The number of digits in the index of the image files.
# SUFFIX  - The extension of the image files, eg. png.
# S       - Number of the initial frame.
# E       - Number of the final frame.
#
# Author: Burkhard Reike, 2011-10-28

echo "Starting: `hostname` `date`" >> render.log

POVNAME=landscape
DIGITS=5
SUFFIX=png
S=1
E=13741

LOCKDIR=$POVNAME.lck
lock() {
   while ! mkdir $LOCKDIR
   do
     sleep 1
   done
}
unlock() {
   rm -fr $LOCKDIR
}

while [ $S -le $E ]; do
    INDEX=`printf "%0"$DIGITS"d" ${S}`
    FILENAME=$POVNAME$INDEX.$SUFFIX
    lock
    if [ ! -f $FILENAME ]; then
        touch $FILENAME
        unlock
        BEFORE="$(date +%s)"
        povray +SF$S +EF$S -d +I $POVNAME.ini &> /dev/null
        AFTER="$(date +%s)"
        ELAPSED="$(expr $AFTER - $BEFORE)"
        echo "$FILENAME $ELAPSED `hostname`" >> render.log
    else
        unlock
    fi
    S=$(($S+1))
done
echo "Finished: `hostname` `date`" >> render.log
------------------------------------------

Cheers,
Burkhard


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.