httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@arctic.org>
Subject Re: misc profiling comments
Date Sun, 11 Jan 1998 12:05:14 GMT
On Sun, 11 Jan 1998, Dean Gaudet wrote:

> Here it is if you want to play with it.  This seems to cut the strcasecmp
> calls in half. 

Uh here it is for real. 

BTW this also includes code cleanup elsewhere in the server because
there's various code that assumes that a table * is the same as an
array_header *... despite the existance of the table_elts() routine.  Even
though the current implementation does "typedef array_header table" it's
not required to be that way... which is why table_elts() exists in the
first place. 

Dean

Index: main/alloc.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/alloc.c,v
retrieving revision 1.67
diff -u -r1.67 alloc.c
--- alloc.c	1998/01/07 16:45:59	1.67
+++ alloc.c	1998/01/11 11:37:48
@@ -584,10 +584,8 @@
  * The 'array' functions...
  */
 
-API_EXPORT(array_header *) make_array(pool *p, int nelts, int elt_size)
+static void make_array_core(array_header *res, pool *p, int nelts, int elt_size)
 {
-    array_header *res = (array_header *) palloc(p, sizeof(array_header));
-
     if (nelts < 1)
 	nelts = 1;		/* Assure sanity if someone asks for
 				 * array of zero elts.
@@ -599,7 +597,13 @@
     res->elt_size = elt_size;
     res->nelts = 0;		/* No active elements yet... */
     res->nalloc = nelts;	/* ...but this many allocated */
+}
+
+API_EXPORT(array_header *) make_array(pool *p, int nelts, int elt_size)
+{
+    array_header *res = (array_header *) palloc(p, sizeof(array_header));
 
+    make_array_core(res, p, nelts, elt_size);
     return res;
 }
 
@@ -658,17 +662,21 @@
  * overhead of the full copy only where it is really needed.
  */
 
-API_EXPORT(array_header *) copy_array_hdr(pool *p, const array_header *arr)
+static ap_inline void copy_array_hdr_core(array_header *res,
+    const array_header *arr)
 {
-    array_header *res = (array_header *) palloc(p, sizeof(array_header));
-
     res->elts = arr->elts;
-
-    res->pool = p;
     res->elt_size = arr->elt_size;
     res->nelts = arr->nelts;
     res->nalloc = arr->nelts;	/* Force overflow on push */
+}
 
+API_EXPORT(array_header *) copy_array_hdr(pool *p, const array_header *arr)
+{
+    array_header *res = (array_header *) palloc(p, sizeof(array_header));
+
+    res->pool = p;
+    copy_array_hdr_core(res, arr);
     return res;
 }
 
@@ -690,80 +698,146 @@
  * The "table" functions.
  */
 
-API_EXPORT(table *) make_table(pool *p, int nelts)
+typedef unsigned int table_hash_t;
+#define TABLE_HASH_SIZE (8*sizeof(table_hash_t))
+
+/* Hash using only the first 8 characters... this is a complete hack,
+ * but should work for the strings that appear in the common tables.
+ */
+static ap_inline table_hash_t table_hash(const char *s)
 {
-    return make_array(p, nelts, sizeof(table_entry));
+    unsigned int h;
+    int i;
+
+    h = 0;
+    for( i = 0; s[i] && i < 8; ++i ) {
+	/* XXX: this assumes ASCII, there's an implicit tolower() here */
+	h = ( h << 1 ) ^ (s[i] & 0x1f);
+    }
+    return 1 << (h % TABLE_HASH_SIZE);
 }
 
-API_EXPORT(table *) copy_table(pool *p, const table *t)
+/* XXX: if you tweak this you should look at is_empty_table() and table_elts()
+ * in alloc.h */
+struct table {
+    /* This has to be first to promote backwards compatibility with
+     * older modules which cast a table * to an array_header *...
+     * they should use the table_elts() function for most of the
+     * cases they do this for.
+     */
+    array_header a;
+    /* Bit h is 0 if there is no key with hash value h in the table.
+     * The converse is *not* true -- a bit of 1 indicates that a key
+     * with value h may be in the table.  This simplifies table_unset,
+     * which is a comparatively infrequent operation.
+     */
+    table_hash_t hash_bits;
+};
+
+
+API_EXPORT(table *) make_table(pool *p, int nelts)
 {
-    return copy_array(p, t);
+    table *t = palloc(p, sizeof(table));
+
+    make_array_core(&t->a, p, nelts, sizeof(table_entry));
+    t->hash_bits = 0;
+    return t;
 }
 
-API_EXPORT(void) clear_table(table *t)
+API_EXPORT(table *) copy_table(pool *p, const table *t)
 {
-    t->nelts = 0;
+    table *new = palloc(p, sizeof(table));
+
+    make_array_core(&new->a, p, t->a.nalloc, sizeof(table_entry));
+    memcpy(new->a.elts, t->a.elts, t->a.nelts * sizeof(table_entry));
+    new->a.nelts = t->a.nelts;
+    new->hash_bits = t->hash_bits;
+    return new;
 }
 
-API_EXPORT(array_header *) table_elts(table *t)
+API_EXPORT(void) clear_table(table *t)
 {
-    return t;
+    t->a.nelts = 0;
+    t->hash_bits = 0;
 }
 
 API_EXPORT(char *) table_get(const table *t, const char *key)
 {
-    table_entry *elts = (table_entry *) t->elts;
+    table_entry *elts = (table_entry *) t->a.elts;
     int i;
+    table_hash_t h;
 
     if (key == NULL)
 	return NULL;
 
-    for (i = 0; i < t->nelts; ++i)
+    h = table_hash(key);
+    if (!(t->hash_bits & h))
+	return NULL;
+
+    for (i = 0; i < t->a.nelts; ++i)
 	if (!strcasecmp(elts[i].key, key))
 	    return elts[i].val;
 
     return NULL;
 }
 
+#ifdef END_HACK
+extern char _end;
+#define is_const(s)		((const char *)(s) < &_end)
+#define dup_nonconst(p, s)	(is_const(s) ? (char *)(s) : pstrdup((p), (s)))
+#else
+#define dup_nonconst(p, s)	(pstrdup((p), (s)))
+#endif
+
 API_EXPORT(void) table_set(table *t, const char *key, const char *val)
 {
     register int i, j, k;
-    table_entry *elts = (table_entry *) t->elts;
+    table_entry *elts = (table_entry *) t->a.elts;
     int done = 0;
+    table_hash_t h;
 
-    for (i = 0; i < t->nelts; ) {
-	if (!strcasecmp(elts[i].key, key)) {
-	    if (!done) {
-		elts[i].val = pstrdup(t->pool, val);
-		done = 1;
-		++i;
-	    }
-	    else {		/* delete an extraneous element */
-		for (j = i, k = i + 1; k < t->nelts; ++j, ++k) {
-		    elts[j].key = elts[k].key;
-		    elts[j].val = elts[k].val;
+    h = table_hash(key);
+    if (t->hash_bits & h) {
+	for (i = 0; i < t->a.nelts; ) {
+	    if (!strcasecmp(elts[i].key, key)) {
+		if (!done) {
+		    elts[i].val = dup_nonconst(t->a.pool, val);
+		    done = 1;
+		    ++i;
+		}
+		else {		/* delete an extraneous element */
+		    for (j = i, k = i + 1; k < t->a.nelts; ++j, ++k) {
+			elts[j].key = elts[k].key;
+			elts[j].val = elts[k].val;
+		    }
+		    --t->a.nelts;
 		}
-		--t->nelts;
 	    }
-	}
-	else {
-	    ++i;
+	    else {
+		++i;
+	    }
 	}
     }
 
     if (!done) {
-	elts = (table_entry *) push_array(t);
-	elts->key = pstrdup(t->pool, key);
-	elts->val = pstrdup(t->pool, val);
+	elts = (table_entry *) push_array(&t->a);
+	elts->key = dup_nonconst(t->a.pool, key);
+	elts->val = dup_nonconst(t->a.pool, val);
+	t->hash_bits |= h;
     }
 }
 
 API_EXPORT(void) table_unset(table *t, const char *key)
 {
     register int i, j, k;
-    table_entry *elts = (table_entry *) t->elts;
+    table_entry *elts = (table_entry *) t->a.elts;
+    table_hash_t h;
+
+    h = table_hash(key);
+    if (!(t->hash_bits & h))
+	return;
 
-    for (i = 0; i < t->nelts; ) {
+    for (i = 0; i < t->a.nelts;) {
 	if (!strcasecmp(elts[i].key, key)) {
 
 	    /* found an element to skip over
@@ -771,11 +845,11 @@
 	     * a contiguous block of memory.  I've chosen one that
 	     * doesn't do a memcpy/bcopy/array_delete, *shrug*...
 	     */
-	    for (j = i, k = i + 1; k < t->nelts; ++j, ++k) {
+	    for (j = i, k = i + 1; k < t->a.nelts; ++j, ++k) {
 		elts[j].key = elts[k].key;
 		elts[j].val = elts[k].val;
 	    }
-	    --t->nelts;
+	    --t->a.nelts;
 	}
 	else {
 	    ++i;
@@ -785,32 +859,50 @@
 
 API_EXPORT(void) table_merge(table *t, const char *key, const char *val)
 {
-    table_entry *elts = (table_entry *) t->elts;
+    table_entry *elts = (table_entry *) t->a.elts;
     int i;
+    table_hash_t h;
 
-    for (i = 0; i < t->nelts; ++i)
-	if (!strcasecmp(elts[i].key, key)) {
-	    elts[i].val = pstrcat(t->pool, elts[i].val, ", ", val, NULL);
-	    return;
+    h = table_hash(key);
+    if (t->hash_bits & h) {
+	for (i = 0; i < t->a.nelts; ++i) {
+	    if (!strcasecmp(elts[i].key, key)) {
+		elts[i].val = pstrcat(t->a.pool, elts[i].val, ", ", val, NULL);
+		return;
+	    }
 	}
+    }
 
-    elts = (table_entry *) push_array(t);
-    elts->key = pstrdup(t->pool, key);
-    elts->val = pstrdup(t->pool, val);
+    t->hash_bits |= h;
+    elts = (table_entry *) push_array(&t->a);
+    elts->key = dup_nonconst(t->a.pool, key);
+    elts->val = dup_nonconst(t->a.pool, val);
 }
 
 API_EXPORT(void) table_add(table *t, const char *key, const char *val)
 {
-    table_entry *elts = (table_entry *) t->elts;
+    table_entry *elts = (table_entry *) t->a.elts;
+    table_hash_t h;
 
-    elts = (table_entry *) push_array(t);
-    elts->key = pstrdup(t->pool, key);
-    elts->val = pstrdup(t->pool, val);
+    h = table_hash(key);
+    t->hash_bits |= h;
+    elts = (table_entry *) push_array(&t->a);
+    elts->key = dup_nonconst(t->a.pool, key);
+    elts->val = dup_nonconst(t->a.pool, val);
 }
 
 API_EXPORT(table *) overlay_tables(pool *p, const table *overlay, const table *base)
 {
-    return append_arrays(p, overlay, base);
+    table *res;
+
+    res = palloc(p, sizeof(table));
+    res->hash_bits = overlay->hash_bits | base->hash_bits;
+    /* behave like append_arrays */
+    res->a.pool = p;
+    copy_array_hdr_core(&res->a, &overlay->a);
+    array_cat(&res->a, &base->a);
+
+    return res;
 }
 
 /* And now for something completely abstract ...
@@ -840,7 +932,7 @@
 {
     va_list vp;
     char *argp;
-    table_entry *elts = (table_entry *) t->elts;
+    table_entry *elts = (table_entry *) t->a.elts;
     int rv, i;
 
     va_start(vp, t);
@@ -848,7 +940,7 @@
     argp = va_arg(vp, char *);
 
     do {
-	for (rv = 1, i = 0; rv && (i < t->nelts); ++i) {
+	for (rv = 1, i = 0; rv && (i < t->a.nelts); ++i) {
 	    if (elts[i].key && (!argp || !strcasecmp(elts[i].key, argp))) {
 		rv = (*comp) (rec, elts[i].key, elts[i].val);
 	    }
Index: main/alloc.h
===================================================================
RCS file: /export/home/cvs/apachen/src/main/alloc.h,v
retrieving revision 1.38
diff -u -r1.38 alloc.h
--- alloc.h	1998/01/07 16:45:59	1.38
+++ alloc.h	1998/01/11 11:37:49
@@ -107,13 +107,13 @@
  * Common enough to want common support code ...
  */
 
-     typedef struct {
-	 pool *pool;
-	 int elt_size;
-	 int nelts;
-	 int nalloc;
-	 char *elts;
-     } array_header;
+typedef struct {
+    pool *pool;
+    int elt_size;
+    int nelts;
+    int nalloc;
+    char *elts;
+} array_header;
 
 API_EXPORT(array_header *) make_array(pool *p, int nelts, int elt_size);
 API_EXPORT(void *) push_array(array_header *);
@@ -139,14 +139,14 @@
  * currently being used...
  */
 
-     typedef array_header table;
+typedef struct table table;
 
-     typedef struct {
-	 char *key;		/* maybe NULL in future;
-				 * check when iterating thru table_elts
-				 */
-	 char *val;
-     } table_entry;
+typedef struct {
+    char *key;		/* maybe NULL in future;
+			 * check when iterating thru table_elts
+			 */
+    char *val;
+} table_entry;
 
 API_EXPORT(table *) make_table(pool *p, int nelts);
 API_EXPORT(table *) copy_table(pool *p, const table *);
@@ -161,9 +161,13 @@
 
 API_EXPORT(table *) overlay_tables(pool *p, const table *overlay, const table *base);
 
-API_EXPORT(array_header *) table_elts(table *);
-
-#define is_empty_table(t) (((t) == NULL)||((t)->nelts == 0))
+/* XXX: these know about the definition of struct table in alloc.c.  That
+ * definition is not here because it is supposed to be private, and by not
+ * placing it here we are able to get compile-time diagnostics from modules
+ * written which assume that a table is the same as an array_header. -djg
+ */
+#define table_elts(t) ((array_header *)(t))
+#define is_empty_table(t) (((t) == NULL)||(((array_header *)(t))->nelts == 0))
 
 /* routines to remember allocation of other sorts of things...
  * generic interface first.  Note that we want to have two separate
Index: main/http_main.c
===================================================================
RCS file: /export/home/cvs/apachen/src/main/http_main.c,v
retrieving revision 1.263
diff -u -r1.263 http_main.c
--- http_main.c	1998/01/07 16:46:06	1.263
+++ http_main.c	1998/01/11 11:37:54
@@ -167,6 +167,13 @@
 
 DEF_Explain
 
+#ifdef GPROF
+extern void moncontrol(int);
+#define MONCONTROL(x) moncontrol(x)
+#else
+#define MONCONTROL(x)
+#endif
+
 #ifndef MULTITHREAD
 /* this just need to be anything non-NULL */
 void *dummy_mutex = &dummy_mutex;
@@ -3181,6 +3188,7 @@
 
     if (!pid) {
 	RAISE_SIGSTOP(MAKE_CHILD);
+	MONCONTROL(1);
 	/* Disable the restart signal handlers and enable the just_die stuff.
 	 * Note that since restart() just notes that a restart has been
 	 * requested there's no race condition here.
@@ -3376,8 +3384,12 @@
     is_graceful = 0;
     ++generation;
 
-    if (!one_process)
+    if (!one_process) {
 	detach();
+    }
+    else {
+	MONCONTROL(1);
+    }
 
     my_pid = getpid();
 
@@ -3587,6 +3599,8 @@
 int main(int argc, char *argv[])
 {
     int c;
+
+    MONCONTROL(0);
 
 #ifdef AUX
     (void) set42sig();
Index: modules/standard/mod_cgi.c
===================================================================
RCS file: /export/home/cvs/apachen/src/modules/standard/mod_cgi.c,v
retrieving revision 1.65
diff -u -r1.65 mod_cgi.c
--- mod_cgi.c	1998/01/07 16:46:46	1.65
+++ mod_cgi.c	1998/01/11 11:37:59
@@ -190,7 +190,7 @@
 static int log_script(request_rec *r, cgi_server_conf * conf, int ret,
 		  char *dbuf, char *sbuf, BUFF *script_in, BUFF *script_err)
 {
-    table *hdrs_arr = r->headers_in;
+    array_header *hdrs_arr = table_elts(r->headers_in);
     table_entry *hdrs = (table_entry *) hdrs_arr->elts;
     char argsbuffer[HUGE_STRING_LEN];
     FILE *f;
@@ -227,7 +227,7 @@
     }
 
     fputs("%response\n", f);
-    hdrs_arr = r->err_headers_out;
+    hdrs_arr = table_elts(r->err_headers_out);
     hdrs = (table_entry *) hdrs_arr->elts;
 
     for (i = 0; i < hdrs_arr->nelts; ++i) {
Index: modules/standard/mod_env.c
===================================================================
RCS file: /export/home/cvs/apachen/src/modules/standard/mod_env.c,v
retrieving revision 1.18
diff -u -r1.18 mod_env.c
--- mod_env.c	1998/01/07 16:46:48	1.18
+++ mod_env.c	1998/01/11 11:37:59
@@ -124,6 +124,7 @@
 
     table *new_table;
     table_entry *elts;
+    array_header *arr;
 
     int i;
     const char *uenv, *unset;
@@ -140,9 +141,10 @@
 
     new_table = copy_table(p, base->vars);
 
-    elts = (table_entry *) add->vars->elts;
+    arr = table_elts(add->vars);
+    elts = (table_entry *)arr->elts;
 
-    for (i = 0; i < add->vars->nelts; ++i) {
+    for (i = 0; i < arr->nelts; ++i) {
         table_set(new_table, elts[i].key, elts[i].val);
     }
 
Index: modules/standard/mod_include.c
===================================================================
RCS file: /export/home/cvs/apachen/src/modules/standard/mod_include.c,v
retrieving revision 1.62
diff -u -r1.62 mod_include.c
--- mod_include.c	1998/01/08 03:16:48	1.62
+++ mod_include.c	1998/01/11 11:38:00
@@ -2013,14 +2013,15 @@
 {
     char tag[MAX_STRING_LEN];
     char *tag_val;
-    table_entry *elts = (table_entry *) r->subprocess_env->elts;
+    array_header *arr = table_elts(r->subprocess_env);
+    table_entry *elts = (table_entry *) arr->elts;
     int i;
 
     if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
         return 1;
     }
     else if (!strcmp(tag, "done")) {
-        for (i = 0; i < r->subprocess_env->nelts; ++i) {
+        for (i = 0; i < arr->nelts; ++i) {
             rvputs(r, elts[i].key, "=", elts[i].val, "\n", NULL);
         }
         return 0;
Index: modules/standard/mod_negotiation.c
===================================================================
RCS file: /export/home/cvs/apachen/src/modules/standard/mod_negotiation.c,v
retrieving revision 1.63
diff -u -r1.63 mod_negotiation.c
--- mod_negotiation.c	1998/01/07 16:46:54	1.63
+++ mod_negotiation.c	1998/01/11 11:38:01
@@ -1811,7 +1811,7 @@
     int vary_by_language = 0;
     int vary_by_charset = 0;
     int vary_by_encoding = 0;
-    array_header *hdrs;
+    table *hdrs;
 
     /* Put headers into err_headers_out, new send_http_header()
      * outputs both headers_out and err_headers_out */
Index: modules/standard/mod_setenvif.c
===================================================================
RCS file: /export/home/cvs/apachen/src/modules/standard/mod_setenvif.c,v
retrieving revision 1.11
diff -u -r1.11 mod_setenvif.c
--- mod_setenvif.c	1998/01/07 16:46:56	1.11
+++ mod_setenvif.c	1998/01/11 11:38:03
@@ -302,9 +302,10 @@
         }
 
         if (!regexec(b->preg, val, 0, NULL, 0)) {
-            elts = (table_entry *) b->features->elts;
+	    array_header *arr = table_elts(b->features);
+            elts = (table_entry *) arr->elts;
 
-            for (j = 0; j < b->features->nelts; ++j) {
+            for (j = 0; j < arr->nelts; ++j) {
                 if (!strcmp(elts[j].val, "!")) {
                     table_unset(r->subprocess_env, elts[j].key);
                 }



Mime
View raw message