performance enhancement to proto.c

Removed the GMemChunk used to allocate/free field_info structures
and used a free list to store the freed structs until they are allocated again.

Ethereal will allocate more field_info structs as it needs to but never free them. Instead the are just placed in a cheap and fast free list so that if we
want to use the struct again, this will be fast.

This affects the speed of the two functions
alloc_field_info() that should be slightly faster now
free_field_info() that was replaced with a 2 line macro.

All in all  my testing suggests that ethereal is 2-3% faster with this patch.

svn path=/trunk/; revision=9073
This commit is contained in:
Ronnie Sahlberg 2003-11-24 21:12:10 +00:00
parent a24a6b7a37
commit fa1ee7667b
2 changed files with 69 additions and 23 deletions

View File

@ -1,7 +1,7 @@
/* proto.c
* Routines for protocol tree
*
* $Id: proto.c,v 1.106 2003/11/22 04:41:31 sahlberg Exp $
* $Id: proto.c,v 1.107 2003/11/24 21:12:10 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@ -154,7 +154,13 @@ static GMemChunk *gmc_hfinfo = NULL;
/* Contains information about a field when a dissector calls
* proto_tree_add_item. */
static GMemChunk *gmc_field_info = NULL;
static field_info *field_info_free_list=NULL;
static field_info *field_info_tmp=NULL;
#define free_field_info(fi) \
fi->next=field_info_free_list; \
field_info_free_list=fi;
/* Contains the space for proto_nodes. */
static GMemChunk *gmc_proto_node = NULL;
@ -204,11 +210,6 @@ proto_init(const char *plugin_dir
INITIAL_NUM_PROTOCOL_HFINFO * sizeof(header_field_info),
G_ALLOC_ONLY);
gmc_field_info = g_mem_chunk_new("gmc_field_info",
sizeof(field_info),
INITIAL_NUM_FIELD_INFO * sizeof(field_info),
G_ALLOC_AND_FREE);
gmc_proto_node = g_mem_chunk_new("gmc_proto_node",
sizeof(proto_node),
INITIAL_NUM_PROTO_NODE * sizeof(proto_node),
@ -279,8 +280,18 @@ proto_cleanup(void)
if (gmc_hfinfo)
g_mem_chunk_destroy(gmc_hfinfo);
if (gmc_field_info)
g_mem_chunk_destroy(gmc_field_info);
while (field_info_free_list) {
field_info *tmpfi;
tmpfi=field_info_free_list->next;
g_free(field_info_free_list);
field_info_free_list=tmpfi;
}
if (field_info_tmp) {
g_free(field_info_tmp);
field_info_tmp=NULL;
}
if (gmc_proto_node)
g_mem_chunk_destroy(gmc_proto_node);
if (gmc_item_labels)
@ -310,13 +321,6 @@ proto_tree_free(proto_tree *tree)
g_node_destroy((GNode*)tree);
}
/* We accept a void* instead of a field_info* to satisfy CLEANUP_POP */
static void
free_field_info(void *fi)
{
g_mem_chunk_free(gmc_field_info, (field_info*)fi);
}
static void
free_GPtrArray_value(gpointer key _U_, gpointer value, gpointer user_data _U_)
{
@ -568,9 +572,28 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
if (new_fi == NULL)
return(NULL);
/* Register a cleanup function in case on of our tvbuff accesses
* throws an exception. We need to clean up new_fi. */
CLEANUP_PUSH(free_field_info, new_fi);
/* there is a possibility here that we might raise an exception
* and thus would lose track of the field_info.
* store it in a temp so that if we come here again we can reclaim
* the field_info without leaking memory.
*/
/* XXX this only keeps track of one field_info struct,
if we ever go multithreaded for calls to this function
we have to change this code to use per thread variable.
*/
if(field_info_tmp){
/* oops, last one we got must have been lost due
* to an exception.
* good thing we saved it, now we can reverse the
* memory leak and reclaim it.
*/
field_info_tmp->next=field_info_free_list;
field_info_free_list=field_info_tmp;
}
/* we might throw an exception, keep track of this one
* across the "dangerous" section below.
*/
field_info_tmp=new_fi;
switch(new_fi->hfinfo->type) {
case FT_NONE:
@ -744,7 +767,10 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
* raised by a tvbuff access method doesn't leave junk in the proto_tree. */
pi = proto_tree_add_node(tree, new_fi);
CLEANUP_POP;
/* we did not raise an exception so we dont have to remember this
* field_info struct any more.
*/
field_info_tmp=NULL;
/* If the proto_tree wants to keep a record of this finfo
* for quick lookup, then record it. */
@ -1873,7 +1899,20 @@ alloc_field_info(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start,
}
}
fi = g_mem_chunk_alloc(gmc_field_info);
if(!field_info_free_list){
int i;
field_info *pfi;
pfi=g_malloc(INITIAL_NUM_FIELD_INFO*sizeof(field_info));
for(i=0;i<INITIAL_NUM_FIELD_INFO;i++){
field_info *tmpfi;
tmpfi=&pfi[i];
tmpfi->next=field_info_free_list;
field_info_free_list=tmpfi;
}
}
fi=field_info_free_list;
field_info_free_list=fi->next;
fi->hfinfo = hfinfo;
fi->start = start;
if (tvb) {

View File

@ -1,7 +1,7 @@
/* proto.h
* Definitions for protocol display
*
* $Id: proto.h,v 1.44 2003/11/21 14:58:49 sahlberg Exp $
* $Id: proto.h,v 1.45 2003/11/24 21:12:10 sahlberg Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
@ -104,7 +104,14 @@ typedef struct hf_register_info {
/* Contains the field information for the proto_item. */
typedef struct field_info {
header_field_info *hfinfo;
union {
/* the next pointer is only used when keeping track of
* free (unallocated) field_infos. Such field_info's
* are never associated with a header_field_info.
*/
struct field_info *next;
header_field_info *hfinfo;
};
gint start;
gint length;
gint tree_type; /* ETT_* */