This library provides a set of function to help the saving of data as XML
formatted files.
Note: this is a lightweight library as it does not check if the document is
well formed or grammaticallt correct.
It must be considered as a commodity that helps tag indentation and avoids user
to toss with '<' and '>'.
To embbed it into executables, run:
XML_LIB=1 make
Also, it adds heading tags with data such as timestamp, system information,
test conditions... This to facilitate post processing. (eg. further comparisons
of different testruns, formatting for plotting...)
This patch does not alter the LTP/RT traditional stats dump.
A new global command line option is used: -x <id>
Compilation is conditional to LIB_XML.
Signed-off-by: Gilles Carry <[EMAIL PROTECTED]>
---
testcases/realtime/config.mk | 5 +
testcases/realtime/include/libxml.h | 134 ++++++++++++
testcases/realtime/lib/librttest.c | 23 ++-
testcases/realtime/lib/libxml.c | 385 +++++++++++++++++++++++++++++++++++
4 files changed, 545 insertions(+), 2 deletions(-)
create mode 100644 testcases/realtime/include/libxml.h
create mode 100644 testcases/realtime/lib/libxml.c
diff --git a/testcases/realtime/config.mk b/testcases/realtime/config.mk
index 19ccddc..0570a2e 100644
--- a/testcases/realtime/config.mk
+++ b/testcases/realtime/config.mk
@@ -18,6 +18,11 @@ endif
#
CPPFLAGS += -I$(srcdir)/include -D_GNU_SOURCE
CFLAGS += -Wall
+ifdef LIB_XML
+LDLIBS += $(srcdir)/lib/libxml.o
+CFLAGS += -DLIB_XML
+endif
+
LDLIBS += $(srcdir)/lib/libjvmsim.o \
$(srcdir)/lib/librttest.o \
$(srcdir)/lib/libstats.o \
diff --git a/testcases/realtime/include/libxml.h
b/testcases/realtime/include/libxml.h
new file mode 100644
index 0000000..715eb7c
--- /dev/null
+++ b/testcases/realtime/include/libxml.h
@@ -0,0 +1,134 @@
+/******************************************************************************
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * NAME
+ * libxml.h
+ *
+ * DESCRIPTION
+ * Lightweight xml functions
+ *
+ * USAGE:
+ * To be linked with testcases
+ *
+ * AUTHOR
+ * Gilles Carry <[EMAIL PROTECTED]>
+ *
+ * HISTORY
+ * 2008-Oct-20: Initial version by Gilles Carry
+ *
+ * TODO:
+ *
+ *****************************************************************************/
+
+#ifndef LIBXML_H
+#define LIBXML_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#define TAGNAME_MAX_SIZE 100
+
+/* Flags for new tags */
+#define XML_TAG_SC 0x1U /* Self-close tag <mytag ... /> */
+#define XML_TAG_NOCR 0x2U /* No carriage return after markup */
+#define XML_TAG_NOIND 0x4U /* No indentation */
+
+#define xml_start_tag(stream,tagname) xml_tag(stream, 0, tagname, NULL)
+#define xml_sc_tag(stream,tagname) xml_tag(stream, XML_TAG_SC, tagname,
NULL)
+#define xml_start_tag_watrr(stream,tagname,...) xml_tag(stream, 0,
tagname, __VA_ARGS__)
+#define xml_sc_tag_watrr(stream,tagname,...) xml_tag(stream, XML_TAG_SC,
tagname, __VA_ARGS__)
+#define xml_end_tag(stream) xml_end(stream, 0)
+#define xml_entry(stream,tagname,...) \
+ do { \
+ xml_tag(stream, XML_TAG_NOCR, tagname, NULL); \
+ xml_content(stream, __VA_ARGS__); \
+ xml_end(stream, XML_TAG_NOIND); \
+ } while (0)
+
+typedef struct xml_stack_tag {
+ char tagname[TAGNAME_MAX_SIZE];
+} xml_stack_tag_t;
+
+typedef struct xml_stream {
+ FILE * fd;
+ int indent_level;
+ xml_stack_tag_t * stack;
+ int stack_size;
+} xml_stream_t;
+
+extern char *test_name;
+extern char *xml_free_user_id;
+extern int xml_dump;
+
+/*
+ Generic function to write a start or selfclosing tag into an xml stream:
+ * <tagname>
+ * or
+ * <tagname attributes...>
+ * or
+ * <tagname/>
+ * or
+ * <tagname attributes.../>
+ *
+ * xs: xml stream to write to
+ * flags:
+ * XML_TAG_SC: self-close tag (no indentation increase and no end_tag)
+ * XML_TAG_CR: carriage return after markup
+ * tagname: xml markup name
+ * attr_fmt, ...: printf style argument for attributes
+ * no attribute if attr_fmt==NULL or attr_fmt is an empty string
+ */
+void xml_tag(xml_stream_t *xs, unsigned int flags, char *tagname, char
*attr_fmt, ...);
+
+/*
+ * Write an end tag into an xml stream:
+ * </tagname>
+ *
+ * xs: xml stream to write to
+ * flags:
+ * XML_TAG_NOIND: do not indent tag
+ */
+void xml_end(xml_stream_t *xs, unsigned int flags);
+
+/*
+ * Write data to xml stream
+ *
+ * xs: xml stream to write to
+ * fmt, ...: printf style formatting
+ */
+void xml_content(xml_stream_t *xs, char *fmt, ...);
+
+/*
+ * Create XML stream file and initialize headers.
+ * testname: name of the test
+ * root_tag: tag of root element
+ * title: title of the XML stream
+ *
+ * return: xml_stream_t pointer to be reused by subsequent xml_... calls.
+ */
+xml_stream_t * xml_stream_init(char *testname, char *root_tag, char *title);
+
+/*
+ * Close XML stream.
+ *
+ */
+void xml_stream_close(xml_stream_t *xs);
+
+
+#endif /* LIBXML_H */
diff --git a/testcases/realtime/lib/librttest.c
b/testcases/realtime/lib/librttest.c
index e42fc84..71971d3 100644
--- a/testcases/realtime/lib/librttest.c
+++ b/testcases/realtime/lib/librttest.c
@@ -41,6 +41,9 @@
*****************************************************************************/
#include <librttest.h>
+#ifdef LIB_XML
+#include <libxml.h>
+#endif
#include <libstats.h>
#include <stdio.h>
@@ -79,6 +82,10 @@ void rt_help(void)
printf(" -p(0,1) 0:don't use pi mutexes, 1:use pi mutexes\n");
printf(" -v[0-4] 0:no debug, 1:DBG_ERR, 2:DBG_WARN, 3:DBG_INFO,
4:DBG_DEBUG\n");
printf(" -s Enable saving stats data (default disabled)\n");
+#ifdef LIB_XML
+ printf(" -x <user_free_id> Enable saving of outputs into xml file
(default disabled)\n");
+ printf(" user_free_id (mandatory arg) string inserted
into xml dump\n");
+#endif
printf(" -c Set pass criteria\n");
}
@@ -105,7 +112,11 @@ int rt_init(const char *options, int (*parse_arg)(int
option, char *value), int
opterr = 0;
char *all_options;
- if (asprintf(&all_options, ":b:p:v:sc:%s", options) == -1) {
+ if (asprintf(&all_options, ":b:p:v:sc:"
+#ifdef LIB_XML
+ "x:"
+#endif
+ "%s", options) == -1) {
fprintf(stderr, "Failed to allocate string for option
string\n");
exit(1);
}
@@ -123,7 +134,7 @@ int rt_init(const char *options, int (*parse_arg)(int
option, char *value), int
exit(1);
}
}
-
+
while ((c = getopt(argc, argv, all_options)) != -1) {
switch (c) {
case 'c':
@@ -141,6 +152,14 @@ int rt_init(const char *options, int (*parse_arg)(int
option, char *value), int
case 's':
save_stats = 1;
break;
+#ifdef LIB_XML
+ case 'x':
+ xml_dump = 1;
+ xml_free_user_id = optarg;
+ if (!strcmp("", xml_free_user_id))
+ return -1;
+ break;
+#endif
case ':':
fprintf(stderr, "option -%c: missing arg\n", optopt);
parse_arg('h', optarg); /* Just to display usage */
diff --git a/testcases/realtime/lib/libxml.c b/testcases/realtime/lib/libxml.c
new file mode 100644
index 0000000..51cfe6a
--- /dev/null
+++ b/testcases/realtime/lib/libxml.c
@@ -0,0 +1,385 @@
+/******************************************************************************
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * NAME
+ * libxml.c
+ *
+ * DESCRIPTION
+ * Lightweight xml functions
+ *
+ *
+ * USAGE:
+ * To be linked with testcases
+ *
+ * AUTHOR
+ * Gilles Carry <[EMAIL PROTECTED]>
+ *
+ * HISTORY
+ * 2008-Oct-20: Initial version by Gilles Carry
+ *
+ * TODO:
+ *
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/utsname.h>
+#include <stdarg.h>
+#include <libxml.h>
+#include <librttest.h>
+
+#define TAG_STACK_INIT_SIZE 100
+
+char *xml_free_user_id = "";
+int xml_dump = 0;
+
+
+/*
+ * Fetch information across /sys to provide the cpu topology
+ * of the system.
+ */
+static void xml_get_cpu_topology(xml_stream_t * xs)
+{
+ DIR *directory_parent, *directory_node;
+ struct dirent *de,*dn;
+ char directory_path[255];
+ char *sys_dir;
+ char *ts_fname="thread_siblings_list";
+ char buf[200];
+
+ xml_start_tag(xs, "sys");
+ xml_start_tag(xs, "devices");
+ xml_start_tag(xs, "system");
+
+ xml_start_tag(xs, "node");
+
+ sys_dir = "/sys/devices/system/node";
+ directory_parent = opendir(sys_dir);
+ if (!directory_parent) {
+ xml_tag(xs, XML_TAG_SC, "not-numa", NULL);
+ } else {
+ while ((de = readdir(directory_parent)) != NULL) {
+ if (strncmp(de->d_name, "node", 4))
+ continue;
+
+ /* Check if string matches /node[0-9]/ */
+ if (!isdigit(de->d_name[4]))
+ continue;
+
+ xml_start_tag(xs, de->d_name); /* <nodeX> */
+
+ sprintf(directory_path, "%s/%s",sys_dir, de->d_name);
+ directory_node = opendir(directory_path);
+ if (!directory_parent) {
+ fprintf(stderr, "Unable to open dir %s: %s\n",
directory_path, strerror(errno));
+ continue;
+ }
+ while ((dn = readdir(directory_node)) != NULL) {
+ if (strncmp(dn->d_name, "cpu", 3))
+ continue;
+
+ if (!isdigit(dn->d_name[3]))
+ continue;
+
+ xml_tag(xs, XML_TAG_SC, dn->d_name, NULL); /*
<cpuX/> */
+ }
+ xml_end_tag(xs); /* nodeX */
+ closedir(directory_node);
+ }
+ closedir(directory_parent);
+ }
+ xml_end_tag(xs); /* node */
+
+
+ xml_start_tag(xs, "cpu");
+ sys_dir = "/sys/devices/system/cpu";
+ directory_parent = opendir(sys_dir);
+ if (!directory_parent) {
+ fprintf(stderr, "Unable to open dir %s: %s\n", sys_dir,
strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ while ((de = readdir(directory_parent)) != NULL) {
+
+ if (strncmp(de->d_name, "cpu", 3))
+ continue;
+
+ /* Check if string matches /node[0-9]/ */
+ if (!isdigit(de->d_name[3]))
+ continue;
+
+ sprintf(directory_path, "%s/%s/topology",sys_dir, de->d_name);
+ directory_node = opendir(directory_path);
+ if (!directory_node) {
+ /* Cpu probably offline */
+ continue;
+ }
+ xml_start_tag(xs, de->d_name);
+
+ xml_start_tag(xs, "topology");
+ while ((dn = readdir(directory_node)) != NULL) {
+ char *fpath;
+ FILE *fd_sib;
+ size_t rd;
+ char *cr;
+
+
+ if (strncmp(dn->d_name, ts_fname, strlen(ts_fname)))
+ continue;
+
+ asprintf(&fpath, "%s/%s", directory_path, dn->d_name);
+ fd_sib = fopen(fpath, "r");
+ if (fd_sib == NULL) {
+ fprintf(stderr, "Unable to open file %s: %s\n",
fpath, strerror(errno));
+ continue;
+ }
+
+
+ rd = fread(buf, 1, sizeof(buf), fd_sib);
+ if (rd == sizeof(buf))
+ fprintf(stderr, "%s:fread: probable
overflow\n", __FILE__);
+ fclose(fd_sib);
+ free(fpath);
+
+ /*
+ * chop off \n.
+ * Note: We consider that only one \n is present
+ * at the end of the file.
+ */
+ cr = strchr(buf, '\n');
+ if(cr)
+ *cr = '\0';
+
+ xml_entry(xs, ts_fname, buf);
+ }
+ xml_end_tag(xs); /* topology */
+ xml_end_tag(xs); /* de->d_name */;
+ closedir(directory_node);
+ }
+ closedir(directory_parent);
+ xml_end_tag(xs); /* cpu */
+
+ xml_end_tag(xs); /* system */
+ xml_end_tag(xs); /* devices */
+ xml_end_tag(xs); /* sys */
+}
+
+/*
+ Generic function to write a start or selfclosing tag into an xml stream:
+ * <tagname>
+ * or
+ * <tagname attributes...>
+ * or
+ * <tagname/>
+ * or
+ * <tagname attributes.../>
+ *
+ * xs: xml stream to write to
+ * flags:
+ * XML_TAG_SC: self-close tag (no indentation increase and no end_tag)
+ * XML_TAG_CR: carriage return after markup
+ * tagname: xml markup name
+ * attr_fmt, ...: printf style argument for attributes
+ * no attribute if attr_fmt==NULL or attr_fmt is an empty string
+ */
+void xml_tag(xml_stream_t *xs, unsigned int flags, char *tagname, char
*attr_fmt, ...)
+{
+ va_list ap;
+ int i;
+
+ if (!(flags & XML_TAG_SC)) {
+ /* Not self-close tag */
+ if (xs->indent_level == xs->stack_size) {
+ /* Stack overflow -> double size */
+ xs->stack_size *= 2;
+ xs->stack = realloc (xs->stack, sizeof(xml_stack_tag_t)
* xs->stack_size);
+ if (xs->stack == NULL) {
+ perror("xml_stream_init:realloc");
+ free(xs);
+ return;
+ }
+ }
+ /* Remember tag */
+ strcpy(xs->stack[xs->indent_level].tagname, tagname);
+ }
+
+
+ for (i = 0; i < xs->indent_level; i++)
+ fprintf(xs->fd,"\t");
+
+ fprintf(xs->fd, "<%s", tagname);
+ if (attr_fmt && strcmp(attr_fmt, "")) {
+ /* Tag has attribute */
+ fprintf(xs->fd, " ");
+ va_start(ap, attr_fmt);
+ vfprintf(xs->fd, attr_fmt, ap);
+ va_end(ap);
+ }
+
+ if (flags & XML_TAG_SC)
+ fprintf(xs->fd, "/>");
+ else {
+ fprintf(xs->fd, ">");
+ xs->indent_level++;
+ }
+
+ if (flags & XML_TAG_NOCR)
+ return;
+
+ fprintf(xs->fd, "\n");
+}
+
+/*
+ * Write an end tag into an xml stream:
+ * </tagname>
+ *
+ * xs: xml stream to write to
+ * flags:
+ * XML_TAG_NOIND: do not indent tag
+ */
+void xml_end(xml_stream_t *xs, unsigned int flags)
+{
+ int i;
+
+ xs->indent_level--;
+
+ if (!(flags & XML_TAG_NOIND))
+ for (i = 0; i < xs->indent_level; i++)
+ fprintf(xs->fd,"\t");
+
+ fprintf(xs->fd, "</%s>\n", xs->stack[xs->indent_level].tagname);
+
+}
+
+/*
+ * Write data to xml stream
+ *
+ * xs: xml stream to write to
+ * fmt, ...: printf style formatting
+ */
+void xml_content(xml_stream_t *xs, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(xs->fd, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Create XML stream file and initialize headers.
+ * testname: name of the test
+ * root_tag: tag of root element
+ * title: title of the XML stream
+ *
+ * return: xml_stream_t pointer to be reused by subsequent xml_... calls.
+ */
+xml_stream_t * xml_stream_init(char *testname, char *root_tag, char *title)
+{
+ FILE *fd;
+ struct utsname u;
+ char *xmlfile;
+ xml_stream_t *xs;
+ time_t t;
+ struct tm *tmp;
+ char start_time[20];
+
+ xs = malloc (sizeof(xml_stream_t));
+ if (xs == NULL) {
+ perror("xml_stream_init:malloc");
+ return NULL;
+ }
+
+ xs->stack = malloc (sizeof(xml_stack_tag_t) * TAG_STACK_INIT_SIZE);
+ if (xs->stack == NULL) {
+ perror("xml_stream_init:malloc2");
+ free(xs);
+ return NULL;
+ }
+
+ xs->stack_size = TAG_STACK_INIT_SIZE;
+
+
+ t = time(NULL);
+ tmp = localtime(&t);
+ if (tmp == NULL) {
+ perror("localtime");
+ exit(EXIT_FAILURE);
+ }
+
+ if (strftime(start_time, sizeof(start_time), "%Y-%m-%d.%H-%M-%S", tmp)
== 0) {
+ fprintf(stderr, "strftime returned 0");
+ exit(EXIT_FAILURE);
+ }
+
+ xs->indent_level = 0;
+
+
+ if (-1 == asprintf(&xmlfile, "%s.%s.xml", testname, start_time)) {
+ fprintf(stderr, "xml_stream_init: Failed to allocate string for
data filename\n");
+ return NULL;
+ }
+
+ /* generate the data file */
+ if (!(fd = fopen(xmlfile, "w")))
+ return NULL;
+
+ xs->fd = fd;
+
+ uname(&u);
+
+ fprintf(xs->fd, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+
+ xml_start_tag(xs, root_tag);
+
+ /* Headers */
+ xml_entry(xs, "title", title);
+ xml_entry(xs, "testname", testname);
+ xml_entry(xs, "start-time", start_time);
+ xml_start_tag(xs, "systeminfo");
+ xml_start_tag(xs, "uname");
+ xml_entry(xs, "sysname", u.sysname);
+ xml_entry(xs, "nodename", u.nodename);
+ xml_entry(xs, "release", u.release);
+ xml_entry(xs, "version", u.version);
+ xml_entry(xs, "machine", u.machine);
+ xml_end_tag(xs); /* uname */
+ xml_get_cpu_topology(xs);
+ xml_entry(xs, "free-user-id", xml_free_user_id);
+ xml_entry(xs, "online-cpus", "%ld", sysconf(_SC_NPROCESSORS_ONLN));
+ xml_end_tag(xs); /* systeminfo */
+ xml_entry(xs, "filename", xmlfile);
+
+ return xs;
+}
+
+/*
+ * Close XML stream.
+ * root_tag: tag of root element
+ *
+ */
+void xml_stream_close(xml_stream_t *xs)
+{
+ xml_end_tag(xs); /* root_tag */
+ fclose(xs->fd);
+ free(xs->stack);
+ free(xs);
+ return;
+}
+
--
1.5.5.GIT
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Ltp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list