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 */