#! /usr/bin/perl

use strict;
use warnings;
use POSIX qw/strftime floor/;

my %groups = (
	'inet_peer_cache'	=> 'net',
	'skbuff_head_cache'	=> 'net',
	'xfrm6_tunnel_spi'	=> 'net/ipsec',
	'xfrm_dst_cache'	=> 'net/ipsec',
	'secpath_cache'		=> 'net/ipsec',
	'ndisc_cache'		=> 'net/neigh',
	'arp_cache'		=> 'net/neigh',
	'ipt_hashlimit'		=> 'net/netfilter',
	'ip_conntrack_expect'	=> 'net/netfilter',
	'ip_conntrack'		=> 'net/netfilter',
	'ip_fib_alias'		=> 'net/route',
	'ip_fib_hash'		=> 'net/route',
	'fib6_nodes'		=> 'net/route',
	'ip6_dst_cache'		=> 'net/route',
	'ip_dst_cache'		=> 'net/route',
	'ip_mrt_cache'		=> 'net/route',
	'rpc_buffers'		=> 'net/rpc',
	'rpc_tasks'		=> 'net/rpc',
	'rpc_inode_cache'	=> 'net/rpc',
	'RAWv6'			=> 'net/sock',
	'UDPv6'			=> 'net/sock',
	'TCPv6'			=> 'net/sock',
	'UNIX'			=> 'net/sock',
	'RAW'			=> 'net/sock',
	'UDP'			=> 'net/sock',
	'TCP'			=> 'net/sock',
	'tcp_tw_bucket'		=> 'net/tcp',
	'tcp_bind_bucket'	=> 'net/tcp',
	'tcp_open_request'	=> 'net/tcp',
	'sysfs_dir_cache'	=> 'fs',
	'mnt_cache'		=> 'fs',
	'dentry_cache'		=> 'fs',
	'fat_cache'		=> 'fs',
	'journal_handle'	=> 'fs',
	'journal_head'		=> 'fs',
	'revoke_table'		=> '',
	'revoke_record'		=> '',
	'ext3_xattr'		=> 'fs',
	'dnotify_cache'		=> 'fs',
	'fs_cache'		=> 'fs',
	'files_cache'		=> 'fs',
	'file_lock_cache'	=> 'fs',
	'ext2_inode_cache'	=> 'fs/inode',
	'fat_inode_cache'	=> 'fs/inode',
	'ext3_inode_cache'	=> 'fs/inode',
	'isofs_inode_cache'	=> 'fs/inode',
	'sock_inode_cache'	=> 'fs/inode',
	'proc_inode_cache'	=> 'fs/inode',
	'inode_cache'		=> 'fs/inode',
	'nfs_write_data'	=> 'fs/nfs',
	'nfs_read_data'		=> 'fs/nfs',
	'nfs_inode_cache'	=> 'fs/nfs',
	'nfs_page'		=> 'fs/nfs',
	'bridge_fdb_cache'	=> '',
	'flow_cache'		=> '',
	'i2o_block_req'		=> '',
	'uhci_urb_priv'		=> '',
	'cfq_ioc_pool'		=> '',
	'cfq_pool'		=> '',
	'crq_pool'		=> '',
	'deadline_drq'		=> '',
	'as_arq'		=> '',
	'mqueue_inode_cache'	=> '',
	'udf_inode_cache'	=> '',
	'eventpoll_pwq'		=> '',
	'eventpoll_epi'		=> '',
	'kioctx'		=> '',
	'kiocb'			=> '',
	'fasync_cache'		=> '',
	'shmem_inode_cache'	=> '',
	'posix_timers_cache'	=> '',
	'uid_cache'		=> '',
	'sgpool-XXX'		=> '',
	'blkdev_ioc'		=> 'dev',
	'blkdev_queue'		=> 'dev',
	'blkdev_requests'	=> 'dev',
	'biovec-XXX'		=> 'dev',
	'bio'			=> 'dev',
	'bdev_cache'		=> '',
	'filp'			=> '',
	'names_cache'		=> '',
	'avc_node'		=> '',
	'idr_layer_cache'	=> '',
	'buffer_head'		=> '',
	'anon_vma'		=> '',
	'pgd'			=> '',
	'task_struct'		=> 'core',
	'mm_struct'		=> 'core/mm',
	'vm_area_struct'	=> 'core/mm',
	'kmem_cache'		=> 'core/mm',
	'signal_cache'		=> 'core/signal',
	'sighand_cache'		=> 'core/signal',
	'sigqueue'		=> 'core/signal',
	'radix_tree_node'	=> 'core/misc',
	'size-XXX'		=> 'generic',
	'size-XXX(DMA)'		=> 'generic/dma',
);

open(SLABINFO, '<', '/proc/slabinfo')
	or die "Can't open /proc/slabinfo for reading";

print "GROUP_DEF slab \"Slab\" \"Num\" \"Active\" \"-\" \"-\"\n";

while (1) {

	seek(SLABINFO, 0, 0);

	print "UPDATE", " ", strftime("%Y-%m-%d %H:%M:%S", localtime), "\n";
	print "NODE <local>\n";
	print "GROUP slab\n";

	while (<SLABINFO>) {
		chomp;
		next if /^slabinfo.+$/;
		next if /^#.*$/;

		my ($name, $active_objs, $num_objs, $objsize, $objsperslab,
		    $pagesperslab, $limit, $batchcount, $sharedfactor,
		    $active_slabs, $num_slabs, $shared_avail, $listallocs,
		    $maxobjs, $grown, $reaped, $error, $maxfreeable, $freelimit,
		    $nodeallocs, $allochit, $allocmiss, $freehit, $freemiss)
		    = m/^([^\s]+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s:\s
		        tunables\s+(\d+)\s+(\d+)\s+(\d+)\s:\s
			slabdata\s+(\d+)\s+(\d+)\s+(\d+)\s:\s
			globalstat\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+
			(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s:\s
			cpustat\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/x;

		print "ITEM ", $name, " 0 <none> 0 slab_num_objs slab_active_objs slab_usage\n";
		print "ATTR slab_num_objs $num_objs 0\n";
		print "ATTR slab_active_objs $active_slabs 0\n";
		print "ATTR slab_nodeallocs $nodeallocs 0\n";
		print "ATTR slab_allochit $allochit 0\n";
		print "ATTR slab_allocmiss $allocmiss 0\n";
		print "ATTR slab_freehit $freehit 0\n";
		print "ATTR slab_freemiss $freemiss 0\n";

		if ($num_objs != 0) {
			my $rx_usage = ($active_slabs / $num_objs) * 100;
			print "ATTR slab_usage ",  floor($rx_usage),  " 0\n";
		}

		print "END_ITEM\n";
	}

	print "END_GROUP\n";
	print "END_NODE\n";
	print "END_UPDATE\n";

	sleep(5);
}

close(SLABINFO)
