summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2014-05-23 02:05:10 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2014-05-23 02:05:10 +0200
commitbad79d577c8b7e87de5113bbb03c3de72c06f4a1 (patch)
tree2ea1ac5bc936ec5c9b1a154b52d9acf21cac0a09
parent6f4e22c2fb1bf412e84fe4ca105944921a8c7c5d (diff)
implement /proc/slabinfo
-rw-r--r--procfs/Makefile22
-rw-r--r--procfs/rootdir.c96
2 files changed, 117 insertions, 1 deletions
diff --git a/procfs/Makefile b/procfs/Makefile
index 5c51c1d2..28205962 100644
--- a/procfs/Makefile
+++ b/procfs/Makefile
@@ -1,6 +1,6 @@
TARGET = procfs
OBJS = procfs.o netfs.o procfs_dir.o \
- process.o proclist.o rootdir.o dircat.o main.o
+ process.o proclist.o rootdir.o dircat.o main.o mach_debugUser.o
LIBS = -lnetfs -lps -lfshelp -lpthread
CC = gcc
@@ -19,8 +19,28 @@ CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
all: $(TARGET)
+rootdir.o: rootdir.c mach_debug_U.h
+
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
clean:
$(RM) $(TARGET) $(OBJS)
+
+# This is the gist of the MIG user stub handling from Hurd's build
+# system:
+
+# Where to find .defs files.
+vpath %.defs /usr/include/mach_debug
+
+MIG = mig
+MIGCOM = $(MIG) -cc cat - /dev/null
+MIGCOMFLAGS := -subrprefix __
+
+%.udefsi: %.defs
+ $(CPP) -x c $(CPPFLAGS) $(MIGUFLAGS) $($*-MIGUFLAGS) \
+ $< -o $*.udefsi
+
+%_U.h %User.c: %.udefsi
+ $(MIGCOM) $(MIGCOMFLAGS) $(MIGCOMUFLAGS) $($*-MIGCOMUFLAGS) < $< \
+ -user $*User.c -server /dev/null -header $*_U.h
diff --git a/procfs/rootdir.c b/procfs/rootdir.c
index 94b0ddb2..bba98116 100644
--- a/procfs/rootdir.c
+++ b/procfs/rootdir.c
@@ -22,6 +22,7 @@
#include <mach/vm_statistics.h>
#include <mach/vm_cache_statistics.h>
#include <mach/default_pager.h>
+#include <mach_debug/mach_debug_types.h>
#include <hurd/paths.h>
#include <stdio.h>
#include <unistd.h>
@@ -35,6 +36,8 @@
#include "procfs_dir.h"
#include "main.h"
+#include "mach_debug_U.h"
+
/* This implements a directory node with the static files in /proc.
NB: the libps functions for host information return static storage;
using them would require locking and as a consequence it would be
@@ -470,6 +473,92 @@ rootdir_mounts_exists (void *dir_hook, const void *entry_hook)
translator_exists = access (MTAB_TRANSLATOR, F_OK|X_OK) == 0;
return translator_exists;
}
+
+static error_t
+rootdir_gc_slabinfo (void *hook, char **contents, ssize_t *contents_len)
+{
+ error_t err;
+ const char header[] =
+ "cache obj slab bufs objs bufs"
+ " total reclaimable\n"
+ "name flags size size /slab usage count"
+ " memory memory\n";
+ char **infos, *p;
+ ssize_t length, written;
+ cache_info_array_t cache_info;
+ size_t mem_usage, mem_reclaimable, mem_total, mem_total_reclaimable;
+ mach_msg_type_number_t cache_info_count;
+ int i, j;
+
+ cache_info = NULL;
+ cache_info_count = 0;
+
+ err = host_slab_info (mach_host_self(), &cache_info, &cache_info_count);
+ if (err)
+ return err;
+
+ infos = malloc ((cache_info_count + 1) * sizeof *infos);
+ if (infos == NULL)
+ return ENOMEM;
+
+ length = sizeof header; /* Includes the terminating 0. */
+ mem_total = 0;
+ mem_total_reclaimable = 0;
+
+ for (i = 0; i < cache_info_count; i++)
+ {
+ mem_usage = (cache_info[i].nr_slabs * cache_info[i].slab_size)
+ >> 10;
+ mem_total += mem_usage;
+ mem_reclaimable = (cache_info[i].flags & CACHE_FLAGS_NO_RECLAIM)
+ ? 0 : (cache_info[i].nr_free_slabs
+ * cache_info[i].slab_size) >> 10;
+ mem_total_reclaimable += mem_reclaimable;
+ length += written =
+ asprintf (&infos[i],
+ "%-21s %04x %7zu %3zuk %4lu %6lu %6lu %7zuk %10zuk\n",
+ cache_info[i].name, cache_info[i].flags,
+ cache_info[i].obj_size, cache_info[i].slab_size >> 10,
+ cache_info[i].bufs_per_slab, cache_info[i].nr_objs,
+ cache_info[i].nr_bufs, mem_usage, mem_reclaimable);
+ if (written == -1)
+ goto out;
+ }
+
+ length += written =
+ asprintf (&infos[i], "total: %zuk, reclaimable: %zuk\n",
+ mem_total, mem_total_reclaimable);
+ if (written == -1)
+ goto out;
+
+ *contents = p = malloc (length);
+ if (p == NULL)
+ goto out;
+
+ strcpy (p, header);
+ p += sizeof header - 1; /* Without the 0. */
+
+ for (i = 0; i < cache_info_count + 1; i++)
+ {
+ size_t l = strlen (infos[i]);
+ memcpy (p, infos[i], l);
+ p += l;
+ free (infos[i]);
+ }
+ free (infos);
+
+ *p = 0;
+ p += 1;
+ assert (p == *contents + length);
+ *contents_len = length;
+ return 0;
+
+ out:
+ for (j = 0; j < i; j++)
+ free (infos[j]);
+ free (infos);
+ return ENOMEM;
+}
/* Glue logic and entries table */
@@ -563,6 +652,13 @@ static const struct procfs_dir_entry rootdir_entries[] = {
.exists = rootdir_mounts_exists,
}
},
+ {
+ .name = "slabinfo",
+ .hook = & (struct procfs_node_ops) {
+ .get_contents = rootdir_gc_slabinfo,
+ .cleanup_contents = procfs_cleanup_contents_with_free,
+ },
+ },
#ifdef PROFILE
/* In order to get a usable gmon.out file, we must apparently use exit(). */
{