macro.c: replaced repeated bsearch+qsort with BSEARCH, 10x faster startup

"rpmquery rpm" callgrind annotations, previous commit:
86,825,432  PROGRAM TOTALS
33,090,616  ???:0x0000000000033080'2
25,635,193  ???:strcmp
11,530,816  ???:compareMacroName
 7,241,913  ???:memcpy
 2,008,600  ???:0x0000000000033080
 1,734,274  ???:sortMacroTable
   774,941  ???:doDefine
   642,062  ???:0x00000000000714c0
   308,897  ???:0x000000000002a7b0
   308,137  ???:do_lookup_x
   259,615  ???:0x0000000000070c50
   245,388  ???:poptReadConfigFile

"rpmquery rpm" callgrind annotations, this commit:
6,249,372  PROGRAM TOTALS
774,941  ???:doDefine
531,291  ???:addMacro
523,434  ???:0x00000000000714c0
388,985  ???:strcmp
308,897  ???:0x000000000002a7b0
308,098  ???:do_lookup_x
245,388  ???:poptReadConfigFile

"rpmquery rpm" repeated 100 times (user time), previous commit:
3.78s

"rpmquery rpm" repeated 100 times (user time), this commit:
0.40s
This commit is contained in:
Alexey Tourbin 2011-01-05 17:18:42 +03:00
parent f332ec8636
commit 6370ecd629
2 changed files with 44 additions and 110 deletions

View File

@ -104,8 +104,6 @@ int print_expand_trace = 0;
#endif
/*@=exportlocal =exportheadervar@*/
#define MACRO_CHUNK_SIZE 16
/* forward ref */
static int expandMacro(MacroBuf mb)
/*@globals rpmGlobalMacroContext,
@ -136,73 +134,18 @@ _free(/*@only@*/ /*@null@*/ const void * p)
* @param bp 2nd macro entry
* @return result of comparison
*/
static int
static inline int
compareMacroName(const void * ap, const void * bp)
/*@*/
{
MacroEntry ame = *((MacroEntry *)ap);
MacroEntry bme = *((MacroEntry *)bp);
if (ame == NULL && bme == NULL)
return 0;
if (ame == NULL)
return 1;
if (bme == NULL)
return -1;
return strcmp(ame->name, bme->name);
}
/**
* Enlarge macro table.
* @param mc macro context
*/
static void
expandMacroTable(MacroContext mc)
/*@modifies mc @*/
{
if (mc->macroTable == NULL) {
mc->macrosAllocated = MACRO_CHUNK_SIZE;
mc->macroTable = (MacroEntry *)
xmalloc(sizeof(*(mc->macroTable)) * mc->macrosAllocated);
mc->firstFree = 0;
} else {
mc->macrosAllocated += MACRO_CHUNK_SIZE;
mc->macroTable = (MacroEntry *)
xrealloc(mc->macroTable, sizeof(*(mc->macroTable)) *
mc->macrosAllocated);
}
memset(&mc->macroTable[mc->firstFree], 0, MACRO_CHUNK_SIZE * sizeof(*(mc->macroTable)));
}
/**
* Sort entries in macro table.
* @param mc macro context
*/
static void
sortMacroTable(MacroContext mc)
/*@modifies mc @*/
{
int i;
if (mc == NULL || mc->macroTable == NULL)
return;
qsort(mc->macroTable, mc->firstFree, sizeof(*(mc->macroTable)),
compareMacroName);
/* Empty pointers are now at end of table. Reset first free index. */
for (i = 0; i < mc->firstFree; i++) {
if (mc->macroTable[i] != NULL)
continue;
mc->firstFree = i;
break;
}
}
void
rpmDumpMacroTable(MacroContext mc, FILE * fp)
{
int nempty = 0;
int nactive = 0;
if (mc == NULL) mc = rpmGlobalMacroContext;
@ -211,13 +154,8 @@ rpmDumpMacroTable(MacroContext mc, FILE * fp)
fprintf(fp, "========================\n");
if (mc->macroTable != NULL) {
int i;
for (i = 0; i < mc->firstFree; i++) {
MacroEntry me;
if ((me = mc->macroTable[i]) == NULL) {
/* XXX this should never happen */
nempty++;
continue;
}
for (i = 0; i < mc->macroTableSize; i++) {
MacroEntry me = mc->macroTable[i];
fprintf(fp, "%3d%c %s", me->level,
(me->used > 0 ? '=' : ':'), me->name);
if (me->opts && *me->opts)
@ -229,9 +167,11 @@ rpmDumpMacroTable(MacroContext mc, FILE * fp)
}
}
fprintf(fp, _("======================== active %d empty %d\n"),
nactive, nempty);
nactive, 0);
}
#include "bsearch.h"
/**
* Find entry in macro table.
* @param mc macro context
@ -250,7 +190,7 @@ findEntry(MacroContext mc, const char * name, size_t namelen)
char namebuf[1024];
if (mc == NULL) mc = rpmGlobalMacroContext;
if (mc->macroTable == NULL || mc->firstFree == 0)
if (mc->macroTable == NULL || mc->macroTableSize == 0)
return NULL;
if (namelen > 0) {
@ -264,8 +204,8 @@ findEntry(MacroContext mc, const char * name, size_t namelen)
/*@-temptrans -assignexpose@*/
key->name = (char *)name;
/*@=temptrans =assignexpose@*/
ret = (MacroEntry *) bsearch(&key, mc->macroTable, mc->firstFree,
sizeof(*(mc->macroTable)), compareMacroName);
ret = BSEARCH(&key, mc->macroTable, mc->macroTableSize,
sizeof(*(mc->macroTable)), compareMacroName);
/* XXX TODO: find 1st empty slot and return that */
return ret;
}
@ -823,14 +763,12 @@ freeArgs(MacroBuf mb)
return;
/* Delete dynamic macro definitions */
for (i = 0; i < mc->firstFree; i++) {
for (i = 0; i < mc->macroTableSize; i++) {
MacroEntry *mep, me;
int skiptest = 0;
mep = &mc->macroTable[i];
me = *mep;
if (me == NULL) /* XXX this should never happen */
continue;
if (me->level < mb->depth)
continue;
if (strlen(me->name) == 1 && strchr("#*0", *me->name)) {
@ -844,13 +782,14 @@ freeArgs(MacroBuf mb)
#endif
}
popMacro(mep);
if (!(mep && *mep))
if (*mep == NULL)
ndeleted++;
else if (ndeleted) {
mep[-ndeleted] = *mep;
*mep = NULL;
}
}
/* If any deleted macros, sort macro table */
if (ndeleted)
sortMacroTable(mc);
mc->macroTableSize -= ndeleted;
}
/**
@ -1563,26 +1502,24 @@ void
addMacro(MacroContext mc,
const char * n, const char * o, const char * b, int level)
{
MacroEntry * mep;
if (mc == NULL) mc = rpmGlobalMacroContext;
/* If new name, expand macro table */
if ((mep = findEntry(mc, n, 0)) == NULL) {
if (mc->firstFree == mc->macrosAllocated)
expandMacroTable(mc);
if (mc->macroTable != NULL)
mep = mc->macroTable + mc->firstFree++;
}
if (mep != NULL) {
/* Push macro over previous definition */
pushMacro(mep, n, o, b, level);
/* If new name, sort macro table */
if ((*mep)->prev == NULL)
sortMacroTable(mc);
struct MacroEntry_s keybuf = { .name = n };
MacroEntry key = &keybuf;
MacroEntry *mep = BSEARCH(&key, mc->macroTable, mc->macroTableSize,
sizeof(*mc->macroTable), compareMacroName);
if (mep == NULL) {
AUTO_REALLOC(mc->macroTable, mc->macroTableSize, 128);
mep = mc->macroTable + BSEARCH_IDX;
/* move the remaining element to the right */
MacroEntry *destp = mc->macroTable + mc->macroTableSize++;
for (; destp > mep; destp--)
*destp = destp[-1];
*mep = NULL;
}
/* Push macro over previous definition */
pushMacro(mep, n, o, b, level);
}
void
@ -1594,9 +1531,14 @@ delMacro(MacroContext mc, const char * n)
/* If name exists, pop entry */
if ((mep = findEntry(mc, n, 0)) != NULL) {
popMacro(mep);
/* If deleted name, sort macro table */
if (!(mep && *mep))
sortMacroTable(mc);
if (*mep == NULL) {
/* move the remaining element to the left */
MacroEntry *destp = mep;
MacroEntry *endp = mc->macroTable + --mc->macroTableSize;
for (; destp < endp; destp++)
*destp = destp[1];
*destp = NULL;
}
}
}
@ -1623,17 +1565,10 @@ rpmLoadMacros(MacroContext mc, int level)
if (mc == NULL || mc == rpmGlobalMacroContext)
return;
if (mc->macroTable != NULL) {
int i;
for (i = 0; i < mc->firstFree; i++) {
MacroEntry *mep, me;
mep = &mc->macroTable[i];
me = *mep;
if (me == NULL) /* XXX this should never happen */
continue;
addMacro(NULL, me->name, me->opts, me->body, (level - 1));
}
int i;
for (i = 0; i < mc->macroTableSize; i++) {
MacroEntry me = mc->macroTable[i];
addMacro(NULL, me->name, me->opts, me->body, (level - 1));
}
}
@ -1754,7 +1689,7 @@ rpmFreeMacros(MacroContext mc)
if (mc->macroTable != NULL) {
int i;
for (i = 0; i < mc->firstFree; i++) {
for (i = 0; i < mc->macroTableSize; i++) {
MacroEntry me;
while ((me = mc->macroTable[i]) != NULL) {
/* XXX cast to workaround const */

View File

@ -18,8 +18,7 @@ typedef /*@abstract@*/ struct MacroEntry_s {
/*! The structure used to store the set of macros in a context. */
typedef /*@abstract@*/ struct MacroContext_s {
/*@owned@*//*@null@*/ MacroEntry *macroTable; /*!< Macro entry table for context. */
int macrosAllocated;/*!< No. of allocated macros. */
int firstFree; /*!< No. of macros. */
int macroTableSize; /*!< No. of macros. */
} * MacroContext;
/*@-redecl@*/