Memory Shadeop

These are some notes about a useful DSO shadeop for determining what PRMan is doing with memory allocation. It was developed specifically to analyse a problem with excessive memory consumption of DynamicLoad procedurals. The platform used was Linux IA32 - although the concepts should transfer to other platforms.

The simplest way to look at the memory usage of a render is to watch the output from top, keeping an eye on the RSS (resident set size) of prman. There are two problems with this: first, RSS is not as tightly connected to allocated memory as you would like, and second, there is no correlation between the values and the part of the image being rendered.

I wanted to be able to visualise the exact memory consumption over the image. The malloc library has a statistics function mallinfo that will return the amount of memory that malloc has allocated including a small amount of housekeeping data. The idea was to place a semi-transparent surface just in front of the camera shaded with these statistics. Clearly this extra geometry will have an effect on the memory used, but this can be ignored since we are interested in patterns not absolute values.

Shadeop

Return a float containing the number of megabytes allocated. The mallinfo structure contains two byte totals that need to be summed (for more details see /usr/include/malloc.h).

#include "shadeop.h"

#include <malloc.h>

 

SHADEOP_TABLE(hal_memory_allocated) =

{

{ "float hal_memory_allocated ()", "", "" },

{ "" }

};

 

SHADEOP(hal_memory_allocated)

{

struct mallinfo mi=mallinfo();

 

((float *)argv[0])[0]=(mi.hblkhd+mi.uordblks)/1024.0F/1024.0F;

 

return(0);

}

Compile with:

cc -I${RMANTREE}/include -c hal_memory_allocated.c

ld -shared hal_memory_allocated.o -o hal_shadeops.so

Shader

This is a very simple shader which just converts the memory consumption to a red-to-green scale with 200M being the default upper scale. This could be easily extended to colour spectrums etc.

surface memory_debug(float maximum = 200)

{

uniform float m = hal_memory_allocated() / maximum;

 

Ci = color(1-m, m, 0);

Oi = color(1, 1, 0);

}

Obviously, it is important to be at least partially transparent so that the geometry that you are testing is actually rendered through the surface, and you can see how it lines up with the statistics.

Results

PRMan 11.1

PRMan 11.3

The following image is the result of a scene of procedural people rendered with PRMan 11.1 (sorry, the original images are part of a production, so I had to blur them).

Here the memory seems to constantly increase - none of the data associated with each procedural is being freed until the end of the frame. This shows graphically the problem I was trying to track down. When I tried again with the latest PRMan 11.3 release, the results changed.

Here the memory consumption is much lower and does not accumulate. It also appears to be proportional to the amount of geometry at each bucket scan line. Clearly there was a memory freeing problem that has been fixed in the latest release. Anyone planning to use procedural geometry should be sure to use 11.3 or later.