diff --git a/ChangeLog b/ChangeLog index cc8c32bf..95b5d632 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Sat Jul 7 23:19:09 CEST 2001 Daniel Veillard + + * config.h.in configure.in: added gettimeofday() check + * libxslt/transform.c libxslt/xsltInternals.h libxslt/xsltutils.[ch]: + profiling works option --profile (or --norman ;) + Sat Jul 7 18:58:56 CEST 2001 Daniel Veillard * libxslt/templates.c libxslt/transform.c libxslt/transform.h diff --git a/config.h.in b/config.h.in index ac7b2ebd..9790f824 100644 --- a/config.h.in +++ b/config.h.in @@ -12,6 +12,9 @@ #undef HAVE_FLOOR #undef HAVE_FABS +/* Define if you have the gettimeofday function. */ +#undef HAVE_GETTIMEOFDAY + /* Define if you have the header file. */ #undef HAVE_ANSIDECL_H diff --git a/configure.in b/configure.in index c12a6631..12184622 100644 --- a/configure.in +++ b/configure.in @@ -52,6 +52,7 @@ AC_CHECK_FUNC(floor, , AC_CHECK_LIB(m, pow, AC_CHECK_FUNC(fabs, , AC_CHECK_LIB(m, pow, [M_LIBS="-lm"; AC_DEFINE(HAVE_FABS)])) +AC_CHECK_FUNCS(gettimeofday) dnl dnl Perl is just needed for generating some data for XSLtmark diff --git a/libxslt/transform.c b/libxslt/transform.c index ab3df0ac..315145ca 100644 --- a/libxslt/transform.c +++ b/libxslt/transform.c @@ -73,6 +73,16 @@ int xsltMaxDepth = 500; #define PUSH_AND_POP(scope, type, name) \ scope int name##Push(xsltTransformContextPtr ctxt, type value) { \ + if (ctxt->name##Max == 0) { \ + ctxt->name##Max = 4; \ + ctxt->name##Tab = (type *) xmlMalloc(ctxt->name##Max * \ + sizeof(ctxt->name##Tab[0])); \ + if (ctxt->name##Tab == NULL) { \ + xmlGenericError(xmlGenericErrorContext, \ + "malloc failed !\n"); \ + return(0); \ + } \ + } \ if (ctxt->name##Nr >= ctxt->name##Max) { \ ctxt->name##Max *= 2; \ ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \ @@ -94,7 +104,7 @@ scope type name##Pop(xsltTransformContextPtr ctxt) { \ if (ctxt->name##Nr > 0) \ ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \ else \ - ctxt->name = NULL; \ + ctxt->name = (type) 0; \ ret = ctxt->name##Tab[ctxt->name##Nr]; \ ctxt->name##Tab[ctxt->name##Nr] = 0; \ return(ret); \ @@ -105,6 +115,7 @@ scope type name##Pop(xsltTransformContextPtr ctxt) { \ */ PUSH_AND_POP(static, xsltTemplatePtr, templ) PUSH_AND_POP(static, xsltStackElemPtr, vars) +PUSH_AND_POP(static, long, prof) /************************************************************************ * * @@ -196,6 +207,13 @@ xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { cur->varsMax = 5; cur->vars = NULL; cur->varsBase = 0; + /* + * the profiling stcka is not initialized by default + */ + cur->profTab = NULL; + cur->profNr = 0; + cur->profMax = 0; + cur->prof = 0; cur->style = style; xmlXPathInit(); @@ -968,6 +986,7 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr oldInst = NULL; xmlAttrPtr attrs; int oldBase; + long start = 0; if ((ctxt == NULL) || (list == NULL)) return; @@ -983,7 +1002,7 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, } /* - * stack and saves + * stack saves, beware ordering of operations counts */ oldInsert = insert = ctxt->insert; oldInst = ctxt->inst; @@ -995,6 +1014,8 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, ctxt->node = node; if (ctxt->profile) { templ->nbCalls++; + start = xsltTimestamp(); + profPush(ctxt, 0); } templPush(ctxt, templ); #ifdef WITH_XSLT_DEBUG_PROCESS @@ -1019,30 +1040,7 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, xsltGenericDebug(xsltGenericDebugContext, "xsltApplyOneTemplate: insert == NULL !\n"); #endif - ctxt->node = oldCurrent; - ctxt->inst = oldInst; - ctxt->insert = oldInsert; - if (params == NULL) - xsltFreeStackElemList(varsPop(ctxt)); - else { - xsltStackElemPtr p, tmp = varsPop(ctxt); - if (tmp != params) { - p = tmp; - while ((p != NULL) && (p->next != params)) - p = p->next; - if (p == NULL) { - xsltFreeStackElemList(tmp); - } else { - p->next = NULL; - xsltFreeStackElemList(tmp); - } - } - } - if (templ != NULL) { - ctxt->varsBase = oldBase; - templPop(ctxt); - } - return; + goto error; } if (IS_XSLT_ELEM(cur)) { @@ -1202,6 +1200,7 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, } } while (cur != NULL); } +error: ctxt->node = oldCurrent; ctxt->inst = oldInst; ctxt->insert = oldInsert; @@ -1224,6 +1223,18 @@ xsltApplyOneTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, if (templ != NULL) { ctxt->varsBase = oldBase; templPop(ctxt); + if (ctxt->profile) { + long spent, child, total, end; + + end = xsltTimestamp(); + child = profPop(ctxt); + total = end - start; + spent = total - child; + + templ->time += spent; + if (ctxt->profNr > 0) + ctxt->profTab[ctxt->profNr - 1] += total; + } } } diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h index f1cd5c8f..71c02640 100644 --- a/libxslt/xsltInternals.h +++ b/libxslt/xsltInternals.h @@ -385,6 +385,10 @@ struct _xsltTransformContext { const char * outputFile; /* the output URI if known */ int profile; /* is this run profiled */ + long prof; /* the current profiled value */ + int profNr; /* Nb of templates in the stack */ + int profMax; /* Size of the templtaes stack */ + long *profTab; /* the profile template stack */ }; /** diff --git a/libxslt/xsltproc.c b/libxslt/xsltproc.c index 0c7b5b6a..f4a264fd 100644 --- a/libxslt/xsltproc.c +++ b/libxslt/xsltproc.c @@ -114,7 +114,7 @@ static void usage(const char *name) { #ifdef LIBXML_XINCLUDE_ENABLED printf(" --xinclude : do XInclude processing on document intput\n"); #endif - printf(" --profile : dump profiling informations \n"); + printf(" --profile or --norman : dump profiling informations \n"); } int @@ -192,6 +192,9 @@ main(int argc, char **argv) } else if ((!strcmp(argv[i], "-profile")) || (!strcmp(argv[i], "--profile"))) { profile++; + } else if ((!strcmp(argv[i], "-norman")) || + (!strcmp(argv[i], "--norman"))) { + profile++; } else if ((!strcmp(argv[i], "-warnnet")) || (!strcmp(argv[i], "--warnnet"))) { xmlSetExternalEntityLoader(xsltNoNetExternalEntityLoader); diff --git a/libxslt/xsltutils.c b/libxslt/xsltutils.c index c35e7666..6727ebe0 100644 --- a/libxslt/xsltutils.c +++ b/libxslt/xsltutils.c @@ -12,6 +12,15 @@ #include "libxslt.h" #include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif #include #include @@ -24,6 +33,16 @@ #include "xsltInternals.h" #include "imports.h" +/* gettimeofday on Windows ??? */ +#ifdef WIN32 +#ifdef _MSC_VER +#include +#pragma comment(lib, "ws2_32.lib") +#define gettimeofday(p1,p2) +#define HAVE_GETTIMEOFDAY +#endif /* _MS_VER */ +#endif /* WIN32 */ + /************************************************************************ * * * Convenience function * @@ -941,10 +960,63 @@ xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) { /************************************************************************ * * - * Generating proviling output * + * Generating profiling informations * * * ************************************************************************/ +/** + * xsltCalibrateTimestamps: + * + * Used for to calibrate the xsltTimestamp() function + * Should work if launched at startup and we don't loose our quantum :-) + * + * Returns the number of milliseconds used by xsltTimestamp() + */ +static long +xsltCalibrateTimestamps(void) { + register int i; + + for (i = 0;i < 999;i++) + xsltTimestamp(); + return(xsltTimestamp() / 1000); +} + +/** + * xsltTimestamp: + * + * Used for gathering profiling data + * + * Returns the number of milliseconds since the beginning of the + * profiling + */ +long +xsltTimestamp(void) { +#ifdef HAVE_GETTIMEOFDAY + static long calibration = -1; + static struct timeval startup; + struct timeval cur; + long msec; + + if (calibration == -1) { + gettimeofday(&startup, NULL); + calibration = 0; + calibration = xsltCalibrateTimestamps(); + gettimeofday(&startup, NULL); + return(0); + } + + gettimeofday(&cur, NULL); + msec = cur.tv_sec - startup.tv_sec; + msec *= 10000; + msec += (cur.tv_usec - startup.tv_usec) / 100; + + msec -= calibration; + return((unsigned long) msec); +#else + return(0); +#endif +} + #define MAX_TEMPLATES 10000 /** @@ -959,6 +1031,7 @@ xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) { int nb, i,j; int max; int total; + long totalt; xsltTemplatePtr *templates; xsltStylesheetPtr style; xsltTemplatePtr template; @@ -981,7 +1054,8 @@ xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) { if (nb >= max) break; - templates[nb++] = template; + if (template->nbCalls > 0) + templates[nb++] = template; template = template->next; } @@ -990,7 +1064,9 @@ xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) { for (i = 0;i < nb -1;i++) { for (j = i + 1; j < nb; j++) { - if (templates[i]->nbCalls <= templates[j]->nbCalls) { + if ((templates[i]->time <= templates[j]->time) || + ((templates[i]->time == templates[j]->time) && + (templates[i]->nbCalls <= templates[j]->nbCalls))) { template = templates[j]; templates[j] = templates[i]; templates[i] = template; @@ -998,9 +1074,10 @@ xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) { } } - fprintf(output, "%6s%20s%20s%10s NbCalls\n\n", + fprintf(output, "%6s%20s%20s%10s NbCalls Time 100us\n\n", "number", "match", "name", "mode"); total = 0; + totalt = 0; for (i = 0;i < nb;i++) { fprintf(output, "%5d ", i); if (templates[i]->match != NULL) { @@ -1027,10 +1104,12 @@ xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) { } else { fprintf(output, "%10s", ""); } - fprintf(output, " %6d\n", templates[i]->nbCalls); + fprintf(output, " %6d", templates[i]->nbCalls); + fprintf(output, " %6ld\n", templates[i]->time); total += templates[i]->nbCalls; + totalt += templates[i]->time; } - fprintf(output, "\n%30s%26s %6d\n", "Total", "", total); + fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt); xmlFree(templates); } diff --git a/libxslt/xsltutils.h b/libxslt/xsltutils.h index 3b509017..fab5e4b0 100644 --- a/libxslt/xsltutils.h +++ b/libxslt/xsltutils.h @@ -116,6 +116,8 @@ int xsltSaveResultToFd (int fd, void xsltSaveProfiling (xsltTransformContextPtr ctxt, FILE *output); +long xsltTimestamp (void); + #ifdef __cplusplus } #endif