Zram monitoring

Using Openhab to monitor and control the technical aspects of your home is a good idea. Monitoring Openhab system’s health is also a good idea.

I use the system binding to monitor the CPU temperature, load, memory and heap size on my small Raspberry pi 3B+. It comes at a cost: you need to define items and ideally also some charts. And you have to interpret the figures yourself.

There is a new ‘The Doctor Binding’ from @matt1, that has another approach. It gives you a warning in the log if something is getting wrong. Easier to use as it tells you if something is good or bad and why.

In the topic, @mstormi suggested to add some monitoring for zram. This would be a good idea.

Meanwhile you can check the zram status with the command

zramctl --output-all

Here is what I see:

NAME       DISKSIZE   DATA COMPR ALGORITHM STREAMS ZERO-PAGES TOTAL MEM-LIMIT MEM-USED MIGRATED MOUNTPOINT
/dev/zram2      75M  43.4M  6.3M zstd            4       5758  7.2M       25M     7.3M       0B /opt/zram/zram2
/dev/zram1     150M 105.8M 14.8M lzo-rle         4       1475 16.2M       50M    16.2M       0B /opt/zram/zram1
/dev/zram0     375M  73.9M 30.8M lzo-rle         4        368 35.8M      150M    62.8M     3.4K [SWAP]

The result is hard to evaluate.

Two ratio’s seem important:

DATA / DISKSIZE: uncompressed used data vs. uncompressed limit
MEM-USED / MEM-LIMIT: compressed data vs. compressed limit

These two ratio’s should remain smaller than one.

I wrote a rule with a javascript script that calculates these ratio’s. I let it execute every hour. To use it, I first defined 6 items:

zram0Compressed and zram0UnCompressed: swap
zram1Compressed and zram1UnCompressed: persistence files
zram2Compressed and zram2UnCompressed: log

Script code:

// zramctlRead
// Read zram memory settings with zramctl

// execute zramctl
command = 'zramctl --output NAME,DISKSIZE,DATA,MEM-LIMIT,MEM-USED';
result = actions.Exec.executeCommandLine(time.Duration.ofSeconds(5),'/bin/sh', '-c',command).trim();

// split in lines with regex
lines = result.split(/\r?\n/);

// are there any lines with values?
if (lines.length > 1){
  // process lines with values
  for (i=1; i < lines.length; i++){
    result = processLine(lines[i]);
  } 
}

function processLine(line){
  values = line.split(/[ ]+/);
  
  name = values[0];  
  diskSize = convertToBytes(values[1]);
  data = convertToBytes(values[2]);
  memLimit = convertToBytes(values[3]);
  memUsed = convertToBytes(values[4]);
    
  // index = last character of name
  index = name.slice(-1);
  
  // calculate and post ratio's
  items.getItem('zram' + index + 'UnCompressed').postUpdate((data / diskSize).toFixed(2));
  // mem_limit is an optional setting in /etc/ztab; setting it to 0 disables it.
  if ( memLimit > 0) {
    items.getItem('zram' + index + 'Compressed').postUpdate((memUsed / memLimit).toFixed(2));     
  }  
}

function convertToBytes(value){
  // split value in number and unit
  unit = value.slice(-1);
  number = value.slice(0,value.length - 1);

  // calculate number of bytes
  switch(unit){
    case 'B':
      bytes = number;
      break;
    case 'K':
      bytes = number * 1024;
      break;
    case 'M':
      bytes = number * 1024 * 1024;
      break;
    case 'G':
      bytes = number * 1024 * 1024 * 1024;
      break;      
  }
  return bytes;  
}

You can see the evolution in a chart:

You could also define limits for the ratio’s, although I am not sure where to set safe limits: 0.5, 0.75, …? Something for The Doctor? :wink:

Edit:

  • Corrected an error: switched compressed and uncompressed in the script
  • According to the zram-config documentation here mem_limit is an optional setting. It can be disabled by setting it to 0. In this case you don’t need to define the zram?Compressed items.
4 Likes