Start hash tables with 7 buckets instead of 17; print more detailed hash stats with -ds; consistently use ErrFp instead of stderr
All checks were successful
Remind unit tests / tests (push) Successful in 32s

This commit is contained in:
Dianne Skoll
2024-12-14 11:52:16 -05:00
parent a19b009f7c
commit 5a2914f6c7
14 changed files with 113 additions and 77 deletions

View File

@@ -1272,7 +1272,7 @@ static void PrintLeft(char const *s, int width, char pad)
buf = calloc(len+1, sizeof(wchar_t));
if (!buf) {
/* Uh-oh... cannot recover */
fprintf(stderr, "%s\n", GetErr(E_NO_MEM));
fprintf(ErrFp, "%s\n", GetErr(E_NO_MEM));
exit(EXIT_FAILURE);
}
}
@@ -1357,7 +1357,7 @@ static void PrintCentered(char const *s, int width, char *pad)
buf = calloc(len+1, sizeof(wchar_t));
if (!buf) {
/* Uh-oh... cannot recover */
fprintf(stderr, "%s\n", GetErr(E_NO_MEM));
fprintf(ErrFp, "%s\n", GetErr(E_NO_MEM));
exit(EXIT_FAILURE);
}
}

View File

@@ -167,17 +167,13 @@ InitDedupeTable(void)
if (hash_table_init(&DedupeTable,
offsetof(DedupeEntry, link),
DedupeHashFunc, CompareDedupes) < 0) {
fprintf(stderr, "Unable to initialize function hash table: Out of memory. Exiting.\n");
fprintf(ErrFp, "Unable to initialize function hash table: Out of memory. Exiting.\n");
exit(1);
}
}
void
get_dedupe_hash_stats(int *total, int *maxlen, double *avglen)
dump_dedupe_hash_stats(void)
{
struct hash_table_stats s;
hash_table_get_stats(&DedupeTable, &s);
*total = s.num_entries;
*maxlen = s.max_len;
*avglen = s.avg_len;
hash_table_dump_stats(&DedupeTable, ErrFp);
}

View File

@@ -3088,10 +3088,10 @@ int DoCoerce(char type, Value *v)
/***************************************************************/
void print_expr_nodes_stats(void)
{
fprintf(stderr, " Expression nodes allocated: %d\n", ExprNodesAllocated);
fprintf(stderr, "Expression nodes high-water: %d\n", ExprNodesHighWater);
fprintf(stderr, " Expression nodes leaked: %d\n", ExprNodesUsed);
fprintf(stderr, " Parse level high-water: %d\n", parse_level_high_water);
fprintf(ErrFp, " Expression nodes allocated: %d\n", ExprNodesAllocated);
fprintf(ErrFp, "Expression nodes high-water: %d\n", ExprNodesHighWater);
fprintf(ErrFp, " Expression nodes leaked: %d\n", ExprNodesUsed);
fprintf(ErrFp, " Parse level high-water: %d\n", parse_level_high_water);
}
/* Return 1 if a value is "true" for its type, 0 if "false" */

View File

@@ -3265,11 +3265,11 @@ static int setenv(char const *varname, char const *val, int overwrite)
{
static char tzbuf[256];
if (strcmp(varname, "TZ")) {
fprintf(stderr, "built-in setenv can only be used with TZ\n");
fprintf(ErrFp, "built-in setenv can only be used with TZ\n");
abort();
}
if (!overwrite) {
fprintf(stderr, "built-in setenv must have overwrite=1\n");
fprintf(ErrFp, "built-in setenv must have overwrite=1\n");
abort();
}
@@ -3287,7 +3287,7 @@ static void unsetenv(char const *varname)
{
static char tzbuf[8];
if (strcmp(varname, "TZ")) {
fprintf(stderr, "built-in unsetenv can only be used with TZ\n");
fprintf(ErrFp, "built-in unsetenv can only be used with TZ\n");
abort();
}
sprintf(tzbuf, "%s", varname);

View File

@@ -63,7 +63,7 @@
* These are used as choices for the number of hash buckets in the table
*/
static size_t bucket_choices[] = {
17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949, 21911, 43853, 87719,
7, 17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949, 21911, 43853, 87719,
175447, 350899, 701819, 1403641, 2807303, 5614657, 11229331, 22458671,
44917381, 89834777, 179669557, 359339171, 718678369, 1437356741 };
@@ -108,6 +108,8 @@ hash_table_init(hash_table *t,
t->hashfunc = hashfunc;
t->compare = compare;
t->buckets = malloc(sizeof(void *) * bucket_choices[0]);
t->num_growths = 0;
t->num_shrinks = 0;
if (!t->buckets) {
return -1;
}
@@ -216,6 +218,11 @@ hash_table_resize(hash_table *t, int dir)
/* Out of memory... just don't resize? */
return 0;
}
if (dir == 1) {
t->num_growths++;
} else {
t->num_shrinks++;
}
for (size_t j=0; j<num_new_buckets; j++) {
new_buckets[j] = NULL;
}

View File

@@ -29,6 +29,8 @@ struct hash_link {
*/
typedef struct {
unsigned int bucket_choice_index; /**< Index into array of possible bucket counts */
size_t num_growths; /**< How many times have we grown the hash table? */
size_t num_shrinks; /**< How many times have we grown the hash table? */
size_t num_entries; /**< Number of entries in the hash table */
size_t hash_link_offset; /**< Offset of the struct hash_link in the container */
void **buckets; /**< Array of buckets */
@@ -45,6 +47,8 @@ struct hash_table_stats {
size_t num_nonempty_buckets; /**< Number of non-emptry buckets */
size_t max_len; /**< Length of longest chain in the hash table */
size_t min_len; /**< Length of the shortest chain in the hash table */
size_t num_growths; /**< How many times have we grown the hash table? */
size_t num_shrinks; /**< How many times have we grown the hash table? */
double avg_len; /**< Average chain length */
double avg_nonempty_len; /**< Average chain length of non-empty bucket */
double stddev; /**< Standard deviation of chain lengths */

View File

@@ -33,14 +33,15 @@ hash_table_dump_stats(hash_table *t, FILE *fp)
{
struct hash_table_stats stat;
hash_table_get_stats(t, &stat);
fprintf(fp, "#Entries: %lu\n#Buckets: %lu\n#Non-empty Buckets: %lu\n",
fprintf(fp, " Entries: %lu; Buckets: %lu; Non-empty Buckets: %lu\n",
(unsigned long) stat.num_entries,
(unsigned long) stat.num_buckets,
(unsigned long) stat.num_nonempty_buckets);
fprintf(fp, "Max len: %lu\nMin len: %lu\nAvg len: %.4f\nStd dev: %.4f\nAvg nonempty len: %.4f\n",
fprintf(fp, " Maxlen: %lu; Minlen: %lu; Avglen: %.3f; Stddev: %.3f; Avg nonempty len: %.3f\n",
(unsigned long) stat.max_len,
(unsigned long) stat.min_len,
stat.avg_len, stat.stddev, stat.avg_nonempty_len);
fprintf(fp, " Growths: %lu; Shrinks: %lu\n", (unsigned long) stat.num_growths, (unsigned long) stat.num_shrinks);
}
/**
@@ -67,6 +68,8 @@ hash_table_get_stats(hash_table *t, struct hash_table_stats *stat)
stat->stddev = 0.0;
stat->num_nonempty_buckets = 0;
stat->avg_nonempty_len = 0.0;
stat->num_growths = t->num_growths;
stat->num_shrinks = t->num_shrinks;
double sum = 0.0;
double sumsq = 0.0;

View File

@@ -149,7 +149,7 @@ static char const *DefaultFilename(void)
s = getenv("HOME");
if (!s) {
fprintf(stderr, "HOME environment variable not set. Unable to determine reminder file.\n");
fprintf(ErrFp, "HOME environment variable not set. Unable to determine reminder file.\n");
exit(EXIT_FAILURE);
}
DBufPuts(&default_filename_buf, s);
@@ -237,7 +237,7 @@ void InitRemind(int argc, char const *argv[])
InvokedAsRem = 1;
}
} else {
fprintf(stderr, "Invoked with a NULL argv[0]; bailing because that's just plain bizarre.\n");
fprintf(ErrFp, "Invoked with a NULL argv[0]; bailing because that's just plain bizarre.\n");
exit(EXIT_FAILURE);
}
@@ -577,7 +577,7 @@ void InitRemind(int argc, char const *argv[])
/* -wt means get width from /dev/tty */
ttyfd = open("/dev/tty", O_RDONLY);
if (ttyfd < 0) {
fprintf(stderr, "%s: `-wt': Cannot open /dev/tty: %s\n",
fprintf(ErrFp, "%s: `-wt': Cannot open /dev/tty: %s\n",
argv[0], strerror(errno));
} else {
InitCalWidthAndFormWidth(ttyfd);
@@ -728,7 +728,7 @@ void InitRemind(int argc, char const *argv[])
default:
if (tok.type == T_Illegal && tok.val < 0) {
fprintf(stderr, "%s: `%s'\n", GetErr(-tok.val), arg);
fprintf(ErrFp, "%s: `%s'\n", GetErr(-tok.val), arg);
Usage();
}
Usage();
@@ -1018,7 +1018,7 @@ AddTrustedUser(char const *username)
{
struct passwd *pwent;
if (NumTrustedUsers >= MAX_TRUSTED_USERS) {
fprintf(stderr, "Too many trusted users (%d max)\n",
fprintf(ErrFp, "Too many trusted users (%d max)\n",
MAX_TRUSTED_USERS);
exit(EXIT_FAILURE);
}

View File

@@ -60,19 +60,21 @@ exitfunc(void)
/* Kill any execution-time-limiter process */
unlimit_execution_time();
int maxlen, total;
double avglen;
if (DebugFlag & DB_PARSE_EXPR) {
fflush(stdout);
fflush(stderr);
get_var_hash_stats(&total, &maxlen, &avglen);
fprintf(stderr, " Var hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
get_userfunc_hash_stats(&total, &maxlen, &avglen);
fprintf(stderr, " Func hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
get_dedupe_hash_stats(&total, &maxlen, &avglen);
fprintf(stderr, "Dedup hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
get_translation_hash_stats(&total, &maxlen, &avglen);
fprintf(stderr, "Trans hash: total = %d; maxlen = %d; avglen = %.3f\n", total, maxlen, avglen);
fflush(ErrFp);
fprintf(ErrFp, "Variable hash table statistics:\n");
dump_var_hash_stats();
fprintf(ErrFp, "Function hash table statistics:\n");
dump_userfunc_hash_stats();
fprintf(ErrFp, "Dedupe hash table statistics:\n");
dump_dedupe_hash_stats();
fprintf(ErrFp, "Translation hash table statistics:\n");
dump_translation_hash_stats();
UnsetAllUserFuncs();
print_expr_nodes_stats();
}
@@ -128,7 +130,7 @@ int main(int argc, char *argv[])
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
if (sigaction(SIGALRM, &act, NULL) < 0) {
fprintf(stderr, "%s: sigaction() failed: %s\n",
fprintf(ErrFp, "%s: sigaction() failed: %s\n",
argv[0], strerror(errno));
exit(1);
}
@@ -137,7 +139,7 @@ int main(int argc, char *argv[])
act.sa_flags = SA_RESTART;
sigemptyset(&act.sa_mask);
if (sigaction(SIGXCPU, &act, NULL) < 0) {
fprintf(stderr, "%s: sigaction() failed: %s\n",
fprintf(ErrFp, "%s: sigaction() failed: %s\n",
argv[0], strerror(errno));
exit(1);
}

View File

@@ -256,10 +256,10 @@ void print_builtinfunc_tokens(void);
void print_remind_tokens(void);
/* Stats for -ds output */
void get_var_hash_stats(int *total, int *maxlen, double *avglen);
void get_userfunc_hash_stats(int *total, int *maxlen, double *avglen);
void get_dedupe_hash_stats(int *total, int *maxlen, double *avglen);
void get_translation_hash_stats(int *total, int *maxlen, double *avglen);
void dump_var_hash_stats(void);
void dump_userfunc_hash_stats(void);
void dump_dedupe_hash_stats(void);
void dump_translation_hash_stats(void);
/* Dedupe code */
int ShouldDedupe(int trigger_date, int trigger_time, char const *body);

View File

@@ -202,7 +202,7 @@ InitTranslationTable(void)
{
if (hash_table_init(&TranslationTable, offsetof(XlateItem, link),
HashXlateItem, CompareXlateItems) < 0) {
fprintf(stderr, "Unable to initialize translation hash table: Out of memory. Exiting.\n");
fprintf(ErrFp, "Unable to initialize translation hash table: Out of memory. Exiting.\n");
exit(1);
}
InsertTranslation("LANGID", "en");
@@ -386,12 +386,8 @@ DoTranslate(ParsePtr p)
}
void
get_translation_hash_stats(int *total, int *maxlen, double *avglen)
dump_translation_hash_stats(void)
{
struct hash_table_stats s;
hash_table_get_stats(&TranslationTable, &s);
*total = s.num_entries;
*maxlen = s.max_len;
*avglen = s.avg_len;
hash_table_dump_stats(&TranslationTable, ErrFp);
}

View File

@@ -56,7 +56,7 @@ InitUserFunctions(void)
offsetof(UserFunc, link),
HashUserFunc,
CompareUserFuncs) < 0) {
fprintf(stderr, "Unable to initialize function hash table: Out of memory. Exiting.\n");
fprintf(ErrFp, "Unable to initialize function hash table: Out of memory. Exiting.\n");
exit(1);
}
}
@@ -506,12 +506,8 @@ RenameUserFunc(char const *oldname, char const *newname)
}
void
get_userfunc_hash_stats(int *total, int *maxlen, double *avglen)
dump_userfunc_hash_stats(void)
{
struct hash_table_stats s;
hash_table_get_stats(&FuncHash, &s);
*total = s.num_entries;
*maxlen = s.max_len;
*avglen = s.avg_len;
hash_table_dump_stats(&FuncHash, ErrFp);
}

View File

@@ -56,7 +56,7 @@ InitVars(void)
{
if (hash_table_init(&VHashTbl, offsetof(Var, link),
VarHashFunc, VarCompareFunc) < 0) {
fprintf(stderr, "Unable to initialize variable hash table: Out of memory. Exiting.\n");
fprintf(ErrFp, "Unable to initialize variable hash table: Out of memory. Exiting.\n");
exit(1);
}
}
@@ -723,7 +723,7 @@ int DoDump(ParsePtr p)
/* */
/* DumpVarTable */
/* */
/* Dump the variable table to stderr. */
/* Dump the variable table to ErrFp. */
/* */
/***************************************************************/
void DumpVarTable(void)
@@ -1249,11 +1249,7 @@ print_sysvar_tokens(void)
}
void
get_var_hash_stats(int *total, int *maxlen, double *avglen)
dump_var_hash_stats(void)
{
struct hash_table_stats s;
hash_table_get_stats(&VHashTbl, &s);
*total = s.num_entries;
*maxlen = s.max_len;
*avglen = s.avg_len;
hash_table_dump_stats(&VHashTbl, ErrFp);
}

View File

@@ -16127,8 +16127,8 @@ TRANSLATE "January" "translated-January"
TRANSLATE "Tuesday" "translated-Tuesday"
TRANSLATE "November" "translated-November"
TRANSLATE "tomorrow" "translated-Tomorrow"
TRANSLATE "today" "translated-Today"
TRANSLATE "is" "translated-Is"
TRANSLATE "today" "translated-Today"
TRANSLATE "from now" "translated-Fromnow"
TRANSLATE "Friday" "translated-Friday"
TRANSLATE "am" "translated-Am"
@@ -16139,8 +16139,8 @@ TRANSLATE "pm" "translated-Pm"
TRANSLATE "August" "translated-August"
TRANSLATE "May" "translated-May"
TRANSLATE "February" "translated-February"
TRANSLATE "on" "translated-On"
TRANSLATE "now" "translated-Now"
TRANSLATE "on" "translated-On"
$Ago is otherway-Ago
$Am is otherway-Am
$And is otherway-And
@@ -16238,10 +16238,22 @@ D'oh, a file whose name has spaces! ../tests/with space.rem
DEBUG -e
Var hash: total = 100141; maxlen = 5; avglen = 1.142
Func hash: total = 100016; maxlen = 5; avglen = 1.140
Dedup hash: total = 10000; maxlen = 7; avglen = 1.828
Trans hash: total = 1; maxlen = 1; avglen = 0.059
Variable hash table statistics:
Entries: 100141; Buckets: 87719; Non-empty Buckets: 66299
Maxlen: 5; Minlen: 0; Avglen: 1.142; Stddev: 0.878; Avg nonempty len: 1.510
Growths: 13; Shrinks: 0
Function hash table statistics:
Entries: 100016; Buckets: 87719; Non-empty Buckets: 63572
Maxlen: 5; Minlen: 0; Avglen: 1.140; Stddev: 0.934; Avg nonempty len: 1.573
Growths: 13; Shrinks: 0
Dedupe hash table statistics:
Entries: 10000; Buckets: 5471; Non-empty Buckets: 4752
Maxlen: 7; Minlen: 0; Avglen: 1.828; Stddev: 1.302; Avg nonempty len: 2.104
Growths: 9; Shrinks: 0
Translation hash table statistics:
Entries: 1; Buckets: 7; Non-empty Buckets: 1
Maxlen: 1; Minlen: 0; Avglen: 0.143; Stddev: 0.350; Avg nonempty len: 1.000
Growths: 0; Shrinks: 0
Expression nodes allocated: 300096
Expression nodes high-water: 300073
Expression nodes leaked: 0
@@ -23707,10 +23719,22 @@ Parsed expression: isany("foo", 1 + 1, 2:00 + 1, '2021-01-01' + 1, '2021-01-01@1
"f" + "oo" => "foo"
isany("foo", 2, 02:01, 2021-01-02, 2021-01-01@14:01, "foo", ?) => 1
No reminders.
Var hash: total = 1; maxlen = 1; avglen = 0.059
Func hash: total = 0; maxlen = 0; avglen = 0.000
Dedup hash: total = 0; maxlen = 0; avglen = 0.000
Trans hash: total = 1; maxlen = 1; avglen = 0.059
Variable hash table statistics:
Entries: 1; Buckets: 7; Non-empty Buckets: 1
Maxlen: 1; Minlen: 0; Avglen: 0.143; Stddev: 0.350; Avg nonempty len: 1.000
Growths: 0; Shrinks: 0
Function hash table statistics:
Entries: 0; Buckets: 7; Non-empty Buckets: 0
Maxlen: 0; Minlen: 0; Avglen: 0.000; Stddev: 0.000; Avg nonempty len: 0.000
Growths: 0; Shrinks: 0
Dedupe hash table statistics:
Entries: 0; Buckets: 7; Non-empty Buckets: 0
Maxlen: 0; Minlen: 0; Avglen: 0.000; Stddev: 0.000; Avg nonempty len: 0.000
Growths: 0; Shrinks: 0
Translation hash table statistics:
Entries: 1; Buckets: 7; Non-empty Buckets: 1
Maxlen: 1; Minlen: 0; Avglen: 0.143; Stddev: 0.350; Avg nonempty len: 1.000
Growths: 0; Shrinks: 0
Expression nodes allocated: 512
Expression nodes high-water: 499
Expression nodes leaked: 0
@@ -24234,10 +24258,22 @@ $Uy
$Was
$Wednesday
No reminders.
Var hash: total = 1; maxlen = 1; avglen = 0.059
Func hash: total = 1; maxlen = 1; avglen = 0.059
Dedup hash: total = 0; maxlen = 0; avglen = 0.000
Trans hash: total = 2; maxlen = 1; avglen = 0.118
Variable hash table statistics:
Entries: 1; Buckets: 7; Non-empty Buckets: 1
Maxlen: 1; Minlen: 0; Avglen: 0.143; Stddev: 0.350; Avg nonempty len: 1.000
Growths: 13; Shrinks: 13
Function hash table statistics:
Entries: 1; Buckets: 7; Non-empty Buckets: 1
Maxlen: 1; Minlen: 0; Avglen: 0.143; Stddev: 0.350; Avg nonempty len: 1.000
Growths: 13; Shrinks: 13
Dedupe hash table statistics:
Entries: 0; Buckets: 7; Non-empty Buckets: 0
Maxlen: 0; Minlen: 0; Avglen: 0.000; Stddev: 0.000; Avg nonempty len: 0.000
Growths: 0; Shrinks: 0
Translation hash table statistics:
Entries: 2; Buckets: 7; Non-empty Buckets: 1
Maxlen: 2; Minlen: 0; Avglen: 0.286; Stddev: 0.700; Avg nonempty len: 2.000
Growths: 13; Shrinks: 13
Expression nodes allocated: 300032
Expression nodes high-water: 300000
Expression nodes leaked: 0