The following tests have been executed on the ARM based TISDP2420 reference board.

The Y-axis on the graphs shows the memory consumption measured in 4-kilobytes pages.

The measurement is done with the kernel patch implementing /dev/kp0 device (the same results can be obtained by sysctl -n machdep.kmpages).

Contents

  1. Fork, kill and fork again
    1. The blue curve marked 'fork'
    2. The red line marked 'fork-and-kill'
  2. Writing files
  3. Reading data from the network
  4. Allocating memory
  5. Comparison of je-malloc with phk-malloc

Fork, kill and fork again

Image:Fork.png

Start up to 40 new processes (all the children are doing nothing, just sleeping and waiting for the KILL signal), after that reduce the children amount to zero, and grow it again repeating the same measurement a few times.

The x-axis represents the process counter i (see the following pseudo code).

The blue curve marked 'fork'

for i in (0,1,2,...,39,40,39,...,2,1,0,1,2,...,40,...,0,...,40,...,1,0)
{
  if i > previous value of i:
    start a new child by calling fork() [the child process does infinite sleep()] ;
  else: /* i less than previous value of i */
    kill the last started child and rip it ;
  Remember page counter value ;
}
for i in (1,2,3,4,5)
{
  allocate all the memory in the system (see below);
  Remember page counter value and mark the first and the last with "!" ;
}

The "allocate all the memory" step above is performed as follows. A new child consuming memory in a infinite loop is starting. After the system is running out of memoty, this child is killed by the kernel, thus all the memory allocated by it is freed.

The red line marked 'fork-and-kill'

for i in (the same list as above)
{
  Kill and rip ALL the children (if any exist) ;
  Start i new children by calling fork() and sleep() ;
  Remember page counter value ;
}
Allocate all the memory five times (as above)

Writing files

Image:Write.png

Open up to 40 files (the green curve represents temporary files on tmpfs, the red one is the same for nfs, the blue curve represents writing to /dev/null) and write some data to them:

for i in (0..40..0..40..0..40..0)
{
  if i > previous value of i:
    open a new file ;
    unlink the opened file unless writing media is NOT /dev/null ;
  else: /* i<previous value of i */
    close the last opened connection (FILO) ;
  Write forty kilobytes to every opened file ;
  Remember page counter value ;
}
Allocate all the memory five times (as test №1 above)

Reading data from the network

Image:Network.png

Open connections to the server on remote host and read some data from them:

for i in (0..40..0..40..0..40..0)
{
  if i > previous value of i:
    open a new connection ;
  else (i<previous value of i):
    close a last opened connection (FILO) ;
  Read forty kilobytes from every opened connection ;
  Remember page counter value ;
}
Allocate all the memory five times (as test №1 above)

Allocating memory

Image:Alloc.png

Allocate (using malloc) memory pieces of B bytes (four curves for different values of B: 300=red, 3000=blue, 30000=magenta, 300000=green) until the total amount of allocated memory exceeds the boundary of 36 megabytes. After that free() all the pieces in reverse order (LIFO). Repeat the procedure three times. After every malloc()/free() call, calculate the amount of allocated memory in megabytes (B×#(pieces) divided by 1024²) and if that value is changed, perform a memory measurement. At the end allocate the whole memory and query the kernel page counter (five times, as usual).

Comparison of je-malloc with phk-malloc

Image:Phk.png

Make the same test as №4 above (with 24 Mb boundary instead of 36 Mb) for two different memory allocators. The default je-malloc (red curves) and the old phk-malloc (blue curves). No usual total consumption at the end of test.