smapsum.c
author viric@llimona
Fri, 23 Feb 2007 23:54:45 +0100
changeset 0 5425a5439bcd
permissions -rw-r--r--
Unua versio.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

static char showtitle = 1;

struct Filemap
{
	char name[300];
	int size;
	int rss;
	int shared_clean;
	int shared_dirty;
	int private_clean;
	int private_dirty;
	enum {
		PRIVATE,
		SHARED
	} type;
	char readable;
	char writable;
	char executable;
	int inode;
	struct {
		unsigned char major;
		unsigned char minor;
	} device;
};

struct Totals
{
	int size;
	int rss;
	int shared_clean;
	int shared_dirty;
	int private_clean;
	int private_dirty;
	char cmd[200];
};


static int readkb(const char *field, FILE *stream)
{
	int kb;
	int res;
	char line[200];

	strcpy(line, field);
	strcat(line, " %i kB\n");
	res = fscanf(stream, line, &kb);
	if (res != 1)
		return -1;
	return kb;
}

static int readsize(FILE *stream)
{
	return readkb("Size:", stream);
}

static int readrss(FILE *stream)
{
	return readkb("Rss:", stream);
}

static int readshared_clean(FILE *stream)
{
	return readkb("Shared_Clean:", stream);
}

static int readshared_dirty(FILE *stream)
{
	return readkb("Shared_Dirty:", stream);
}

static int readprivate_clean(FILE *stream)
{
	return readkb("Private_Clean:", stream);
}

static int readprivate_dirty(FILE *stream)
{
	return readkb("Private_Dirty:", stream);
}

static int readfilemap(FILE *stream, struct Filemap *map)
{
	int res;
	char type;

	unsigned int major;
	unsigned int minor;

	res = fscanf(stream, "%*x-%*x %c%c%c%c %*x %x:%x %i",
			&map->readable,
			&map->writable,
			&map->executable,
			&type,
			&major,
			&minor,
			&map->inode);

	if (res != 7)
		return -1;

	fgets(map->name, 300, stream);

	map->device.major = major;
	map->device.minor = minor;

	if (type == 's')
		map->type = PRIVATE;
	else
		map->type = SHARED;

	if (map->readable == '-')
		map->readable = 0;
	if (map->writable == '-')
		map->writable = 0;
	if (map->executable == '-')
		map->executable = 0;

	map->size = readsize(stream);
	if (map->size == -1)
		return -2;
	map->rss = readrss(stream);
	if (map->rss == -1)
		return -2;
	map->shared_clean = readshared_clean(stream);
	if (map->shared_clean == -1)
		return -2;
	map->shared_dirty = readshared_dirty(stream);
	if (map->shared_dirty == -1)
		return -2;
	map->private_clean = readprivate_clean(stream);
	if (map->private_clean == -1)
		return -2;
	map->private_dirty = readprivate_dirty(stream);
	if (map->private_dirty == -1)
		return -2;

	return 0;
}

static int readsmap(const int pid, struct Totals *totals)
{
	FILE *stream;
	char filename[100];

	snprintf(filename, 100, "/proc/%i/smaps", pid);

	stream = fopen(filename, "r");

	if (stream == 0)
		return -1;

	totals->size = 0;
	totals->rss = 0;
	totals->shared_clean = 0;
	totals->shared_dirty = 0;
	totals->private_clean = 0;
	totals->private_dirty = 0;

	while(!feof(stream))
	{
		struct Filemap map;
		int res;
		res = readfilemap(stream, &map);
		if (res == -1)
			break;
		if (res == -2)
		{
			fprintf(stderr, "ERROR READING %s\n", filename);
			break;
		}
		/*printf("Map: %s\n", map.name);*/
		totals->size = totals->size + map.size;
		totals->rss = totals->rss + map.rss;
		totals->shared_clean = totals->shared_clean + map.shared_clean;
		totals->shared_dirty = totals->shared_dirty + map.shared_dirty;
		totals->private_clean = totals->private_clean
			+ map.private_clean;
		totals->private_dirty = totals->private_dirty
			+ map.private_dirty;
	}

	fclose(stream);

	/* Read the cmd */
	totals->cmd[0] = '\0';
	snprintf(filename, 100, "/proc/%i/cmdline", pid);
	stream = fopen(filename, "r");
	fgets(totals->cmd, 200, stream);
	fclose(stream);

	return 0;
}

static void showtotals(const int pid, const struct Totals *totals)
{
	if (showtitle)
		printf("PID\tSIZE\tRSS\tS_CLN\tS_DTY\tP_CLN\tP_DTY\tCMD\n");
	printf("%i\t%i\t%i\t%i\t%i\t%i\t%i\t%s\n",
			pid,
			totals->size,
			totals->rss,
			totals->shared_clean,
			totals->shared_dirty,
			totals->private_clean,
			totals->private_dirty,
			totals->cmd);
}

static void showhelp(const char *progname)
{
	fprintf(stderr,"usage: %s <pid>\n", progname);
}

int main(int argc, char *argv[])
{
	int pid;
	struct Totals t;
	int res;

	if (argc < 2)
	{
		showhelp(argv[0]);
		return 1;
	}

	if (argc == 2)
		pid = atoi(argv[1]);
	else
	{
		if (argv[1][1] == 'q')
			showtitle = 0;
		pid = atoi(argv[2]);
	}

	res = readsmap(pid, &t);

	if (res == -1)
		return -1;

	showtotals(pid, &t);

	return 0;
}