blender/release/io/netrender/slave.py
Martin Poirier afee963155 First commit draft for network rendering.
Docs are here: http://wiki.blender.org/index.php/User:Theeth/netrender

Should be easy to test if people want too, just follow the instructions on wiki

Code is still very much in flux, so I'd like if people would refrain from making changes (send patches directly to me if you must).

The UI side is very crap, it's basically there just to get things testable. See wiki for known bugs.
2009-08-29 17:25:22 +00:00

148 lines
4.1 KiB
Python

import sys, os
import http, http.client, http.server, urllib
import subprocess, time
from netrender.utils import *
import netrender.model
CANCEL_POLL_SPEED = 2
MAX_TIMEOUT = 10
INCREMENT_TIMEOUT = 1
def slave_Info():
sysname, nodename, release, version, machine = os.uname()
return (nodename, sysname + " " + release + " " + machine)
def testCancel(conn, job_id):
conn.request("HEAD", "status", headers={"job-id":job_id})
response = conn.getresponse()
# cancelled if job isn't found anymore
if response.status == http.client.NOT_FOUND:
return True
else:
return False
def render_slave(engine, scene):
NODE_PREFIX = PATH_PREFIX + "node" + os.sep
timeout = 1
if not os.path.exists(NODE_PREFIX):
os.mkdir(NODE_PREFIX)
engine.update_stats("", "Network render node initiation")
conn = clientConnection(scene)
if conn:
conn.request("POST", "slave", repr(slave_Info()))
response = conn.getresponse()
slave_id = response.getheader("slave-id")
while not engine.test_break():
conn.request("GET", "job", headers={"slave-id":slave_id})
response = conn.getresponse()
if response.status == http.client.OK:
timeout = 1 # reset timeout on new job
job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8')))
print("File:", job.path)
engine.update_stats("", "Render File", job.path, "for job", job.id)
if os.path.isabs(job.path):
# if an absolute path, make sure path exists, if it doesn't, use relative local path
job_full_path = job.path
if not os.path.exists(job_full_path):
job_full_path = NODE_PREFIX + job.id + ".blend"
else:
job_full_path = NODE_PREFIX + job.path
if not os.path.exists(job_full_path):
conn.request("GET", "file", headers={"job-id": job.id, "slave-id":slave_id})
response = conn.getresponse()
if response.status != http.client.OK:
break # file for job not returned by server, need to return an error code to server
f = open(job_full_path, "wb")
buf = response.read(1024)
while buf:
f.write(buf)
buf = response.read(1024)
f.close()
frame_args = []
for frame in job.frames:
frame_args += ["-f", str(frame.number)]
start_t = time.time()
process = subprocess.Popen([sys.argv[0], "-b", job_full_path, "-o", NODE_PREFIX + job.id, "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
cancelled = False
stdout = bytes()
run_t = time.time()
while process.poll() == None and not cancelled:
stdout += process.stdout.read(32)
current_t = time.time()
cancelled = engine.test_break()
if current_t - run_t > CANCEL_POLL_SPEED:
if testCancel(conn, job.id):
cancelled = True
else:
run_t = current_t
if cancelled:
continue # to next frame
total_t = time.time() - start_t
avg_t = total_t / len(job.frames)
status = process.returncode
print("status", status)
headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)}
if status == 0: # non zero status is error
headers["job-result"] = str(DONE)
for frame in job.frames:
headers["job-frame"] = str(frame.number)
# send result back to server
f = open(NODE_PREFIX + job.id + "%04d" % frame.number + ".exr", 'rb')
conn.request("PUT", "render", f, headers=headers)
f.close()
response = conn.getresponse()
else:
headers["job-result"] = str(ERROR)
for frame in job.frames:
headers["job-frame"] = str(frame.number)
# send error result back to server
conn.request("PUT", "render", headers=headers)
response = conn.getresponse()
for frame in job.frames:
headers["job-frame"] = str(frame.number)
# send log in any case
conn.request("PUT", "log", stdout, headers=headers)
response = conn.getresponse()
else:
if timeout < MAX_TIMEOUT:
timeout += INCREMENT_TIMEOUT
for i in range(timeout):
time.sleep(1)
if engine.test_break():
conn.close()
return
conn.close()