/* iksemel (XML parser for Jabber) ** Copyright (C) 2000-2003 Gurer Ozen ** This code is free software; you can redistribute it and/or ** modify it under the terms of GNU Lesser General Public License. */ #include "common.h" #include "iksemel.h" #include "perf.h" #include #ifdef HAVE_GETOPT_LONG #include #endif #ifdef HAVE_GETOPT_LONG static struct option longopts[] = { { "all", 0, 0, 'a' }, { "sax", 0, 0, 's' }, { "dom", 0, 0, 'd' }, { "serialize", 0, 0, 'e' }, { "sha1", 0, 0, '1' }, { "block", required_argument, 0, 'b' }, { "memdbg", 0, 0, 'm' }, { "help", 0, 0, 'h' }, { "version", 0, 0, 'V' }, { 0, 0, 0, 0 } }; #endif static char *shortopts = "asde1b:mhV"; static void print_usage (void) { puts ("Usage: iksperf [OPTIONS] FILE\n" "This tool measures the performance of the iksemel library.\n" " -a, --all Make all tests.\n" " -s, --sax Sax test.\n" " -d, --dom Tree generating test.\n" " -e, --serialize Tree serializing test.\n" " -1, --sha1 SHA1 hashing test.\n" " -b, --block SIZE Parse the file in SIZE byte blocks.\n" " -m, --memdbg Trace malloc and free calls.\n" " -h, --help Print this text and exit.\n" " -V, --version Print version and exit.\n" #ifndef HAVE_GETOPT_LONG "(long options are not supported on your system)\n" #endif "Report bugs to ."); } /* if not 0, file is parsed in block_size byte blocks */ int block_size; char *load_file (const char *fname, int *sizeptr) { FILE *f; char *buf; struct stat fs; size_t size, ret; if (stat (fname, &fs) != 0) { fprintf (stderr, "Cannot access file '%s'.\n", fname); exit (1); } size = fs.st_size; printf ("Test file '%s' (%d bytes):\n", fname, size); f = fopen (fname, "rb"); if (!f) { fprintf (stderr, "Cannot open file.\n"); exit (1); } buf = malloc (size); if (!buf) { fclose (f); fprintf (stderr, "Cannot allocate %d bytes for buffer.\n", size); exit (2); } ret = fread (buf, 1, size, f); if (ret < size) { fprintf (stderr, "Read error in file.\n"); exit (1); } *sizeptr = size; fclose (f); return buf; } /* stats */ int sax_tag; int sax_cdata; int tagHook (void *udata, char *name, char **atts, int type) { ++sax_tag; return IKS_OK; } int cdataHook (void *udata, char *data, size_t len) { ++sax_cdata; return IKS_OK; } void sax_test (char *buf, int len) { unsigned long time; iksparser *prs; int bs, i, err; bs = block_size; if (0 == bs) bs = len; sax_tag = 0; sax_cdata = 0; t_reset (); prs = iks_sax_new (NULL, tagHook, cdataHook); i = 0; while (i < len) { if (i + bs > len) bs = len - i; err = iks_parse (prs, buf + i, bs, 0); switch (err) { case IKS_OK: break; case IKS_NOMEM: exit (2); case IKS_BADXML: fprintf (stderr, "Invalid xml at byte %ld, line %ld\n", iks_nr_bytes (prs), iks_nr_lines (prs)); exit (1); case IKS_HOOK: exit (1); } i += bs; } time = t_elapsed (); printf ("SAX: parsing took %ld milliseconds.\n", time); printf ("SAX: tag hook called %d, cdata hook called %d times.\n", sax_tag, sax_cdata); iks_parser_delete (prs); } void dom_test (char *buf, int len) { int bs, i, err; iksparser *prs; unsigned long time; iks *x; size_t allocated, used; bs = block_size; if (0 == bs) bs = len; t_reset (); prs = iks_dom_new (&x); iks_set_size_hint (prs, len); i = 0; while (i < len) { if (i + bs > len) bs = len - i; err = iks_parse (prs, buf + i, bs, 0); switch (err) { case IKS_OK: break; case IKS_NOMEM: exit (2); case IKS_BADXML: fprintf (stderr, "Invalid xml at byte %ld, line %ld\n", iks_nr_bytes (prs), iks_nr_lines (prs)); exit (1); case IKS_HOOK: exit (1); } i += bs; } time = t_elapsed (); iks_stack_stat (iks_stack (x), &allocated, &used); printf ("DOM: parsing and building the tree took %ld milliseconds.\n", time); printf ("DOM: ikstack: %d bytes allocated, %d bytes used.\n", allocated, used); t_reset (); iks_delete (x); time = t_elapsed (); printf ("DOM: deleting the tree took %ld milliseconds.\n", time); iks_parser_delete (prs); } void serialize_test (char *buf, int len) { unsigned long time; iks *x; iksparser *prs; int err; prs = iks_dom_new (&x); err = iks_parse (prs, buf, len, 1); switch (err) { case IKS_OK: break; case IKS_NOMEM: exit (2); case IKS_BADXML: fprintf (stderr, "Invalid xml at byte %ld, line %ld\n", iks_nr_bytes (prs), iks_nr_lines (prs)); exit (1); case IKS_HOOK: exit (1); } iks_parser_delete (prs); t_reset (); iks_string (iks_stack (x), x); time = t_elapsed (); printf ("Serialize: serializing the tree took %ld milliseconds.\n", time); iks_delete (x); } void sha_test (char *buf, int len) { unsigned long time; iksha *s; char out[41]; t_reset (); s = iks_sha_new (); iks_sha_hash (s, buf, len, 1); iks_sha_print (s, out); out[40] = '\0'; iks_sha_delete (s); time = t_elapsed (); printf ("SHA: hashing took %ld milliseconds.\n", time); printf ("SHA: hash [%s]\n", out); } int main (int argc, char *argv[]) { int test_type = 0; int c; #ifdef HAVE_GETOPT_LONG int i; while ((c = getopt_long (argc, argv, shortopts, longopts, &i)) != -1) { #else while ((c = getopt (argc, argv, shortopts)) != -1) { #endif switch (c) { case 'a': test_type = 0xffff; break; case 's': test_type |= 1; break; case 'd': test_type |= 2; break; case 'e': test_type |= 4; break; case '1': test_type |= 8; break; case 'b': block_size = atoi (optarg); break; case 'm': m_trace (); break; case 'h': print_usage (); exit (0); case 'V': puts ("iksperf (iksemel) "VERSION); exit (0); } } for (; optind < argc; optind++) { char *buf; int len; buf = load_file (argv[optind], &len); if (test_type & 1) sax_test (buf, len); if (test_type == 0 || test_type & 2) dom_test (buf, len); if (test_type & 4) serialize_test (buf, len); if (test_type & 8) sha_test (buf, len); free (buf); } return 0; }