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

Reply via email to