/* Copyright 2004, 2008 Soeren Sandmann (sandmann@daimi.au.dk) * * Compile with gcc `pkg-config --cflags --libs glib-2.0` freon.c */ #include #include #include #include #include #include #include #include #include #include #include #define PAGE_SIZE 4096 /* FIXME: use getpagesize() */ static void disaster (const char *s) { /* FIXME */ g_print ("something bad happened with %s\n", s); exit (-1); } static void gather_maps (pid_t pid, GHashTable *library_names) { #define BUF_SIZE 1024 char *name = g_strdup_printf ("/proc/%d/maps", pid); char buffer[BUF_SIZE]; FILE *in; in = fopen (name, "r"); if (!in) { disaster ("fopen"); return; } while (fgets (buffer, BUF_SIZE - 1, in)) { char file[256]; int count; count = sscanf (buffer, "%*x-%*x %*15s %*x %*x:%*x %*u %255s", file); if (count == 1) { if (!g_hash_table_lookup (library_names, file)) g_hash_table_insert (library_names, g_strdup (file), GINT_TO_POINTER (1)); } } g_free (name); } static gboolean all_digits (const char *str) { const char *s; for (s = str; *s != '\0'; ++s) { if (!isdigit (*s)) return FALSE; } return TRUE; } static GList * list_running_processes (void) { DIR *proc; GList *result = NULL; struct dirent *entry; proc = opendir ("/proc"); if (!proc) { disaster ("opendir (\"/proc\")"); return NULL; } while ((entry = readdir (proc))) { if (entry->d_name && all_digits (entry->d_name)) { int pid = atoi (entry->d_name); result = g_list_prepend (result, GINT_TO_POINTER (pid)); } } closedir (proc); return result; } static char * library_incore (const char *library_name, int *n_pages) { int fd; void *address; struct stat stat_info; unsigned char *mincore_buf; fd = open (library_name, O_RDONLY); if (fd < 0) return NULL; if (fstat (fd, &stat_info) < 0) { disaster ("fstat"); return NULL; } *n_pages = (stat_info.st_size + PAGE_SIZE - 1) / PAGE_SIZE; address = mmap (NULL, *n_pages * PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0); if (address == MAP_FAILED) { disaster ("mmap"); return NULL; } mincore_buf = malloc (*n_pages); if (mincore (address, *n_pages * PAGE_SIZE, mincore_buf) < 0) { disaster ("mincore"); return NULL; } munmap (address, *n_pages * PAGE_SIZE); return mincore_buf; } static void check_pages (gpointer key, gpointer value, gpointer data) { const char *name = key; char *incore; int i, n_pages; int n_in_core; int n_not_in_core; int *total_pages = data; incore = library_incore (name, &n_pages); if (!incore) return; n_in_core = 0; n_not_in_core = 0; for (i = 0; i < n_pages; ++i) { if (incore[i]) n_in_core++; else n_not_in_core++; } *total_pages += n_in_core; g_free (incore); g_print ("%-55s %6d in core %6d not %6d total\n", name, n_in_core, n_not_in_core, n_in_core + n_not_in_core); } int main () { GList *pids; GHashTable *libraries; GList *list; int total_pages; pids = list_running_processes(); libraries = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (list = pids; list != NULL; list = list->next) gather_maps (GPOINTER_TO_INT (list->data), libraries); total_pages = 0; g_hash_table_foreach (libraries, check_pages, &total_pages); g_hash_table_destroy (libraries); g_list_free (pids); g_print ("Total pages in core: %d (%.2f MB)\n", total_pages, (total_pages * PAGE_SIZE) / (1024.0 * 1024)); return 0; }