OOM Killer user application

From: Mauricio Lin
Date: Mon Jan 10 2005 - 17:16:53 EST


Hi all,

Here goes the OOM application:

/* 2005
* Bruna Moreira <bruna.moreira@xxxxxxxxxxx>
* Edjard Mota <edjard.mota@xxxxxxxxxxx>
* Ilias Biris <ext-ilias.biris@xxxxxxxxxxx>
* Mauricio Lin <mauricio.lin@xxxxxxxxxxx>
*
* Embedded Linux Lab - 10LE Institulo Nokia de Tecnologia - INdT
*
* Original ranking algorithm ported from kernel space to user space.
* This application writes the list of pids to /proc/oom based on Rik van Riel
* ranking algorithm from mm/oom_kill.c.
*/

#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <linux/timex.h>
#include <math.h>
#include <errno.h>

#if __GNUC__ > 2 || __GNUC_MINOR__ >= 96
#define likely(x) __builtin_expect(!!(x),1)
#define unlikely(x) __builtin_expect(!!(x),0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif

#define CAP_SYS_ADMIN 21
#define CAP_SYS_RAWIO 17

#define PID_MAX 1000

//***************************************************************
// main struct
struct pids_t
{
char pids[PID_MAX + 1];
int points;
struct pids_t *next;
};

//***************************************************************
// Insert new elements in the list
void insert_list(struct pids_t **first, struct pids_t aux)
{
struct pids_t *node = NULL, *previous = NULL, *nnode;

//Creating new node
nnode = (struct pids_t *)malloc(sizeof(struct pids_t));
strcpy(nnode->pids, aux.pids);
nnode->points = aux.points;

if (*first) {
node = (*first);
//find the correct position
while ((node) && (node->points>aux.points)) {
previous = node;
node = node->next;
}
if (nnode == NULL) {
//printf("Problem ......");
exit(1);
}
nnode->next = node;
if (previous)
previous->next = nnode;
else
*first = nnode;
}
else {
*first = nnode;
(*first)->next = NULL;
}
}

void find_field(char *file, char *buffer, char *field)
{

char* match;
char nfield[100];

strcpy(nfield, field);
match = strstr(file, field);

if (match == NULL) {
printf("Prooooblem ....");
}
else {
strcat(nfield, ": %s");
}

sscanf(match, nfield, buffer);

if (!(strcmp(field, "Uid"))) {
strcpy(nfield, buffer);
strcat(nfield, " ");
match += strlen (field) + strlen(buffer) + 2;
sscanf(match, "%s ", buffer);
strcat(nfield, buffer);
strcpy(buffer, nfield);
}

}

char *get_field(char *value, int field, char *result)
{
int c;
strcpy(result, value);
for (c =1; c<field; c++)
strcpy(result, strchr(result, ' ') + sizeof(char));

for (c=0; result[c] != ' ' ; c++);
result[c] = '\0';

return (result);
}

int get_file(char *file, char *pid)
{
int fd;
ssize_t count;
char aux[PID_MAX+1], filename[100];

strcpy(filename, "/proc/");
strcat(filename, pid);
strcat(filename, file);

fd = open(filename, O_RDONLY);
if (likely(fd == -1))
return -1;
count = read(fd, aux, sizeof(aux));
if (likely(count == -1))
return -1;

close(fd);
aux[count] = '\0';
strcpy(file, aux);
return 0;
}



//***************************************************************
// Create the command to record in the /proc/oom

void pidstostr(struct pids_t **list, char *pids)
{

struct pids_t *current;

strcpy(pids,"");
while (*list) {
strcat(pids, (*list)->pids);
current = *list;
*list = (*list)->next;
if ((*list)!=NULL)
strcat(pids, " ");
free(current);
}

}


unsigned long cal_points(char *pid)
{
unsigned long points, cpu_time, run_time, s, uptime, utime,
stime, start_time;
char stat[1024], result[1024]; //data

strcpy(stat, "/oom") ;
get_file(stat, pid);
utime = strtoul(get_field(stat, 2, result), NULL, 10);
stime = strtoul(get_field(stat, 3, result), NULL, 10);

strcpy(stat, "/stat") ;
if (get_file(stat, pid) == -1)
goto failed;

points = strtoul(get_field(stat, 23, result), NULL, 10)/4096;
//vsize
if (points==0)
return 0;

cpu_time = (utime + stime) >> 13; //utime

strcpy(result, "/uptime");
if (get_file(result, "") == -1)
goto failed;

uptime = (strtoul(get_field(result, 1, result), NULL, 10)) *
100; //jiffies
start_time = (strtoul(get_field(stat, 22, result), NULL, 10));
if(uptime >= start_time)
run_time = ((uptime - start_time) >> 10)/100;
else
run_time = 0;

s = sqrt(cpu_time);

if (s)
points /= s;
s = sqrt (sqrt (run_time));

if (s)
points /= s;

if (strtol(get_field(stat, 19, result),NULL,10) > 0)//nice
points*=2;

strcpy(result, "/status") ;

if (get_file(result, pid) == -1)
goto failed;

find_field(result, stat, "CapEff");

s = strtoul(stat , NULL, 16) ;
find_field(result, stat, "Uid");

//Superuser process
if (s & (1 << (CAP_SYS_ADMIN)) ||
atoi(get_field (stat, 1, result)) == 0 ||
atoi(get_field (stat, 2, result)) == 0)
points /=4;

//Process with direct hardware access
if (s & (1 << (CAP_SYS_RAWIO)))
points /=4;
return (points);

failed:
return -1;

}

int write_to_file(char *fname,char *pids)
{
pid_t child_pid;
int fd, i;
ssize_t count;

fd = open(fname, O_WRONLY | O_TRUNC);
if (fd == -1) {
int error_code = errno;
fprintf(stderr, "Error opening file: %s\n",
strerror(error_code));
return -1;
}
count = write(fd, pids, strlen(pids));
if (count == -1) {
int error_code = errno;
fprintf(stderr, "Error writing file: %s\n",
strerror(error_code)); return -1;
}
close(fd);
return 0;
}

unsigned long get_mem(char *type)
{
char memfile[1025], buffer[100];

strcpy (memfile, "/meminfo");
get_file(memfile, "");
find_field(memfile, buffer, type);
return (strtoul(buffer , NULL, 10) );
}

int get_cmdline(char *pid, char *cmd)
{
char file[200];

strcpy (file, "/cmdline");
if(get_file(file, pid)==-1)
return 0;

if ((strstr(file,cmd))==NULL)
return 0;
else
return 1;

}

int main(void)
{
struct pids_t *list = NULL, aux;
DIR* dir;
struct dirent* entry;
int ranking;
char pids[10025];
int pid =(int)getpid();
// ranking = 0 - normal
// ranking = 1 - oom - ranking once

// free<2%Total
ranking = 0;
for(;;) {
if (get_mem("MemFree") <= (0.02*get_mem("MemTotal"))) //
{

if (ranking == 0)
{

dir = opendir("/proc");
while ((entry = readdir(dir)) != NULL) {
if (likely(likely(*entry->d_name > '0') &&
likely(*entry->d_name <= '9'))) {
if (atoi(entry->d_name) != pid) {
if (!(get_cmdline(entry->d_name,
"klogd") || get_cmdline(entry->d_name, "syslogd")))
{
strcpy(aux.pids, entry->d_name);
if ((aux.points =
cal_points(aux.pids)) >= 0)
insert_list(&list, aux);


}
}
}
}

closedir(dir);
pidstostr(&list, pids);
write_to_file("/proc/oom",pids);
ranking = 1;

}
}
else
ranking = 0;
}
return 0;
}

BR,

Mauricio Lin.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/