The following belongs in apr/test.
It will replay files generated by the following patch:
There are 2 sample replay files which should also get commited at
webperf.org/a2/pool (they are too large to post)

..Ian
Index: apr_pools.c
===================================================================
RCS file: /home/cvspublic/apr/memory/unix/apr_pools.c,v
retrieving revision 1.99
diff -u -u -r1.99 apr_pools.c
--- apr_pools.c 2001/07/07 07:21:14     1.99
+++ apr_pools.c 2001/07/08 02:14:02
@@ -171,7 +171,16 @@
#include <sys/mman.h>
#endif

-
+/** 
+ * APR_INSTRUMENT is only intentended for debuging/performance tuning
+ * and should never be defined on a live system.
+/*
+#define APR_INSTRUMENT
+*/
+#ifdef APR_INSTRUMENT
+#include <sys/time.h>
+static void apr_instrument(const char*fn, apr_pool_t *pool, const
char*format,... );
+#endif
/** The memory allocation structure
  */
struct apr_pool_t {
@@ -670,6 +679,10 @@
     newpool->apr_abort = abortfunc;

     *newcont = newpool;
+
+#ifdef APR_INSTRUMENT
+       apr_instrument("apr_pool_create",parent_pool, "%lu", newpool);
+#endif
     return APR_SUCCESS;
}

@@ -706,7 +719,9 @@
                                      apr_status_t (*child_cleanup)
(void *))
{
     struct cleanup *c;
-
+#ifdef APR_INSTRUMENT
+       apr_instrument("apr_pool_cleanup_register",p,"-");
+#endif
     if (p != NULL) {
         c = (struct cleanup *) apr_palloc(p, sizeof(struct cleanup));
         c->data = data;
@@ -725,6 +740,10 @@

     if (p == NULL)
         return;
+
+#ifdef APR_INSTRUMENT
+       apr_instrument("apr_pool_cleanup_kill",p,"-");
+#endif
     c = p->cleanups;
     lastp = &p->cleanups;
     while (c) {
@@ -804,6 +823,10 @@
     known_stack_point = &s;
     stack_var_init(&s);
#endif
+
+#ifdef APR_INSTRUMENT
+       apr_instrument("apr_pool_alloc_init",globalp,"-");
+#endif
#if APR_HAS_THREADS
     status = apr_lock_create(&alloc_mutex, APR_MUTEX, APR_INTRAPROCESS,
                    NULL, globalp);
@@ -835,6 +858,10 @@
     alloc_mutex = NULL;
     spawn_mutex = NULL;
#endif
+
+#ifdef APR_INSTRUMENT
+       apr_instrument("apr_pool_alloc_term",globalp,"-");
+#endif
     apr_pool_destroy(globalp);
}

@@ -848,6 +875,10 @@
{
     /* free the subpools. we can just loop -- the subpools will detach
        themselve from us, so this is easy. */
+
+#ifdef APR_INSTRUMENT
+       apr_instrument("apr_pool_clear",a,"-");
+#endif
     while (a->sub_pools) {
        apr_pool_destroy(a->sub_pools);
     }
@@ -898,6 +929,9 @@
{
     union block_hdr *blok;

+#ifdef APR_INSTRUMENT
+       apr_instrument("apr_pool_destroy",a,"-");
+#endif
     /* toss everything in the pool. */
     apr_pool_clear(a);

@@ -1104,6 +1138,9 @@
     char *first_avail;
     char *new_first_avail;

+#ifdef APR_INSTRUMENT
+       apr_instrument("apr_palloc",a,"%lu",reqsize);
+#endif
     nclicks = 1 + ((reqsize - 1) / CLICK_SZ);
     size = nclicks * CLICK_SZ;

@@ -1158,7 +1195,9 @@

APR_DECLARE(void *) apr_pcalloc(apr_pool_t *a, apr_size_t size)
{
+
     void *res = apr_palloc(a, size);
+
     memset(res, '\0', size);
     return res;
}
@@ -1174,6 +1213,9 @@
{
     apr_size_t keylen = strlen(key);

+#ifdef APR_INSTRUMENT
+       apr_instrument("apr_pool_userdata_set",cont,"%s",key);
+#endif
     if (cont->prog_data == NULL)
         cont->prog_data = apr_hash_make(cont);

@@ -1191,6 +1233,9 @@

APR_DECLARE(apr_status_t) apr_pool_userdata_get(void **data, const char
*key, apr_pool_t *cont)
{
+#ifdef APR_INSTRUMENT
+       apr_instrument("apr_pool_userdata_get",cont,"%s",key);
+#endif
     if (cont->prog_data == NULL)
         *data = NULL;
     else
@@ -1466,3 +1511,27 @@
        }
     }
}
+
+#ifdef APR_INSTRUMENT
+static void apr_instrument(const char*fn, apr_pool_t *pool, const
char*format,... )
+{
+       static volatile int bfirst=1;
+
+       char buffer[1000];
+       char buffer2[1000];
+    va_list ap;
+       apr_os_thread_t pthread = apr_os_thread_current();
+       pid_t pid = getpid();
+       struct timeval tv;
+       gettimeofday(&tv, NULL);
+       if (bfirst==1) {
+               bfirst=0;
+               fprintf(stderr,
"#APR_INSTRUMENT:PID,THREAD,SECS,USEC,POOL,FN,ARGS\n");
+       }
+    va_start(ap, format);
+       vsnprintf(buffer,sizeof(buffer), format, ap);
+    va_end(ap);
+       snprintf(buffer2,sizeof(buffer2),
"APR_INSTRUMENT:POOL,%lu,%lu,%ld,%ld,%lu,%s,%s\n",pid,pthread,
tv.tv_sec, tv.tv_usec,pool,fn, buffer);
+       fputs(buffer2,stderr);
+}
+#endif

Index: Makefile.in
===================================================================
RCS file: /home/cvspublic/apr/test/Makefile.in,v
retrieving revision 1.59
diff -u -u -r1.59 Makefile.in
--- Makefile.in 2001/07/07 13:03:46     1.59
+++ Makefile.in 2001/07/08 02:11:09
@@ -25,7 +25,8 @@
         [EMAIL PROTECTED]@ \
         [EMAIL PROTECTED]@ \
        [EMAIL PROTECTED]@ \
-        [EMAIL PROTECTED]@
+    [EMAIL PROTECTED]@ \
+       [EMAIL PROTECTED]@ 

TARGETS = $(PROGRAMS)

@@ -125,6 +126,9 @@

[EMAIL PROTECTED]@: teststr.lo $(LOCAL_LIBS)
        $(LINK) teststr.lo $(LOCAL_LIBS) $(ALL_LIBS)
+
[EMAIL PROTECTED]@: testpool.lo $(LOCAL_LIBS)
+       $(LINK) testpool.lo $(LOCAL_LIBS) $(ALL_LIBS)

[EMAIL PROTECTED]@: testsockets.lo $(LOCAL_LIBS)
        $(LINK) testsockets.lo $(LOCAL_LIBS) $(ALL_LIBS)

--
Ian Holsman
Performance Measurement & Analysis
CNET Networks    -    415 364-8608
/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact [EMAIL PROTECTED]
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

#include "apr_thread_proc.h"
#include "apr_lock.h"
#include "apr_errno.h"
#include "apr_file_io.h"
#include "apr_general.h"
#include "apr_strings.h"
#include "apr_tables.h"
#include "errno.h"
#include <stdio.h>
#ifdef BEOS
#include <unistd.h>
#endif

#if !APR_HAS_THREADS
int main(void)
{
    fprintf(stderr,
            "This program won't work on this platform because there is no "
            "support for threads.\n");
    return 0;
}
#else /* !APR_HAS_THREADS */

void * APR_THREAD_FUNC thread_func1(void *data);


typedef enum {  
        cmdPalloc, 
        cmdCleanupRegister,
        cmdUserDataGet,
        cmdUserDataSet,
        cmdCleanupKill,
        cmdDestroy,
        cmdClear,
        cmdCreate
    } pool_cmd_type_e;

typedef struct poolcmd {
    long pid;
    long tid;
    long sec;
    long usec;
    int pool;
    pool_cmd_type_e cmd;
    int poolCreated; /* only used for cmdCreate */
    apr_size_t reqSize; /* only used for cmdPalloc*/

    char *key; /* used for keyget/keyset */
} poolcmd;

apr_lock_t *thread_lock;
apr_pool_t *context;
int x = 0;
apr_array_header_t *command_array;
poolcmd *commands;

#define MAXPOOLS 200
typedef struct poolp {
  unsigned long pool;
  unsigned long poolparent;
} pooltype;
pooltype pools[MAXPOOLS];


int poolcount=0;
int iterations=0;

int find_pool(unsigned long poolID ) 
{
  int i=0;
/*  
  fprintf(stderr,"find pool %lu\n",poolID);
*/
  while (i<poolcount) {
    if (pools[i].pool == poolID )
      return i;
    i++;
  }
  return -1;
}
int new_pool( unsigned long poolID, unsigned long poolParent )
{
  int i=0;
  i=find_pool(poolID);
  if (i!=-1)  {
    return i;
   }
   /*
  fprintf(stderr,"new pool %d %lu Parent %ld\n",poolcount+1,poolID,poolParent); 
  */
  pools[poolcount].pool=poolID;
  pools[poolcount++].poolparent=poolParent;
  return poolcount-1;
}

/* 
 * undefine all pools setup by this parent 
 */
void clearpools( int parent, apr_pool_t** poolthread ) 
{
  int i;
/*
  fprintf(stderr,"Clearing  pool for parent %d\n",parent);
*/
  for (i=0;i<poolcount;i++) {
    if ( pools[i].poolparent == parent ) {
        clearpools(i, poolthread);
        poolthread[i] = NULL;
    }
  }
}
void * APR_THREAD_FUNC thread_func1(void *data)
{
    int i;
    int j;
    apr_status_t s;
    apr_pool_t*p;
//    apr_pool_t*pC;
    apr_pool_t*thread_pool;

    apr_pool_t *poolthread[MAXPOOLS];
    for (j=0;j<iterations;j++) {
      for (i=0;i<MAXPOOLS;i++) {
        poolthread[i] =NULL;
      }
      apr_pool_create( &thread_pool, context);

      for (i = 0; i < (command_array->nelts-1); i++) {
        switch ( commands[i].cmd) {
            case cmdCreate:
             p = poolthread[commands[i].pool];
             /*
             fprintf(stderr,"created pool for line %d parent %d poolthread %d parent %d\n",
                 commands[i].pool, commands[i].poolCreated, poolthread[commands[i].poolCreated], poolthread[commands[i].pool] );
             */
             if ( poolthread[commands[i].pool] < 0 ) {
               s= apr_pool_create( &(poolthread[commands[i].poolCreated] ),thread_pool);
            
             } else  {
               s= apr_pool_create( &(poolthread[commands[i].poolCreated] ),p);
             }

              if (s != APR_SUCCESS)
                fprintf(stderr,"create failed on line %d\n",i+1);
              
              break;
            case cmdPalloc:
              p = poolthread[commands[i].pool];

              if (p == NULL) {
                /*
                fprintf(stderr,"pool for line %d not set\n",i+1);
                */
                s= apr_pool_create( &(poolthread[commands[i].pool] ),thread_pool);
                /*
                fprintf(stderr,"created pool for line %d poolthread %d\n",commands[i].pool, poolthread[commands[i].pool] );
                */
                break;
               }
               apr_palloc( p, commands[i].reqSize);
              /*
              if (s != APR_SUCCESS)
                fprintf(stderr,"palloc failed\n");
                */
              break;
            case cmdDestroy:
              p = poolthread[commands[i].pool];
              if (p == NULL) {
                /*
                fprintf(stderr,"pool for line %d not set\n",i+1);
                */
                break;
               }
                
              /*
              fprintf(stderr,"destroy pool for line %d poolthread %d\n",commands[i].pool, poolthread[commands[i].pool] );
              */
              apr_pool_destroy( p);

              poolthread[commands[i].pool]=NULL;
              clearpools( commands[i].pool, poolthread );
              break;
            case cmdClear:
              p = poolthread[commands[i].pool];
              if (p == NULL) {
                /*
                fprintf(stderr,"pool for line %d not set\n",i+1);
                */
                break;
               }
                
              apr_pool_clear(p);
              /*
              fprintf(stderr,"Clear pool for line %d poolthread %d\n",commands[i].pool, poolthread[commands[i].pool] );
              */
              poolthread[commands[i].pool]=NULL;
              clearpools( commands[i].pool, poolthread );
              break;
        }
/* 
        fprintf(stderr,"command %d\n",i+1);
*/
      }
      apr_pool_destroy( thread_pool );
/* 
      fprintf(stderr,"Itereation %d\n",j+1);
*/
    }
    return NULL;
} 

int main(int argc, char**argv)
{
#if APR_HAS_THREADS
    apr_thread_t *threads[100];
    apr_status_t s1;
    int i;
    
    apr_file_t *file_pool;
    char buffer[200];
    char *p;
    char*token;
    char*tokenargs;
    char*state;
    poolcmd *cmd;

    int nThreads;
    int n;

    if (argc != 4 ) {
        fprintf(stderr, "%s <pool command file> <#threads> <#iterations>\n",argv[0]);
        exit(-1);
    }
    nThreads=atoi(argv[2]);
    if (nThreads > 100 ) {
        fprintf(stderr, "program is hard-coded for <100 threads\n",argv[0]);
        exit(-1);
    }
    iterations=atoi(argv[3]);

    apr_initialize();
    atexit(apr_terminate);

    fprintf(stdout, "Initializing the context......."); 
    if (apr_pool_create(&context, NULL) != APR_SUCCESS) {
        fprintf(stderr, "could not initialize\n");
        exit(-1);
    }
    fprintf(stdout, "OK\n");
    command_array = apr_array_make(context, 1000, sizeof(poolcmd));

    fprintf(stdout, "Reading in pool commands......."); 
    if ( apr_file_open(&file_pool,argv[1],APR_READ, APR_OS_DEFAULT,context) != APR_SUCCESS) {
        fprintf(stderr, "could not open file %s\n",argv[1]);
        exit(-1);
    }

    n=strlen("APR_INSTRUMENT:");
    s1 = APR_SUCCESS;
    while (s1 == APR_SUCCESS ) {
       s1=apr_file_gets(buffer,sizeof(buffer),file_pool);
       cmd = (poolcmd*)apr_array_push(command_array);
       
       if (strncmp("APR_INSTRUMENT:",buffer,n)!=0)
        continue;

       p = &(buffer[n]);
       token= apr_strtok(p,",",&state);
       if (strcmp(token,"POOL")!=0) 
        continue;
       token= apr_strtok(NULL,",",&state);
       cmd->pid=atol(token);
       token= apr_strtok(NULL,",",&state);
       cmd->tid=atol(token);
       token= apr_strtok(NULL,",",&state);
       cmd->sec=atol(token);
       token= apr_strtok(NULL,",",&state);
       cmd->usec=atol(token);
       token= apr_strtok(NULL,",",&state);
       
       cmd->pool=new_pool(strtoul(token,NULL,10),-1);

       token= apr_strtok(NULL,",",&state);
       tokenargs= apr_strtok(NULL,",",&state);
       if (strcmp(token,"apr_palloc") ==0 ) {
        cmd->cmd = cmdPalloc;
        cmd->reqSize =strtoul(tokenargs,NULL,10);
       } else if ( strcmp(token, "apr_pool_cleanup_register")==0) {
        cmd->cmd = cmdCleanupRegister;
       } else if ( strcmp(token, "apr_pool_userdata_get")==0) {
        cmd->cmd = cmdUserDataGet;
        cmd->key=apr_pstrdup(context,tokenargs);
       } else if ( strcmp(token, "apr_pool_userdata_set")==0) {
        cmd->cmd = cmdUserDataSet;
        cmd->key=apr_pstrdup(context,tokenargs);
       } else if ( strcmp(token, "apr_pool_cleanup_kill")==0) {
        cmd->cmd = cmdCleanupKill;
       } else if ( strcmp(token, "apr_pool_destroy")==0) {
        cmd->cmd = cmdDestroy;
       } else if ( strcmp(token, "apr_pool_clear")==0) {
        cmd->cmd = cmdClear;
       } else if ( strcmp(token, "apr_pool_create")==0) {
        cmd->cmd = cmdCreate;
        cmd->poolCreated= new_pool(strtoul( tokenargs,NULL,10), cmd->pool);
       } else {
        fprintf(stderr, "unknown command %s %s\n",token,tokenargs);
        exit(-1);
       }

       
    }
    apr_file_close(file_pool);
    fprintf(stdout, "OK %d commands and %d unique pools\n",command_array->nelts,poolcount);
    commands=(poolcmd*)command_array->elts;


    fprintf(stdout, "Starting all the threads......."); 
    for (i=0;i<nThreads;i++) {
      s1 = apr_thread_create(&(threads[i]), NULL, thread_func1, NULL, context);
      if (s1 != APR_SUCCESS ) {
        fprintf(stdout, "unable to start thread %d.......",i); 
        exit(-1);
      }
    }
   fprintf(stdout, "OK\n");

    fprintf(stdout, "Waiting for threads to exit.......");
    for (i=0;i<nThreads;i++) {
      apr_thread_join(&s1, threads[i]);
    }
    fprintf (stdout, "OK\n");   


    
#endif
    return 1;
}

#endif /* !APR_HAS_THREADS */

Reply via email to