summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBharata B Rao <bharata@linux.vnet.ibm.com>2009-04-01 11:29:19 +0530
committerBalbir Singh <balbir@linux.vnet.ibm.com>2009-04-01 11:29:19 +0530
commit48532a1617ed59b5aaef247eace7a5cb67a1c69c (patch)
tree34b2d9db0aa305c1398716794b8e84029b0fe72f
parentc47ee042c61d050b70e6b90aa50848d82e77b041 (diff)
downloadlibcg-48532a1617ed59b5aaef247eace7a5cb67a1c69c.tar.gz
libcg-48532a1617ed59b5aaef247eace7a5cb67a1c69c.tar.xz
libcg-48532a1617ed59b5aaef247eace7a5cb67a1c69c.zip
Here is the v2 of the patch which introduces APIs to read controller
specific stats. Added Makefile.am updates which I had missed in the previous post. New APIs to read controller specific statistics. This patch introduces 3 new APIs which can be used to read controller statistics iteratively. (Eg. stats from memory.stat etc) Reading of stats is initiated by cgroup_read_stats_begin() API, which returns the first stat of the requested controller in addition to returing a handle that should be used in subsequent reads. cgroup_read_stats_next() API can be used to read the remaining stats one by one. This needs the handle returned by cgroup_read_stats_begin(). cgroup_read_stats_end() API will terminate the stats reading iteration initiated by cgroup_read_stats_begin(). Changelog: v2 - Update tests/Makefile.am so that it generates appropriate rules for tests/read_stats.c in the Makefile. This is in addition to the manual updates done to the generated file tests/Makefile.in. v1 - cgroup_read_stats apis now work with relative cgroup path names instead of absolute path names. v0 - Initial post. Signed-off-by: Bharata B Rao <bharata@linux.vnet.ibm.com> Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com>
-rw-r--r--include/libcgroup.h24
-rw-r--r--src/api.c102
-rw-r--r--src/libcgroup.map3
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/Makefile.in18
-rw-r--r--tests/read_stats.c80
6 files changed, 226 insertions, 4 deletions
diff --git a/include/libcgroup.h b/include/libcgroup.h
index 750e36e..efa852b 100644
--- a/include/libcgroup.h
+++ b/include/libcgroup.h
@@ -129,6 +129,11 @@ struct cgroup_file_info {
*/
#define CG_HIER_MAX CG_CONTROLLER_MAX
+struct cgroup_stat {
+ char name[FILENAME_MAX];
+ char value[CG_VALUE_MAX];
+};
+
/* Functions and structures that can be used by the application*/
struct cgroup;
struct cgroup_controller;
@@ -250,6 +255,25 @@ int cgroup_walk_tree_next(const int depth, void **handle,
struct cgroup_file_info *info, int base_level);
int cgroup_walk_tree_end(void **handle);
+/**
+ * Read the statistics values for the specified controller
+ * @controller: Name of the controller for which stats are requested.
+ * @path: cgroup path.
+ * @handle: Handle to be used during iteration.
+ * @stat: Stats values will be filled and returned here.
+ */
+int cgroup_read_stats_begin(char *controller, char *path, void **handle,
+ struct cgroup_stat *stat);
+
+/**
+ * Read the next stat value.
+ * @handle: Handle to be used during iteration.
+ * @stat: Stats values will be filled and returned here.
+ */
+int cgroup_read_stats_next(void **handle, struct cgroup_stat *stat);
+
+int cgroup_read_stats_end(void **handle);
+
/* The wrappers for filling libcg structures */
struct cgroup *cgroup_new_cgroup(const char *name);
diff --git a/src/api.c b/src/api.c
index 2d57351..a45802e 100644
--- a/src/api.c
+++ b/src/api.c
@@ -20,6 +20,9 @@
*
* Code initiated and designed by Dhaval Giani. All faults are most likely
* his mistake.
+ *
+ * Bharata B Rao <bharata@linux.vnet.ibm.com> is willing is take blame
+ * for mistakes in APIs for reading statistics.
*/
#include <dirent.h>
@@ -2321,3 +2324,102 @@ int cgroup_walk_tree_begin(char *controller, char *base_path, const int depth,
*handle = fts;
return ret;
}
+
+/*
+ * This parses a stat line which is in the form of (name value) pair
+ * separated by a space.
+ */
+int cg_read_stat(FILE *fp, struct cgroup_stat *stat)
+{
+ int ret = 0;
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t read;
+ char *token, *saveptr;
+
+ read = getline(&line, &len, fp);
+ if (read == -1)
+ return ECGEOF;
+
+ token = strtok_r(line, " ", &saveptr);
+ if (!token) {
+ ret = ECGINVAL;
+ goto out_free;
+ }
+ strncpy(stat->name, token, FILENAME_MAX);
+
+ token = strtok_r(NULL, " ", &saveptr);
+ if (!token) {
+ ret = ECGINVAL;
+ goto out_free;
+ }
+ strncpy(stat->value, token, CG_VALUE_MAX);
+
+out_free:
+ free(line);
+ return 0;
+}
+
+int cgroup_read_stats_end(void **handle)
+{
+ FILE *fp;
+
+ if (!cgroup_initialized)
+ return ECGROUPNOTINITIALIZED;
+
+ if (!handle)
+ return ECGINVAL;
+
+ fp = (FILE *)*handle;
+ fclose(fp);
+ return 0;
+}
+
+int cgroup_read_stats_next(void **handle, struct cgroup_stat *stat)
+{
+ int ret = 0;
+ FILE *fp;
+
+ if (!cgroup_initialized)
+ return ECGROUPNOTINITIALIZED;
+
+ if (!handle || !stat)
+ return ECGINVAL;
+
+ fp = (FILE *)*handle;
+ ret = cg_read_stat(fp, stat);
+ *handle = fp;
+ return ret;
+}
+
+/*
+ * TODO: Need to decide a better place to put this function.
+ */
+int cgroup_read_stats_begin(char *controller, char *path, void **handle,
+ struct cgroup_stat *stat)
+{
+ int ret = 0;
+ char stat_file[FILENAME_MAX];
+ FILE *fp;
+
+ if (!cgroup_initialized)
+ return ECGROUPNOTINITIALIZED;
+
+ if (!stat || !handle)
+ return ECGINVAL;
+
+ if (!cg_build_path(path, stat_file, controller))
+ return ECGOTHER;
+
+ sprintf(stat_file, "%s/%s.stat", stat_file, controller);
+
+ fp = fopen(stat_file, "r");
+ if (!fp) {
+ cgroup_dbg("fopen failed\n");
+ return ECGINVAL;
+ }
+
+ ret = cg_read_stat(fp, stat);
+ *handle = fp;
+ return ret;
+}
diff --git a/src/libcgroup.map b/src/libcgroup.map
index 1989f90..dd44fd7 100644
--- a/src/libcgroup.map
+++ b/src/libcgroup.map
@@ -52,5 +52,8 @@ global:
cgroup_walk_tree_begin;
cgroup_walk_tree_next;
cgroup_walk_tree_end;
+ cgroup_read_stats_begin;
+ cgroup_read_stats_next;
+ cgroup_read_stats_end;
} CGROUP_0.32.1;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3927621..5999389 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -2,13 +2,14 @@ INCLUDES = -I$(top_srcdir)/include
LDADD = $(top_srcdir)/src/.libs/libcgroup.la
# compile the tests, but do not install them
-noinst_PROGRAMS = libcgrouptest01 libcg_ba setuid pathtest walk_test
+noinst_PROGRAMS = libcgrouptest01 libcg_ba setuid pathtest walk_test read_stats
libcgrouptest01_SOURCES=libcgrouptest01.c test_functions.c libcgrouptest.h
libcg_ba_SOURCES=libcg_ba.cpp
setuid_SOURCES=setuid.c
pathtest_SOURCES=pathtest.c
walk_test_SOURCES=walk_test.c
+read_stats_SOURCES=read_stats.c
EXTRA_DIST = pathtest.sh runlibcgrouptest.sh
diff --git a/tests/Makefile.in b/tests/Makefile.in
index dae7a12..704e96f 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -33,7 +33,8 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
noinst_PROGRAMS = libcgrouptest01$(EXEEXT) libcg_ba$(EXEEXT) \
- setuid$(EXEEXT) pathtest$(EXEEXT) walk_test$(EXEEXT)
+ setuid$(EXEEXT) pathtest$(EXEEXT) walk_test$(EXEEXT) \
+ read_stats$(EXEEXT)
subdir = tests
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -65,6 +66,10 @@ am_walk_test_OBJECTS = walk_test.$(OBJEXT)
walk_test_OBJECTS = $(am_walk_test_OBJECTS)
walk_test_LDADD = $(LDADD)
walk_test_DEPENDENCIES = $(top_srcdir)/src/.libs/libcgroup.la
+am_read_stats_OBJECTS = read_stats.$(OBJEXT)
+read_stats_OBJECTS = $(am_read_stats_OBJECTS)
+read_stats_LDADD = $(LDADD)
+read_stats_DEPENDENCIES = $(top_srcdir)/src/.libs/libcgroup.la
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@@ -87,9 +92,11 @@ CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
SOURCES = $(libcg_ba_SOURCES) $(libcgrouptest01_SOURCES) \
- $(pathtest_SOURCES) $(setuid_SOURCES) $(walk_test_SOURCES)
+ $(pathtest_SOURCES) $(setuid_SOURCES) $(walk_test_SOURCES) \
+ $(read_stats_SOURCES)
DIST_SOURCES = $(libcg_ba_SOURCES) $(libcgrouptest01_SOURCES) \
- $(pathtest_SOURCES) $(setuid_SOURCES) $(walk_test_SOURCES)
+ $(pathtest_SOURCES) $(setuid_SOURCES) $(walk_test_SOURCES) \
+ $(read_test_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -214,6 +221,7 @@ libcg_ba_SOURCES = libcg_ba.cpp
setuid_SOURCES = setuid.c
pathtest_SOURCES = pathtest.c
walk_test_SOURCES = walk_test.c
+read_stats_SOURCES = read_stats.c
EXTRA_DIST = pathtest.sh runlibcgrouptest.sh
TESTS = runlibcgrouptest.sh
all: all-am
@@ -271,6 +279,9 @@ setuid$(EXEEXT): $(setuid_OBJECTS) $(setuid_DEPENDENCIES)
walk_test$(EXEEXT): $(walk_test_OBJECTS) $(walk_test_DEPENDENCIES)
@rm -f walk_test$(EXEEXT)
$(LINK) $(walk_test_OBJECTS) $(walk_test_LDADD) $(LIBS)
+read_stats$(EXEEXT): $(read_stats_OBJECTS) $(read_stats_DEPENDENCIES)
+ @rm -f read_stats$(EXEEXT)
+ $(LINK) $(read_stats_OBJECTS) $(read_stats_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -284,6 +295,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setuid.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_functions.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/walk_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read_stats.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
diff --git a/tests/read_stats.c b/tests/read_stats.c
new file mode 100644
index 0000000..6e61b97
--- /dev/null
+++ b/tests/read_stats.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <libcgroup.h>
+
+int read_stats(char *path, char *controller)
+{
+ int ret;
+ void *handle;
+ struct cgroup_stat stat;
+
+ ret = cgroup_read_stats_begin(controller, path, &handle, &stat);
+
+ if (ret != 0) {
+ fprintf(stderr, "stats read failed\n");
+ return -1;
+ }
+
+ printf("Stats for %s:\n", path);
+ printf("%s: %s", stat.name, stat.value);
+
+ while ((ret = cgroup_read_stats_next(&handle, &stat)) !=
+ ECGEOF) {
+ printf("%s: %s", stat.name, stat.value);
+ }
+
+ cgroup_read_stats_end(&handle);
+ printf("\n");
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ char *controller;
+ void *handle;
+ struct cgroup_file_info info;
+ int lvl;
+ char cgroup_path[FILENAME_MAX];
+ int root_len;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage %s: <controller name>\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ controller = argv[1];
+
+ cgroup_init();
+
+ ret = cgroup_walk_tree_begin(controller, "/", 0, &handle, &info, &lvl);
+
+ if (ret != 0) {
+ fprintf(stderr, "Walk failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ root_len = strlen(info.full_path) - 1;
+ strncpy(cgroup_path, info.path, FILENAME_MAX);
+ ret = read_stats(cgroup_path, controller);
+ if (ret < 0)
+ exit(EXIT_FAILURE);
+
+ while ((ret = cgroup_walk_tree_next(0, &handle, &info, lvl)) !=
+ ECGEOF) {
+ if (info.type != CGROUP_FILE_TYPE_DIR)
+ continue;
+ strncpy(cgroup_path, info.full_path + root_len, FILENAME_MAX);
+ strcat(cgroup_path, "/");
+ ret = read_stats(cgroup_path, controller);
+ if (ret < 0)
+ exit(EXIT_FAILURE);
+ }
+ cgroup_walk_tree_end(&handle);
+
+ return EXIT_SUCCESS;
+}