Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

TLDR: the number of particles used, and the memory required was far too big to fit on one machine. more over, machines needed to pass data to each other, they chose to use files for that.

Long story:

Forgive me if you already know this, I'm going to start with a toy example and then ramp up the scale.

Imagine that you are doing a "normal" simulation of something like a ball rolling down a ramp into a pot. That's fairly simple, but you need to know the position of the ball, the force vector and the location of any object near by that might collide with it.

It gets a bit harder when there are two balls, as they might also interact, so you need to store the state of two balls.

At a thousand balls, you start to need to think about scaling/threading/parralising (I mean you probably don't, you'd just use physX from nvidia and make it the library's problem, but bear with me) One way is to divide up the simulation area into a bunch of voxels and treat them as individual processing areas. When an object enters/exits an simulation area, you pass the object over with its force vector, and mass, and let that simulator deal with it.

Now, I'm not a physics engine person. The above may or may not happen as I describe, but the key thing is, there are sub simulation to allow you to run in parallel. You need to make sure that each processing voxel has completed it's processing for that time step before you can move on.

Once you have calcuated the position of each object, you can save that to disk and begin to calculate the next frame. Note, this isn't rendering, this is just working out the "pose" (position and rotation) of each active object.

The simulation of the black hole was effectively a massive particle simulation. I don't recall how many particles, but something like 14 billion sticks in my mind. It might have only been a billion. So they need to calculate and store the id, position, rotation, velocity and probably other details for every single particle. Even if everything is in a single float for a billion particles, its 28 gigabytes for position and rotation alone (xyz for position, quaternion for rotation) That's without any other state info like heat, force vectors, the weird quantum stuff or weight.

Once you have the position of all the particles, you then need to fire photons through them to work out what colour the pixel should be. That involves loading in the position of the particles, firing rays through them all and recording what it hits and why.

But why so much file IO? didn't the machines talk directly?

DNEG at the time was as close to being a "perfect" unix/linux shop as you could get. everything was ephemeral, even the file servers. All the nodes in the render farm could configure themselves from scratch (pretty much) from power on. You'd plug it in, switch it on and it would work out what it's hostname is, image themselves and join the rendering system autonomously. Most binaries that you used were stored on an NFS share somewhere. this meant that you had more or less complete control over the data flow. For example `rm` wasn't actually rm, it was a wrapper that moved files into a 'deleted' area, rather than binning them.

There were many layers of backup, all the way to tape.

Your home directory followed you everywhere, which meant so did your environment. This meant that if you wanted a specific version of a program, we had a wrapper that set that for you. So typing "maya" would spin up the right version of maya, use the correct plugins, and safe your files to the correct fileserver.

Everything was divided into shows. so you'd cd /shows/$showname/$department/$shotnumber/$version and you'd magically be on the right fileserver. This was done via the magic of symlinks.

So everything was files, and if you wanted to exchange large amounts of data, you'd use files.

If anyone is interested I'll talk about the system they used to coordinate all the rendering (no it wasn't k8s)



If anyone is interested I'll talk about the system they used to coordinate all the rendering (no it wasn't k8s)

most certainly, please share. and thank you, this is very interesting.


stretches fingers

So, the "farm" (the name given to all the machines that render everything) had 36k CPUs. I can't remember what the specs of the machines were but I think they were either 8 or ten core CPUs. Most of them were blade units, because that was the densest way to fit in that many CPUs into that sized space (The farm lived in the basement and consumed something like half a megawatt, I can't remember if that included aircon or not.)

Now, each machine on the farm was split into slots. From memory, the biggest slot was 8 cores, but you could request less.

THe farm ran "jobs" which were lots of commands strung together into a "direct acyclical graph" (DAG) for short. A node in the job could be as simple as "cd /show && mkdir dave/" or it could be a render. EAch stage in the job could have a dependency, either on a physical property, like amount of ram, or machine class (some CPUs were newer than others) a license to run renderman (a renderer from pixar) or some other expensive bit of software. It could also be dependent on a previous stage completing (so frame 44 can't render before frame 20 because it needs to reference something that frame 20 generates.)

All these commands are parcelled up into a single lump, using a "job description language" and sent to the scheduler.

Its the scheduler that works out where and when to place a command, on which machine. Now, the system that they used at the time was called alfred. The thing you need to know about alfred is that it's interface was written in something that looks like the athena widget set: http://appartager.free.fr/renderman/prman%2012.5/programming...

Alfred is old, as in, Single threaded, older than SSH old. The man page dates from 1995, and I suspect that its probably older still by a good 5 years.

However, despite being old, its still fast. It can dispatch jobs way quicker than k8s, even on an old shitty machine. But, we were pushing it a bit. I think we were sending something like 30k commands an hour through the thing. (ie, telling a machine to run a command, store the logs, capture the return code, pre-empt, reap, all that kinda jazz). We did have to run it on an overclocked workstation, as the main VM cluster wasn't quite fast enough in single threaded performance to keep up with demand.

WE had something like 800 artists in the building, all using the quaint athena interface.

There was a cgroups wrapper that was written to make sure that people couldn't take more ram than was allotted. We over subscribed CPU by something like 10-20%. If you went over your ram allocation, you'd get OOM'd. swapping ram between processes is expensive, swapping CPU is pretty much free (its not, but the penalty for running at 110% CPU is way less than paying the electricity for having more machines and undersubscribing.)

So why not K8s?

I'm sure some people do use it. But its not practical for batch processing like this for a number of reasons:

1) scaling past 500 nodes means that you loose a lot of network to message passing and state transfer

2) the scheduler isn't designed to have complex dependency trees (by default you can have a sidecar and thats about it really. You can create a service, but thats not really designed for ephemeral tasks)

3) the networking is batshit. (virtual networking is really not great for low latency high throughput stuff like NFS or some other file protocol)

What can you use?

If you're on AWS, Batch is good enough. Its not as fast, but it'll do. You'll need to write an interface to make complex job graphs though.

Azure has a batch interface as well.

https://www.opencue.io/ is what a lot of people use. And some people use https://renderman.pixar.com/tractor




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: