cargilld 2004/07/08 08:13:51 Modified: c/tests/ThreadTest ThreadTest.cpp Log: Various updates to ThreadTest from Khaled, Steve Dulin and myself including sax2 support, grammar caching, and some debug support. Revision Changes Path 1.34 +535 -235 xml-xerces/c/tests/ThreadTest/ThreadTest.cpp Index: ThreadTest.cpp =================================================================== RCS file: /home/cvs/xml-xerces/c/tests/ThreadTest/ThreadTest.cpp,v retrieving revision 1.33 retrieving revision 1.34 diff -u -r1.33 -r1.34 --- ThreadTest.cpp 13 Feb 2004 13:23:17 -0000 1.33 +++ ThreadTest.cpp 8 Jul 2004 15:13:51 -0000 1.34 @@ -63,16 +63,24 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <ctype.h> #include <xercesc/parsers/SAXParser.hpp> #include <xercesc/parsers/XercesDOMParser.hpp> #include <xercesc/util/PlatformUtils.hpp> #include <xercesc/sax/HandlerBase.hpp> #include <xercesc/framework/MemBufInputSource.hpp> +#include <xercesc/sax2/SAX2XMLReader.hpp> +#include <xercesc/sax2/XMLReaderFactory.hpp> +#include <xercesc/sax2/Attributes.hpp> +#include <xercesc/sax2/DefaultHandler.hpp> + #include <xercesc/dom/DOM.hpp> #include <xercesc/framework/StdOutFormatTarget.hpp> - +#include <xercesc/internal/XMLGrammarPoolImpl.hpp> +#include <xercesc/internal/MemoryManagerImpl.hpp> +#include <xercesc/util/OutOfMemoryException.hpp> void clearFileInfoMemory(); @@ -86,8 +94,6 @@ #include "Windows.h" #include "process.h" - - typedef DWORD (WINAPI *ThreadFunc)(void *); class ThreadFuncs // This class isolates OS dependent threading @@ -136,7 +142,6 @@ extern "C" { - typedef void (*ThreadFunc)(void *); typedef void *(*pthreadfunc)(void *); @@ -181,13 +186,13 @@ } } -} + +} // end of extern "C" #else #error This platform is not supported #endif - //------------------------------------------------------------------------------ // // struct InFileInfo One of these structs will be set up for each file listed @@ -210,36 +215,6 @@ // each file before the worker threads are started. }; -//------------------------------------------------------------------------------ -// -// struct runInfo Holds the info extracted from the command line. -// There is only one of these, and it is static, and -// unchanging once the command line has been parsed. -// During the test, the threads will access this info without -// any synchronization. -// -//------------------------------------------------------------------------------ -const int MAXINFILES = 25; -struct RunInfo -{ - bool quiet; - bool verbose; - bool stopNow; - int numThreads; - bool validating; - bool dom; - bool reuseParser; - bool inMemory; - bool dumpOnErr; - bool doSchema; - bool schemaFullChecking; - bool doNamespaces; - bool doInitialParse; - int totalTime; - int numInputFiles; - InFileInfo files[MAXINFILES]; -}; - //------------------------------------------------------------------------------ // @@ -251,11 +226,11 @@ //------------------------------------------------------------------------------ struct ThreadInfo { - bool fHeartBeat; // Set true by the thread each time it finishes - // parsing a file. - bool fInProgress; // Set to false by the thread when parse in progress - unsigned int fParses; // Number of parses completed. - int fThreadNum; // Identifying number for this thread. + bool fHeartBeat; // Set true by the thread each time it finishes + // parsing a file. + bool fInProgress; // Set to false by the thread when parse in progress + unsigned int fParses; // Number of parses completed. + int fThreadNum; // Identifying number for this thread. ThreadInfo() { fHeartBeat = false; fInProgress = false; @@ -265,6 +240,41 @@ }; +XERCES_CPP_NAMESPACE_USE +//------------------------------------------------------------------------------ +// +// struct runInfo Holds the info extracted from the command line. +// There is only one of these, and it is static, and +// unchanging once the command line has been parsed. +// During the test, the threads will access this info without +// any synchronization. +// +//------------------------------------------------------------------------------ +const int MAXINFILES = 25; +struct RunInfo +{ + bool doGrammarCaching; + bool quiet; + bool verbose; + bool stopNow; + bool dom; + bool sax; + bool reuseParser; + bool inMemory; + bool dumpOnErr; + bool doSchema; + bool schemaFullChecking; + bool doNamespaces; + bool doInitialParse; + bool doNamespacePrefixes; // SAX2 + SAXParser::ValSchemes valScheme; + int numThreads; + int totalTime; + int numInputFiles; + unsigned int numParses; + InFileInfo files[MAXINFILES]; +}; + // //------------------------------------------------------------------------------ // @@ -274,8 +284,61 @@ RunInfo gRunInfo; ThreadInfo *gThreadInfo; +/** Grammar caching thread testing */ +MemoryManager* gpMemMgr = 0; +XMLGrammarPool* gp = 0; -XERCES_CPP_NAMESPACE_USE +// Routines which maybe helpful for debugging +static void printString(const XMLCh *str) +{ + char *s = XMLString::transcode(str); + printf("%s", s); + delete s; +} + +#define CHARS_PER_LINE 40 +#define BYTES_PER_LINE 16 + +/* + * DumpLine: Dump out a buffer (address and length) to stderr. + */ +static void DumpLine(char* address, int length) { + int i, c, charCount=0; + if (length % 4) length += 4; + fprintf(stderr, "%8.8p: ", address); + for (i=0; i < length/4; ++i) { + fprintf(stderr, "%8.8X ", ((int*)address)[i]); + charCount += 9; + } + for (i=charCount; i < CHARS_PER_LINE; ++i) { + putc(' ', stderr); + } + fprintf(stderr, "| "); + for (i=0; i < length; ++i) { + c = address[i]; + c = (isprint(c) ? c : '.'); + fprintf(stderr, "%c", c); + } + fprintf(stderr, "\n"); +} + +/* + * dump: dump out a buffer (address and length) to stderr by dumping out + * a line at a time (DumpLine), until the buffer is written out. + */ + +static void dump(void* generalAddress, int length) { + int curr = 0; + char* address = (char*) generalAddress; + while (&address[curr] < &address[length-BYTES_PER_LINE]) { + DumpLine(&address[curr], BYTES_PER_LINE); + curr += BYTES_PER_LINE; + } + if (curr < length) { + DumpLine(&address[curr], length-curr); + } + fflush(stderr); +} //------------------------------------------------------------------------------ // @@ -287,16 +350,17 @@ // in different threads. // //------------------------------------------------------------------------------- -class ThreadParser: public HandlerBase -{ -private: - int fCheckSum; - SAXParser* fSAXParser; - XercesDOMParser* fXercesDOMParser; - XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * fDoc; - -public: // This is the API used by the rest of the test program +class ThreadParser +{ +public: + class SAXHandler; + class SAX2Handler; + SAXHandler* fSAXHandler; + SAX2Handler* fSAX2Handler; + ErrorHandler* fDOMErrorHandler; + + // This is the API used by the rest of the test program ThreadParser(); ~ThreadParser(); @@ -305,84 +369,197 @@ // return the XML checksum, or // 0 if a parse error occurred. + int getCheckSum() { + return fCheckSum; + }; + int reCheck(); // Try to compute the checksum again. // for DOM, re-walk the tree. // for SAX, can't do, just return previous value. void domPrint(); // including any children. Default (no param) // version dumps the entire document. - -private: - ThreadParser(const ThreadParser &); // No copy constructor - const ThreadParser & operator =(const ThreadParser &); // No assignment. - void addToCheckSum(const XMLCh *chars, int len=-1); - void domCheckSum(const DOMNode *); - - -public: // Not really public, - // These are the SAX call-back functions - // that this class implements. - void startElement(const XMLCh* const name, AttributeList& attributes); + + // These are the SAX call-back functions that this class implements. Can be used + // for SAX and SAX2. void characters(const XMLCh* const chars, const unsigned int length) { - addToCheckSum(chars, length);}; + addToCheckSum(chars, length); + }; + void ignorableWhitespace(const XMLCh* const chars, const unsigned int length) { - addToCheckSum(chars, length);}; - void resetDocument() {}; + addToCheckSum(chars, length); + }; + + void resetDocument() { + }; void warning(const SAXParseException& exception) { fprintf(stderr, "*** Warning "); - throw exception;}; + fflush(stderr); + throw exception; + }; void error(const SAXParseException& exception) { fprintf(stderr, "*** Error "); - throw exception;}; + fflush(stderr); + throw exception; + }; void fatalError(const SAXParseException& exception) { fprintf(stderr, "***** Fatal error "); - throw exception;}; -}; + fflush(stderr); + throw exception; + }; + + // Create a nested class that can inherit from HandlerBase + // for SAX startElement callbacks. + class SAXHandler : public HandlerBase + { + public: + ThreadParser* SAXInstance; + + void startElement(const XMLCh* const name, AttributeList& attributes); + }; + + // Create a nested class that can inherit from DefaultHandler + // for SAX2 startElement callbacks. + class SAX2Handler : public DefaultHandler + { + public: + ThreadParser* SAX2Instance; + + void startElement(const XMLCh* const uri, + const XMLCh* const localname, + const XMLCh* const qname, + const Attributes& attributes); + }; + +private: + int fCheckSum; + SAXParser* fSAXParser; + SAX2XMLReader* fSAX2Parser; + XercesDOMParser* fXercesDOMParser; + XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument * fDoc; + ThreadParser(const ThreadParser &); // No copy constructor + const ThreadParser & operator =(const ThreadParser &); // No assignment. + + void domCheckSum(const DOMNode *); +}; // // ThreadParser constructor. Invoked by the threads of the test program // to create parsers. // ThreadParser::ThreadParser() -{ - fSAXParser = 0; +{ + fSAXParser = 0; + fSAX2Parser = 0; fXercesDOMParser = 0; - fDoc = 0; + fSAXHandler = 0; + fSAX2Handler = 0; + fDOMErrorHandler = 0; + fDoc = 0; + fCheckSum = 0; + if (gRunInfo.dom) { // Set up to use a DOM parser - fXercesDOMParser = new XercesDOMParser; - fXercesDOMParser->setDoValidation(gRunInfo.validating); + /** Grammar caching thread testing */ + if (gp) { + fXercesDOMParser = new XercesDOMParser(0, XMLPlatformUtils::fgMemoryManager, gp); + fXercesDOMParser->cacheGrammarFromParse(true); + fXercesDOMParser->useCachedGrammarInParse(true); + } + else { + fXercesDOMParser = new XercesDOMParser; + } + switch (gRunInfo.valScheme) { + case SAXParser::Val_Never: + fXercesDOMParser->setValidationScheme(XercesDOMParser::Val_Never); + break; + case SAXParser::Val_Auto: + fXercesDOMParser->setValidationScheme(XercesDOMParser::Val_Auto); + break; + default: //SAXParser::Val_Always: + fXercesDOMParser->setValidationScheme(XercesDOMParser::Val_Always); + break; + } fXercesDOMParser->setDoSchema(gRunInfo.doSchema); fXercesDOMParser->setValidationSchemaFullChecking(gRunInfo.schemaFullChecking); fXercesDOMParser->setDoNamespaces(gRunInfo.doNamespaces); - fXercesDOMParser->setErrorHandler(this); + fDOMErrorHandler = (ErrorHandler*) new HandlerBase(); + fXercesDOMParser->setErrorHandler(fDOMErrorHandler); } - else - { - // Set up to use a SAX parser. - fSAXParser = new SAXParser; - fSAXParser->setDoValidation(gRunInfo.validating); + + else if (gRunInfo.sax) { + // Set up to use a SAX1 parser. + /** Grammar caching thread testing */ + if (gp) { + fSAXParser = new SAXParser(0, XMLPlatformUtils::fgMemoryManager, gp); + fSAXParser->cacheGrammarFromParse(true); + fSAXParser->useCachedGrammarInParse(true); + } + else { + fSAXParser = new SAXParser(); + } + fSAXParser->setValidationScheme(gRunInfo.valScheme); fSAXParser->setDoSchema(gRunInfo.doSchema); fSAXParser->setValidationSchemaFullChecking(gRunInfo.schemaFullChecking); fSAXParser->setDoNamespaces(gRunInfo.doNamespaces); - fSAXParser->setDocumentHandler(this); - fSAXParser->setErrorHandler(this); + fSAXHandler = new ThreadParser::SAXHandler(); + fSAXHandler->SAXInstance = this; + fSAXParser->setDocumentHandler(fSAXHandler); + fSAXParser->setErrorHandler(fSAXHandler); } -} - + else { + // Set up to use a SAX2 parser. + /** Grammar caching thread testing */ + if (gp) { + fSAX2Parser = XMLReaderFactory::createXMLReader(gpMemMgr, gp); + fSAX2Parser->setFeature(XMLUni::fgXercesCacheGrammarFromParse,true); + fSAX2Parser->setFeature(XMLUni::fgXercesUseCachedGrammarInParse,true); + } + else { + fSAX2Parser = XMLReaderFactory::createXMLReader(); + } + fSAX2Parser->setFeature(XMLUni::fgSAX2CoreNameSpaces,(gRunInfo.doNamespaces)); + fSAX2Parser->setFeature(XMLUni::fgXercesSchema,(gRunInfo.doSchema)); + fSAX2Parser->setFeature(XMLUni::fgXercesSchemaFullChecking,(gRunInfo.schemaFullChecking)); + + switch (gRunInfo.valScheme) { + case SAXParser::Val_Never: + fSAX2Parser->setFeature(XMLUni::fgSAX2CoreValidation, false); + break; + case SAXParser::Val_Auto: + fSAX2Parser->setFeature(XMLUni::fgSAX2CoreValidation, true); + fSAX2Parser->setFeature(XMLUni::fgXercesDynamic, true); + break; + default: //SAXParser::Val_Always: + fSAX2Parser->setFeature(XMLUni::fgSAX2CoreValidation, true); + fSAX2Parser->setFeature(XMLUni::fgXercesDynamic, false); + break; + } + + fSAX2Parser->setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes,(gRunInfo.doNamespacePrefixes)); + fSAX2Handler = new ThreadParser::SAX2Handler(); + fSAX2Handler->SAX2Instance = this; + fSAX2Parser->setContentHandler(fSAX2Handler); + fSAX2Parser->setErrorHandler(fSAX2Handler); + } +} ThreadParser::~ThreadParser() { - delete fSAXParser; + delete fSAXParser; + delete fSAX2Parser; delete fXercesDOMParser; + delete fSAXHandler; + delete fSAX2Handler; + delete fDOMErrorHandler; } //------------------------------------------------------------------------ @@ -415,37 +592,47 @@ fXercesDOMParser->parse(*mbis); else fXercesDOMParser->parse(fInfo->fileName); - XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* doc = fXercesDOMParser->getDocument(); - domCheckSum(doc); + fDoc = fXercesDOMParser->getDocument(); + domCheckSum(fDoc); } - else - { - // Do a SAX parse + else if (gRunInfo.sax) { + // Do a SAX1 parse if (gRunInfo.inMemory) fSAXParser->parse(*mbis); else fSAXParser->parse(fInfo->fileName); } + else { + // Do a SAX2 parse + if (gRunInfo.inMemory) + fSAX2Parser->parse(*mbis); + else + fSAX2Parser->parse(fInfo->fileName); + } + } + catch (const OutOfMemoryException&) + { + fprintf(stderr, " during parsing: %s\n OutOfMemoryException.\n", fInfo->fileName); + errors = true; } - catch (const XMLException& e) { char *exceptionMessage = XMLString::transcode(e.getMessage()); - fprintf(stderr, " during parsing: %s \n Exception message is: %s \n", + fprintf(stderr, " during parsing: %s\n Exception message is: %s\n", fInfo->fileName, exceptionMessage); XMLString::release(&exceptionMessage); errors = true; } catch (const DOMException& toCatch) { - fprintf(stderr, " during parsing: %s \n DOMException code is: %i \n", + fprintf(stderr, " during parsing: %s\n DOMException code is: %i\n", fInfo->fileName, toCatch.code); errors = true; } catch (const SAXParseException& e) { char *exceptionMessage = XMLString::transcode(e.getMessage()); - fprintf(stderr, " during parsing: %s \n Exception message is: %s \n", + fprintf(stderr, " during parsing: %s\n Exception message is: %s\n", fInfo->fileName, exceptionMessage); XMLString::release(&exceptionMessage); errors = true; @@ -457,8 +644,10 @@ } delete mbis; - if (errors) + if (errors) { + fflush(stderr); return 0; // if errors occurred, return zero as if checksum = 0; + } return fCheckSum; } @@ -494,25 +683,47 @@ // -// startElement - our SAX handler callback function for element starts. -// update the document checksum with the element name +// startElement - our SAX handler callback function for startElement. +// Update the document checksum with the element name // and any attribute names and values. // -void ThreadParser::startElement(const XMLCh *const name, AttributeList &attributes) + void ThreadParser::SAXHandler::startElement(const XMLCh *const name, AttributeList &attributes) { - addToCheckSum(name); - + SAXInstance->addToCheckSum(name); int n = attributes.getLength(); int i; for (i=0; i<n; i++) { const XMLCh *attNam = attributes.getName(i); - addToCheckSum(attNam); + SAXInstance->addToCheckSum(attNam); const XMLCh *attVal = attributes.getValue(i); - addToCheckSum(attVal); + SAXInstance->addToCheckSum(attVal); } } +// +// startElement - our SAX2 handler callback function for startElement. +// Update the document checksum with the element name +// and any attribute names and values. +// + +void ThreadParser::SAX2Handler::startElement(const XMLCh *const uri, + const XMLCh *const localname, + const XMLCh *const qname, + const Attributes& attributes) +{ + SAX2Instance->addToCheckSum(localname); + + int n = attributes.getLength(); + int i; + for (i=0; i<n; i++) + { + const XMLCh *attNam = attributes.getQName(i); + SAX2Instance->addToCheckSum(attNam); + const XMLCh *attVal = attributes.getValue(i); + SAX2Instance->addToCheckSum(attVal); + } +} // // domCheckSum - Compute the check sum for a DOM node. @@ -543,7 +754,6 @@ break; } - case DOMNode::ATTRIBUTE_NODE: { s = node->getNodeName(); // The attribute name @@ -554,7 +764,6 @@ break; } - case DOMNode::TEXT_NODE: case DOMNode::CDATA_SECTION_NODE: { @@ -619,13 +828,6 @@ printf("End DOMPrint\n"); } -static void printString(const XMLCh *str) -{ - char *s = XMLString::transcode(str); - printf("%s", s); - delete s; -} - //---------------------------------------------------------------------- // // parseCommandLine Read through the command line, and save all @@ -640,49 +842,79 @@ void parseCommandLine(int argc, char **argv) { + gRunInfo.doGrammarCaching = false; gRunInfo.quiet = false; // Set up defaults for run. gRunInfo.verbose = false; - gRunInfo.numThreads = 2; - gRunInfo.validating = false; - gRunInfo.doSchema = false; - gRunInfo.schemaFullChecking = false; - gRunInfo.doNamespaces = false; - gRunInfo.doInitialParse = false; + gRunInfo.stopNow = false; gRunInfo.dom = false; + gRunInfo.sax = true; gRunInfo.reuseParser = false; gRunInfo.inMemory = false; gRunInfo.dumpOnErr = false; + gRunInfo.doSchema = false; + gRunInfo.schemaFullChecking = false; + gRunInfo.doNamespaces = false; + gRunInfo.doInitialParse = false; + gRunInfo.doNamespacePrefixes = false; + + gRunInfo.valScheme = SAXParser::Val_Auto; + gRunInfo.numThreads = 2; gRunInfo.totalTime = 0; gRunInfo.numInputFiles = 0; + gRunInfo.numParses = 0; try // Use exceptions for command line syntax errors. { int argnum = 1; - while (argnum < argc) - { + while (argnum < argc) { if (strcmp(argv[argnum], "-quiet") == 0) gRunInfo.quiet = true; else if (strcmp(argv[argnum], "-verbose") == 0) gRunInfo.verbose = true; - else if (strcmp(argv[argnum], "-v") == 0) - gRunInfo.validating = true; + else if (strncmp(argv[argnum], "-v=", 3) == 0) { + const char* const parm = &argv[argnum][3]; + if (!strcmp(parm, "never")) + gRunInfo.valScheme = SAXParser::Val_Never; + else if (!strcmp(parm, "auto")) + gRunInfo.valScheme = SAXParser::Val_Auto; + else if (!strcmp(parm, "always")) + gRunInfo.valScheme = SAXParser::Val_Always; + else { + fprintf(stderr, "Unrecognized -v option \"%s\"\n", parm); + throw 1; + } + } + else if (strcmp(argv[argnum], "-v") == 0) { + fprintf(stderr, "Please note the -v option has been changed to -v=[always | never | auto]\n"); + fprintf(stderr, "ThreadTest will continue with -v=always\n"); + gRunInfo.valScheme = SAXParser::Val_Always; + } else if (strcmp(argv[argnum], "-s") == 0) gRunInfo.doSchema = true; else if (strcmp(argv[argnum], "-f") == 0) gRunInfo.schemaFullChecking = true; else if (strcmp(argv[argnum], "-n") == 0) - gRunInfo.doNamespaces = true; + gRunInfo.doNamespaces = true; + else if (strcmp(argv[argnum], "-p") == 0) + gRunInfo.doNamespacePrefixes = true; else if (!strncmp(argv[argnum], "-parser=", 8)) { - const char* const parm = &argv[argnum][8]; - + const char* const parm = &argv[argnum][8]; if (!strcmp(parm, "dom")) { gRunInfo.dom = true; + gRunInfo.sax = false; } else if (!strcmp(parm, "sax")) { gRunInfo.dom = false; + gRunInfo.sax = true; } - else + else if (!strcmp(parm, "sax2")) { + gRunInfo.dom = false; + gRunInfo.sax = false; + } + else { + fprintf(stderr, "Unrecognized -parser option \"%s\"\n", parm); throw 1; + } } else if (strcmp(argv[argnum], "-init") == 0) gRunInfo.doInitialParse = true; @@ -692,35 +924,53 @@ gRunInfo.dumpOnErr = true; else if (strcmp(argv[argnum], "-mem") == 0) gRunInfo.inMemory = true; - else if (strcmp(argv[argnum], "-threads") == 0) - { + else if (strcmp(argv[argnum], "-threads") == 0) { ++argnum; - if (argnum >= argc) + if (argnum >= argc) { + fprintf(stderr, "Invalid -threads option (missing # of threads)\n"); throw 1; + } gRunInfo.numThreads = atoi(argv[argnum]); - if (gRunInfo.numThreads < 0) + if (gRunInfo.numThreads < 0) { + fprintf(stderr, "Invalid -threads option (negative # of threads)\n"); throw 1; + } } - else if (strcmp(argv[argnum], "-time") == 0) - { + else if (strcmp(argv[argnum], "-time") == 0) { ++argnum; - if (argnum >= argc) + if (argnum >= argc) { + fprintf(stderr, "Invalid -time option (missing time value)\n"); throw 1; + } gRunInfo.totalTime = atoi(argv[argnum]); - if (gRunInfo.totalTime < 1) + if (gRunInfo.totalTime < 1) { + fprintf(stderr, "Invalid -time option (time value < 1)\n"); throw 1; + } + } + else if (strcmp(argv[argnum], "-gc") == 0) + gRunInfo.doGrammarCaching = true; + else if (strcmp(argv[argnum], "-parses") == 0) { + ++argnum; + if (argnum >= argc) { + fprintf(stderr, "Invalid -parses option (missing # of parses)\n"); + throw 1; + } + int temp = atoi(argv[argnum]); + if (temp < 0) { + fprintf(stderr, "Invalid -parses option (negative # of parses)\n"); + throw 1; + } + gRunInfo.numParses = temp; } - else if (argv[argnum][0] == '-') - { + else if (argv[argnum][0] == '-') { fprintf(stderr, "Unrecognized command line option. Scanning \"%s\"\n", argv[argnum]); throw 1; } - else - { + else { gRunInfo.numInputFiles++; - if (gRunInfo.numInputFiles >= MAXINFILES) - { + if (gRunInfo.numInputFiles >= MAXINFILES) { fprintf(stderr, "Too many input files. Limit is %d\n", MAXINFILES); throw 1; } @@ -730,30 +980,35 @@ } // We've made it through the command line. - // Verify that at least one input file to be parsed was specified. - if (gRunInfo.numInputFiles == 0) - { + // Verify that at least one input file to be parsed was specified. + if (gRunInfo.numInputFiles == 0) { fprintf(stderr, "No input XML file specified on command line.\n"); throw 1; }; - + if (gRunInfo.numParses && gRunInfo.totalTime) { + fprintf(stderr, "Both -parses nnn and -time nnn were specified. Ignoring -time nnn.\n"); + } } catch (int) { - fprintf(stderr, "usage: threadtest [-v] [-threads nnn] [-time nnn] [-quiet] [-verbose] xmlfile...\n" - " -v Use validating parser. Non-validating is default.\n" + fprintf(stderr, "usage: ThreadTest [-v] [-threads nnn] [-time nnn] [-quiet] [-verbose] xmlfile...\n" + " -v=xxx Validation scheme [always | never | auto]. Default is AUTO.\n" " -n Enable namespace processing. Defaults to off.\n" " -s Enable schema processing. Defaults to off.\n" " -f Enable full schema constraint checking. Defaults to off.\n" - " -parser=xxx Parser Type [dom | sax]. Default is SAX.\n" + " -parser=xxx Parser Type [dom | sax | sax2]. Default is SAX (SAX1).\n" + " -p Enable namespace prefixes. Defaults to off.\n" + " (Only used with -parser=sax2, ignored otherwise.)\n" " -quiet Suppress periodic status display.\n" " -verbose Display extra messages.\n" " -reuse Retain and reuse parser. Default creates new for each parse.\n" " -threads nnn Number of threads. Default is 2.\n" " -time nnn Total time to run, in seconds. Default is forever.\n" + " -parses nnn Run for nnn parses instead of time. Default is to use time\n" " -dump Dump DOM tree on error.\n" " -mem Read files into memory once only, and parse them from there.\n" + " -gc Enable grammar caching (i.e. grammar cached and used in subsequent parses). Defaults to off.\n" " -init Perform an initial parse of the file(s) before starting up the individual threads.\n\n" ); exit(1); @@ -834,7 +1089,6 @@ unsigned long WINAPI threadMain (void *param) #else extern "C" { - void threadMain (void *param) #endif { @@ -850,66 +1104,74 @@ // Each time through this loop, one file will be parsed and its checksum // computed and compared with the precomputed value for that file. // - while (gRunInfo.stopNow == false) - { - - thInfo->fInProgress = true; + while (gRunInfo.stopNow == false) { + if (gRunInfo.numParses == 0 || thInfo->fParses < gRunInfo.numParses) { + thInfo->fInProgress = true; - if (thParser == 0) - thParser = new ThreadParser; + if (thParser == 0) + thParser = new ThreadParser; - docNum++; + docNum++; - if (docNum >= gRunInfo.numInputFiles) - docNum = 0; + if (docNum >= gRunInfo.numInputFiles) + docNum = 0; - InFileInfo *fInfo = &gRunInfo.files[docNum]; + InFileInfo *fInfo = &gRunInfo.files[docNum]; - if (gRunInfo.verbose ) - printf("Thread #%d: starting file %s\n", thInfo->fThreadNum, fInfo->fileName); - - - int checkSum = 0; - checkSum = thParser->parse(docNum); + if (gRunInfo.verbose ) + printf("Thread #%d: parse %d starting file %s\n", thInfo->fThreadNum, thInfo->fParses, fInfo->fileName); - // For the case where we skip the preparse we will have nothing to - // compare the first parse's results to ... so if this looks like first - // parse move the checkSum back into the gRunInfo data for this file. + int checkSum = 0; + + checkSum = thParser->parse(docNum); + + // For the case where we skip the preparse we will have nothing to + // compare the first parse's results to ... so if this looks like first + // parse move the checkSum back into the gRunInfo data for this file. - if (gRunInfo.files[docNum].checkSum == 0) - { - gRunInfo.files[docNum].checkSum = checkSum; - } + if (gRunInfo.files[docNum].checkSum == 0) { + gRunInfo.files[docNum].checkSum = checkSum; + } + else if (checkSum != gRunInfo.files[docNum].checkSum) { + if (checkSum == 0) { + // parse returns 0 if there was an error so do this to get the real + // checksum value + checkSum = thParser->getCheckSum(); + } + fprintf(stderr, "\nThread %d: Parse Check sum error on file \"%s\" for parse # %d. Expected %x, got %x\n", + thInfo->fThreadNum, thInfo->fParses, fInfo->fileName, fInfo->checkSum, checkSum); - if (checkSum != gRunInfo.files[docNum].checkSum) - { - fprintf(stderr, "\nThread %d: Parse Check sum error on file \"%s\". Expected %x, got %x\n", - thInfo->fThreadNum, fInfo->fileName, fInfo->checkSum, checkSum); + double totalParsesCompleted = 0; + for (int threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) { + totalParsesCompleted += gThreadInfo[threadNum].fParses; + } + fprintf(stderr, "Total number of parses completed is %f.\n", totalParsesCompleted); + + // Revisit - let the loop continue to run? + int secondTryCheckSum = thParser->reCheck(); + fprintf(stderr, " Retry checksum is %x\n", secondTryCheckSum); + if (gRunInfo.dumpOnErr && gRunInfo.dom) { + thParser->domPrint(); + } + fflush(stdout); + fflush(stderr); + clearFileInfoMemory(); + exit(-1); + } - // Revisit - let the loop continue to run? - int secondTryCheckSum = thParser->reCheck(); - fprintf(stderr, " Retry checksum is %x\n", secondTryCheckSum); - if (gRunInfo.dumpOnErr) { - if (gRunInfo.dom) - thParser->domPrint(); + if (gRunInfo.reuseParser == false) { + delete thParser; + thParser = 0; } - fflush(stdout); - clearFileInfoMemory(); - exit(-1); - } - if (gRunInfo.reuseParser == false) - { - delete thParser; - thParser = 0; + thInfo->fHeartBeat = true; + thInfo->fParses++; + thInfo->fInProgress = false; + } + else { + ThreadFuncs::Sleep(1000); } - - - thInfo->fHeartBeat = true; - thInfo->fParses++; - thInfo->fInProgress = false; } - delete thParser; #ifdef PLATFORM_WIN32 return 0; @@ -920,8 +1182,6 @@ } - - //---------------------------------------------------------------------- // // main @@ -948,6 +1208,17 @@ } + /** Grammar caching thread testing */ + // Initialize memory manger and grammar pool + // set doInitialParse to true so that the first parse will cache the + // grammar and it'll be used in subsequent parses + + if (gRunInfo.doSchema == true && gRunInfo.doNamespaces == true && gRunInfo.doGrammarCaching == true) { + gpMemMgr = new MemoryManagerImpl(); + gp = new XMLGrammarPoolImpl(gpMemMgr); + gRunInfo.doInitialParse = true; + } + // // If we will be parsing from memory, read each of the input files // into memory now. @@ -966,7 +1237,7 @@ { // // While we are still single threaded, parse each of the documents - // once, to check for errors, and to note the checksum. + // once, to check for errors, and to note the checksum. // Blow off the rest of the test if there are errors. // ThreadParser *mainParser = new ThreadParser; @@ -982,8 +1253,7 @@ cksum = mainParser->parse(n); - if (cksum == 0) - { + if (cksum == 0) { fprintf(stderr, "An error occurred while initially parsing %s\n", fileName); errors = true; @@ -992,13 +1262,18 @@ gRunInfo.files[n].checkSum = cksum; if (gRunInfo.verbose ) printf("%x\n", cksum); - if (gRunInfo.dumpOnErr && errors) { - if (gRunInfo.dom) - mainParser->domPrint(); + if (gRunInfo.dumpOnErr && errors && gRunInfo.dom) { + mainParser->domPrint(); } } delete mainParser; + + if (errors) { + fprintf(stderr, "Quitting due to error incurred during initial parse\n"); + clearFileInfoMemory(); + return 1; + } } // @@ -1018,38 +1293,53 @@ gThreadInfo[threadNum].fThreadNum = threadNum; ThreadFuncs::startThread(threadMain, &gThreadInfo[threadNum]); } - - // - // Loop, watching the heartbeat of the worker threads. - // Each second, display "+" when all threads have completed a parse - // display "." if some thread hasn't since previous "+" - // - - unsigned long startTime = XMLPlatformUtils::getCurrentMillis(); - int elapsedSeconds = 0; - while (gRunInfo.totalTime == 0 || gRunInfo.totalTime > elapsedSeconds) - { - ThreadFuncs::Sleep(1000); - if (gRunInfo.quiet == false && gRunInfo.verbose == false) - { - char c = '+'; - int threadNum; - for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) - { - if (gThreadInfo[threadNum].fHeartBeat == false) - { - c = '.'; - break; - }; - } - fputc(c, stdout); - fflush(stdout); - if (c == '+') - for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) - gThreadInfo[threadNum].fHeartBeat = false; + + if (gRunInfo.numParses) + { + bool notDone; + while (true) + { + ThreadFuncs::Sleep(1000); + notDone = false; + + for (threadNum = 0; threadNum < gRunInfo.numThreads; threadNum++) { + if (gThreadInfo[threadNum].fParses < gRunInfo.numParses) + notDone = true; + } + if (notDone == false) { + break; + } } - elapsedSeconds = (XMLPlatformUtils::getCurrentMillis() - startTime) / 1000; - }; + } + else + { + // + // Loop, watching the heartbeat of the worker threads. + // Each second, display "+" when all threads have completed a parse + // display "." if some thread hasn't since previous "+" + // + + unsigned long startTime = XMLPlatformUtils::getCurrentMillis(); + int elapsedSeconds = 0; + while (gRunInfo.totalTime == 0 || gRunInfo.totalTime > elapsedSeconds) { + ThreadFuncs::Sleep(1000); + if (gRunInfo.quiet == false && gRunInfo.verbose == false) { + char c = '+'; + for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) { + if (gThreadInfo[threadNum].fHeartBeat == false) { + c = '.'; + break; + } + } + fputc(c, stdout); + fflush(stdout); + if (c == '+') + for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) + gThreadInfo[threadNum].fHeartBeat = false; + } + elapsedSeconds = (XMLPlatformUtils::getCurrentMillis() - startTime) / 1000; + } + } // // Time's up, we are done. (We only get here if this was a timed run) @@ -1066,7 +1356,6 @@ } if (gRunInfo.verbose) printf("Thread #%d: is finished.\n", threadNum); - } // @@ -1080,8 +1369,19 @@ } if (gRunInfo.quiet == false) { - double parsesPerMinute = totalParsesCompleted / (double(gRunInfo.totalTime) / double(60)); - printf("\n%8.1f parses per minute.\n", parsesPerMinute); + if (gRunInfo.numParses) { + printf("\n%8.0f total parses were completed.\n", totalParsesCompleted); + } + else { + double parsesPerMinute = totalParsesCompleted / (double(gRunInfo.totalTime) / double(60)); + printf("\n%8.2f parses per minute.\n", parsesPerMinute); + } + } + + // delete grammar pool and memory manager + if (gp) { + delete gp; + delete gpMemMgr; } XMLPlatformUtils::Terminate();
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]