+/* -----------------------------------------------------------------------------
+ * Hash tables.
+ *
+ * For profiling by module, constructor or closure type we need to be
+ * able to get from a string describing the category to a structure
+ * containing the counters for that category. The strings aren't
+ * unique (although gcc will do a fairly good job of commoning them up
+ * where possible), so we have a many->one mapping.
+ *
+ * We represent the many->one mapping with a hash table. In order to
+ * find the unique counter associated with a string the first time we
+ * encounter a particular string, we need another hash table, mapping
+ * hashed strings to buckets of counters. The string is hashed, then
+ * the bucket is searched for an existing counter for the same
+ * string.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifdef PROFILING
+typedef struct _ctr {
+ const char *str;
+ unsigned long mem_resid;
+ struct _ctr *next;
+ struct _ctr *next_bucket;
+} prof_ctr;
+
+/* Linked list of all existing ctr structs */
+prof_ctr *all_ctrs;
+
+/* Hash table mapping (char *) -> (struct _ctr) */
+HashTable *str_to_ctr;
+
+/* Hash table mapping hash_t (hashed string) -> (struct _ctr) */
+HashTable *hashstr_to_ctrs;
+
+static void
+initHashTables( void )
+{
+ str_to_ctr = allocHashTable();
+ hashstr_to_ctrs = allocHashTable();
+ all_ctrs = NULL;
+}
+
+static prof_ctr *
+strToCtr(const char *str)
+{
+ prof_ctr *ctr;
+
+ ctr = lookupHashTable( str_to_ctr, (W_)str );
+
+ if (ctr != NULL) { return ctr; }
+
+ else {
+ hash_t str_hash = hash_str((char *)str);
+ prof_ctr *prev;
+
+ ctr = lookupHashTable( hashstr_to_ctrs, (W_)str_hash );
+ prev = NULL;
+
+ for (; ctr != NULL; prev = ctr, ctr = ctr->next_bucket ) {
+ if (!strcmp(ctr->str, str)) {
+ insertHashTable( str_to_ctr, (W_)str, ctr );
+#ifdef DEBUG
+ fprintf(stderr,"strToCtr: existing ctr for `%s'\n",str);
+#endif
+ return ctr;
+ }
+ }
+
+ ctr = stgMallocBytes(sizeof(prof_ctr), "strToCtr");
+ ctr->mem_resid = 0;
+ ctr->str = str;
+ ctr->next_bucket = NULL;
+ ctr->next = all_ctrs;
+ all_ctrs = ctr;
+
+#ifdef DEBUG
+ fprintf(stderr,"strToCtr: new ctr for `%s'\n",str);
+#endif
+
+ if (prev != NULL) {
+ prev->next_bucket = ctr;
+ } else {
+ insertHashTable( hashstr_to_ctrs, str_hash, ctr );
+ }
+ insertHashTable( str_to_ctr, (W_)str, ctr);
+ return ctr;
+ }
+}
+
+static void
+clearCtrResid( void )
+{
+ prof_ctr *ctr;
+
+ for (ctr = all_ctrs; ctr != NULL; ctr = ctr->next) {
+ ctr->mem_resid = 0;
+ }
+}
+
+static void
+reportCtrResid(FILE *fp)
+{
+ prof_ctr *ctr;
+
+ for (ctr = all_ctrs; ctr != NULL; ctr = ctr->next) {
+ if (ctr->mem_resid != 0) {
+ fprintf(fp," %s %ld\n", ctr->str, ctr->mem_resid * sizeof(W_));
+ }
+ }
+}
+#endif /* PROFILING */
+
+/* -------------------------------------------------------------------------- */