Provide a decent interface for finding out about the audio cache and
authormdw <mdw>
Sat, 2 Feb 2002 22:43:50 +0000 (22:43 +0000)
committermdw <mdw>
Sat, 2 Feb 2002 22:43:50 +0000 (22:43 +0000)
configuring its capacity.

au.c
au.h
rxglue.c

diff --git a/au.c b/au.c
index 80382b8..5c90186 100644 (file)
--- a/au.c
+++ b/au.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: au.c,v 1.1 2002/02/02 19:16:28 mdw Exp $
+ * $Id: au.c,v 1.2 2002/02/02 22:43:50 mdw Exp $
  *
  * High-level audio subsystem
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: au.c,v $
+ * Revision 1.2  2002/02/02 22:43:50  mdw
+ * Provide a decent interface for finding out about the audio cache and
+ * configuring its capacity.
+ *
  * Revision 1.1  2002/02/02 19:16:28  mdw
  * New audio subsystem.
  *
@@ -68,7 +72,7 @@ static unsigned au_flags = 0;
 static sym_table au_tab;               /* Sample cache, by name */
 static const char *au_dir = AUDIODIR;  /* Directory containing samples */
 static struct { au_data *next, *prev; } au_spare; /* Lists for sample data */
-static size_t au_sz, au_max;           /* Size of cached samples */
+static au_cacheinfo cache;             /* Cache usage information */
 
 #define AU_SPARE ((au_data*)&au_spare)
 #define f_init 1u
@@ -106,18 +110,21 @@ static const char *filename(const char *tag)
 static void prune(void)
 {
   T( trace(T_AU, "au: pruning cache (%lu/%lu)",
-          (unsigned long)au_sz, (unsigned long)au_max); )
-  while (au_sz > au_max && AU_SPARE->next != AU_SPARE) {
+          (unsigned long)cache.sz_total, (unsigned long)cache.sz_max); )
+  while (cache.sz_total > cache.sz_max && AU_SPARE->next != AU_SPARE) {
     au_data *a = AU_SPARE->next;
     au_sample *s = a->s;
     assert(!a->ref);
     AU_SPARE->next = a->next;
     a->next->prev = AU_SPARE;
     s->a = 0;
-    au_sz -= a->sz;
+    cache.sz_spare -= a->sz;
+    cache.sz_total -= a->sz;
+    cache.n_spare--;
+    cache.n_total--;
     ausys_free(a);
     T( trace(T_AU, "au: ... discarded `%s' (%lu/%lu)", SYM_NAME(s),
-            (unsigned long)au_sz, (unsigned long)au_max); )
+            (unsigned long)cache.sz_total, (unsigned long)cache.sz_max); )
   }
 }
 
@@ -149,7 +156,7 @@ void au_init(const char *dir, size_t max)
 
   sym_create(&au_tab);
   AU_SPARE->next = AU_SPARE->prev = AU_SPARE;
-  au_max = max;
+  cache.sz_max = max;
 
   /* --- Initialize the system-specific subsystem --- */
 
@@ -178,6 +185,42 @@ void au_shutdown(void)
   T( trace(T_AU, "au: shutdown ok"); )
 }
 
+/* --- @au_getcacheinfo@ --- *
+ *
+ * Arguments:  @au_cacheinfo *c@ = where to put the information
+ *
+ * Returns:    ---
+ *
+ * Use:                Extracts audio cache information.
+ */
+
+void au_getcacheinfo(au_cacheinfo *c)
+{
+  ausys_lock();
+  *c = cache;
+  ausys_unlock();
+  assert(c->sz_spare + c->sz_queue == c->sz_total);
+  assert(c->n_spare + c->n_queue == c->n_total);
+}
+
+/* --- @au_setcachelimit@ --- *
+ *
+ * Arguments:  @size_t max@ = new cache limit
+ *
+ * Returns:    ---
+ *
+ * Use:                Reconfigures the maximum cache size.  This probably isn't
+ *             very useful, but it was easy...
+ */
+
+void au_setcachelimit(size_t max)
+{
+  ausys_lock();
+  cache.sz_max = max;
+  prune();
+  ausys_unlock();
+}
+
 /* --- @au_find@ --- *
  *
  * Arguments:  @const char *tag@ = sample tag string
@@ -251,6 +294,11 @@ au_data *au_fetch(au_sample *s)
       a->prev->next = a->next;
       a->next->prev = a->prev;
       a->next = a->prev = 0;
+      cache.sz_spare -= a->sz;
+      cache.sz_queue += a->sz;
+      cache.n_spare--;
+      cache.n_queue++;
+      cache.hits++;
     }
     a->ref++;
     T( trace(T_AU, "au: reusing sample `%s'", SYM_NAME(s)); )
@@ -302,7 +350,6 @@ au_data *au_fetch(au_sample *s)
 
   if ((a = ausys_decode(s, d.buf, d.len)) == 0)
     goto fail_0;
-  au_sz += a->sz;
   a->ref = 1;
   a->next = a->prev = 0;
   a->s = s;
@@ -311,6 +358,11 @@ au_data *au_fetch(au_sample *s)
   /* --- Done --- */
 
   ausys_lock();
+  cache.sz_queue += a->sz;
+  cache.sz_total += a->sz;
+  cache.n_queue++;
+  cache.n_total++;
+  cache.misses++;
   prune();
   ausys_unlock();
   goto done;
@@ -385,6 +437,10 @@ void au_free_unlocked(au_data *a)
     a->prev = AU_SPARE->prev;
     AU_SPARE->prev->next = a;
     AU_SPARE->prev = a;
+    cache.sz_queue -= a->sz;
+    cache.sz_spare += a->sz;
+    cache.n_queue--;
+    cache.n_spare++;
     T( trace(T_AU, "au: drop last ref to `%s'", SYM_NAME(a->s)); )
     prune();
   }
diff --git a/au.h b/au.h
index 7678943..891bdf4 100644 (file)
--- a/au.h
+++ b/au.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: au.h,v 1.1 2002/02/02 19:16:28 mdw Exp $
+ * $Id: au.h,v 1.2 2002/02/02 22:43:50 mdw Exp $
  *
  * Audio handling
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: au.h,v $
+ * Revision 1.2  2002/02/02 22:43:50  mdw
+ * Provide a decent interface for finding out about the audio cache and
+ * configuring its capacity.
+ *
  * Revision 1.1  2002/02/02 19:16:28  mdw
  * New audio subsystem.
  *
@@ -93,7 +97,21 @@ typedef struct au_data {
   size_t sz;                           /* Size of sample file data */
 } au_data;
 
-#define AU_CACHEMAX 0x01000000         /* Maximum resident sample data */
+/* --- Audio cache information --- */
+
+typedef struct au_cacheinfo {
+  size_t sz_max;                       /* Maximum allowed cache size */
+  size_t sz_total;                     /* Total size used by samples */
+  size_t sz_spare;                     /* Size used by `spare' samples */
+  size_t sz_queue;                     /* Size used by queued samples */
+  unsigned n_total;                    /* Total number of cached samples */
+  unsigned n_spare;                    /* Number of `spare' samples */
+  unsigned n_queue;                    /* Number of queued samples */
+  unsigned long hits;                  /* Number of cache hits */
+  unsigned long misses;                        /* Number of cache misses */
+} au_cacheinfo;
+
+#define AU_CACHEMAX 0x01000000         /* Default cache maximum size */
 
 /*----- Functions provided ------------------------------------------------*/
 
@@ -120,6 +138,29 @@ extern void au_init(const char */*dir*/, size_t /*max*/);
 
 extern void au_shutdown(void);
 
+/* --- @au_getcacheinfo@ --- *
+ *
+ * Arguments:  @au_cacheinfo *c@ = where to put the information
+ *
+ * Returns:    ---
+ *
+ * Use:                Extracts audio cache information.
+ */
+
+extern void au_getcacheinfo(au_cacheinfo */*c*/);
+
+/* --- @au_setcachelimit@ --- *
+ *
+ * Arguments:  @size_t max@ = new cache limit
+ *
+ * Returns:    ---
+ *
+ * Use:                Reconfigures the maximum cache size.  This probably isn't
+ *             very useful, but it was easy...
+ */
+
+extern void au_setcachelimit(size_t /*max*/);
+
 /* --- @au_find@ --- *
  *
  * Arguments:  @const char *tag@ = sample tag string
index d57d798..75e0f96 100644 (file)
--- a/rxglue.c
+++ b/rxglue.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: rxglue.c,v 1.3 2002/02/02 19:17:41 mdw Exp $
+ * $Id: rxglue.c,v 1.4 2002/02/02 22:43:50 mdw Exp $
  *
  * REXX glue for C core functionality
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: rxglue.c,v $
+ * Revision 1.4  2002/02/02 22:43:50  mdw
+ * Provide a decent interface for finding out about the audio cache and
+ * configuring its capacity.
+ *
  * Revision 1.3  2002/02/02 19:17:41  mdw
  * New audio subsystem.
  *
@@ -575,6 +579,83 @@ static APIRET APIENTRY rxfn_aunum(const char *fn, ULONG ac, RXSTRING *av,
   return (0);
 }
 
+/* --- @AUCACHE([FLAG], [VALUE, ...]@ --- *
+ *
+ * Arguments:  @FLAG@ = operation to perform
+ *
+ * Returns:    Dependent on operation.
+ *
+ * Use:                If @FLAG@ is omitted or `Info', returns audio cache usage
+ *             information as words in the following order:
+ *
+ *               sz_max                Maximum allowed cache size
+ *               sz_total              Total size used by samples
+ *               sz_spare              Size used by `spare' samples
+ *               sz_queue              Size used by queued samples
+ *               n_total               Total number of cached samples
+ *               n_spare               Number of `spare' samples
+ *               n_queue               Number of queued samples
+ *               hits                  Number of cache hits
+ *               misses                Number of cache misses
+ *
+ *             If @FLAG@ is `Max', sets the maximum cache size to the first
+ *             @VALUE@ (if set), and returns the old maximum on its own.
+ *
+ *             If @FLAG@ is `Usage', returns the `sz_*' items, as a list of
+ *             words.
+ *
+ *             If @FLAGS@ is `Numbers', returns the `n_*' items, as a list
+ *             of words.
+ *
+ *             If @FLAGS@ is `Hits', returns `hits' and `misses' as a pair
+ *             of words.
+ */
+
+static APIRET APIENTRY rxfn_aucache(const char *fn, ULONG ac, RXSTRING *av,
+                                   const char *sn, RXSTRING *r)
+{
+  int i = 1;
+  au_cacheinfo c;
+
+  au_getcacheinfo(&c);
+  if (ac < 1 || !av[0].strlength)
+    goto info;
+  switch (av[0].strptr[0]) {
+    case 'i': case 'I': info:
+      rxs_putf(r, "%lu %lu %lu %lu %u %u %u %lu %lu",
+              (unsigned long)c.sz_max, (unsigned long)c.sz_total,
+              (unsigned long)c.sz_spare, (unsigned long)c.sz_queue,
+              c.n_total, c.n_spare, c.n_total, c.hits, c.misses);
+      break;
+    case 'm': case 'M':
+      if (ac > i) {
+       long max;
+       if (rxs_tol(&av[i], &max))
+         return (-1);
+       au_setcachelimit(max);
+       i++;
+      }
+      rxs_putf(r, "%lu", (unsigned long)c.sz_max);
+      break;
+    case 'u': case 'U':
+      rxs_putf(r, "%lu %lu %lu %lu",
+              (unsigned long)c.sz_max, (unsigned long)c.sz_total,
+              (unsigned long)c.sz_spare, (unsigned long)c.sz_queue);
+      break;
+    case 'n': case 'N':
+      rxs_putf(r, "%u %u %u", c.n_total, c.n_spare, c.n_total);
+      break;
+    case 'h': case 'H':
+      rxs_putf(r, "%lu %lu", c.hits, c.misses);
+      break;
+    default:
+      return (-1);
+  }
+  if (i > ac)
+    return (-1);
+  return (0);
+}
+
 /* --- @MILLIWAIT(MILLIS)@ --- *
  *
  * Arguments:  @MILLIS@ = how long (in milliseconds) to wait
@@ -616,6 +697,7 @@ static const struct rxfntab rxfntab[] = {
   { "txready",         rxfn_txready },
   { "auplay",          rxfn_auplay },
   { "aufetch",         rxfn_aufetch },
+  { "aucache",         rxfn_aucache },
   { "aunum",           rxfn_aunum },
   { "milliwait",       rxfn_milliwait },
   { 0,         0 }