Make struct Ban monolithic and improve memory statistics counting.
authorMichael Poole <mdpoole@troilus.org>
Fri, 17 Jun 2005 03:55:13 +0000 (03:55 +0000)
committerMichael Poole <mdpoole@troilus.org>
Fri, 17 Jun 2005 03:55:13 +0000 (03:55 +0000)
git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1427 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

ChangeLog
include/channel.h
ircd/channel.c
ircd/list.c
ircd/m_burst.c
ircd/m_clearmode.c
ircd/s_stats.c

index 4201d70eaf4778936af1b2190d18bc945f9591d1..69692d2b865cba53daf50ea80440a4279d6e7ab8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,47 @@
+2005-05-16  Michael Poole <mdpoole@troilus.org>
+
+       * include/channel.h (struct Ban): Make 'who' and 'banstr' direct
+       arrays, rather than pointers.
+
+       * ircd/channel.c (bans_alloc): New variable to count number of ban
+       structures allocated.
+       (bans_inuse): New variable to count number of ban structures
+       currently in use.
+       (set_banmask): Adapt to changes in struct Ban.
+       (make_ban): Likewise, and update ban counts.
+       (free_ban): Likewise.
+       (bans_send_meminfo): New function.
+       (apply_ban): Adapt to changes in struct Ban.
+       (mode_parse_ban): Likewise.
+       (mode_process_bans): Likewise.
+       (mode_parse): Likewise.
+       (RevealDelayedJoin): Fix brace placement.
+       (CheckDelayedJoins): Fix brace placement and whitespace.
+
+       * ircd/list.c (struct liststats): Add new fields to eliminate the
+       separate count variables.
+       (init_list): Adapt to those changes.
+       (alloc_client): Likewise.
+       (dealloc_client): Likewise.
+       (alloc_connection): Likewise.
+       (dealloc_connection): Likewise.
+       (make_server): Likewise.
+       (remove_client_from_list): Likewise.
+       (verify_client_list): Likewise.
+       (make_link): Likewise.
+       (free_link): Likewise.
+       (send_liststats): New function.
+       (send_listinfo): Rewrite to use new struct liststats layout.
+
+       * ircd/m_burst.c (ms_burst): Adapt to changes in struct Ban.
+
+       * ircd/m_clearmode.c (do_clearmode): Adapt to changes in struct
+       Ban.
+
+       * ircd/s_stats.c (stats_meminfo): Define unconditionally and call
+       bans_send_meminfo().
+       (statsinfo): Always give access to stats_meminfo.
+
 2005-06-16  Michael Poole <mdpoole@troilus.org>
 
        * include/ircd_string.h: Include necessary <string.h> header.
index db347976c6343021ef6dd64ff7ed229541208427..210c4df1c8ecaa381f6dd54c6049b2e246cacce0 100644 (file)
@@ -261,14 +261,14 @@ struct Mode {
 
 /** A single ban for a channel. */
 struct Ban {
-  struct Ban* next;   /**< next ban in the channel */
+  struct Ban* next;           /**< next ban in the channel */
   struct irc_in_addr address; /**< addres for BAN_IPMASK bans */
-  time_t when;        /**< timestamp when ban was added */
-  unsigned short flags; /**< modifier flags for the ban */
-  unsigned char nu_len; /**< length of nick!user part of banstr */
-  unsigned char addrbits; /**< netmask length for BAN_IPMASK bans */
-  char *who;          /**< name of client that set the ban */
-  char *banstr;       /**< hostmask that the ban matches */
+  time_t when;                /**< timestamp when ban was added */
+  unsigned short flags;       /**< modifier flags for the ban */
+  unsigned char nu_len;       /**< length of nick!user part of banstr */
+  unsigned char addrbits;     /**< netmask length for BAN_IPMASK bans */
+  char who[NICKLEN+1];        /**< name of client that set the ban */
+  char banstr[NICKLEN+USERLEN+HOSTLEN+3];  /**< hostmask that the ban matches */
 };
 
 /** Information about a channel */
index 4f30a65e3c6e204238bc0bd7b90c2b6131162731..ff12cc1cae844197758d43e402ced3a381d9f869 100644 (file)
@@ -67,6 +67,10 @@ static unsigned int membershipAllocCount;
 static struct Membership* membershipFreeList;
 /** Freelist for struct Ban*'s */
 static struct Ban* free_bans;
+/** Number of ban structures allocated. */
+static size_t bans_alloc;
+/** Number of ban structures in use. */
+static size_t bans_inuse;
 
 #if !defined(NDEBUG)
 /** return the length (>=0) of a chain of links.
@@ -91,10 +95,8 @@ static void
 set_ban_mask(struct Ban *ban, const char *banstr)
 {
   char *sep;
-  MyFree(ban->banstr);
-  if (!banstr)
-    return;
-  DupString(ban->banstr, banstr);
+  assert(banstr != NULL);
+  ircd_strncpy(ban->banstr, banstr, sizeof(ban->banstr) - 1);
   sep = strrchr(banstr, '@');
   if (sep) {
     ban->nu_len = sep - banstr;
@@ -117,6 +119,9 @@ make_ban(const char *banstr)
   }
   else if (!(ban = MyMalloc(sizeof(*ban))))
     return NULL;
+  else
+    bans_alloc++;
+  bans_inuse++;
   memset(ban, 0, sizeof(*ban));
   set_ban_mask(ban, banstr);
   return ban;
@@ -128,10 +133,22 @@ make_ban(const char *banstr)
 void
 free_ban(struct Ban *ban)
 {
-  MyFree(ban->who);
-  MyFree(ban->banstr);
   ban->next = free_bans;
   free_bans = ban;
+  bans_inuse--;
+}
+
+/** Report ban usage to \a cptr.
+ * @param[in] cptr Client requesting information.
+ */
+void bans_send_meminfo(struct Client *cptr)
+{
+  struct Ban *ban;
+  size_t num_free;
+  for (num_free = 0, ban = free_bans; ban; ban = ban->next)
+    num_free++;
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Bans: inuse %zu(%zu) free %zu alloc %zu",
+            bans_inuse, bans_inuse * sizeof(*ban), num_free, bans_alloc);
 }
 
 /** return the struct Membership* that represents a client on a channel
@@ -2704,8 +2721,6 @@ int apply_ban(struct Ban **banlist, struct Ban *newban, int do_free)
       if (!bmatch(ban, newban)) {
         if (do_free)
           free_ban(newban);
-        else
-          MyFree(newban->banstr);
         return 1;
       }
       if (!(ban->flags & (BAN_OVERLAPPED|BAN_DEL))) {
@@ -2736,14 +2751,10 @@ int apply_ban(struct Ban **banlist, struct Ban *newban, int do_free)
     /* If no matches were found, fail. */
     if (do_free)
       free_ban(newban);
-    else
-      MyFree(newban->banstr);
     return 3;
   }
   if (do_free)
     free_ban(newban);
-  else
-    MyFree(newban->banstr);
   return 4;
 }
 
@@ -2800,9 +2811,8 @@ mode_parse_ban(struct ParseState *state, int *flag_p)
   newban->next = 0;
   newban->flags = ((state->dir == MODE_ADD) ? BAN_ADD : BAN_DEL)
       | (*flag_p == MODE_BAN ? 0 : BAN_EXCEPTION);
-  newban->banstr = NULL;
   set_ban_mask(newban, collapse(pretty_mask(t_str)));
-  newban->who = cli_name(state->sptr);
+  ircd_strncpy(newban->who, cli_name(state->sptr), HOSTLEN);
   newban->when = TStime();
   apply_ban(&state->chptr->banlist, newban, 0);
 }
@@ -2834,12 +2844,12 @@ mode_process_bans(struct ParseState *state)
       count--;
       len -= banlen;
 
-      MyFree(ban->banstr);
-
       continue;
     } else if (ban->flags & BAN_DEL) { /* Deleted a ban? */
+      char *bandup;
+      DupString(bandup, ban->banstr);
       modebuf_mode_string(state->mbuf, MODE_DEL | MODE_BAN,
-                         ban->banstr, 1);
+                         bandup, 1);
 
       if (state->flags & MODE_PARSE_SET) { /* Ok, make it take effect */
        if (prevban) /* clip it out of the list... */
@@ -2849,9 +2859,6 @@ mode_process_bans(struct ParseState *state)
 
        count--;
        len -= banlen;
-
-        ban->banstr = NULL; /* modebuf_mode_string() gave ownership of
-                             * the ban string to state->mbuf */
         free_ban(ban);
 
        changed++;
@@ -2869,7 +2876,6 @@ mode_process_bans(struct ParseState *state)
          !(state->flags & MODE_PARSE_BOUNCE)) {
        count--;
        len -= banlen;
-        MyFree(ban->banstr);
       } else {
        if (state->flags & MODE_PARSE_SET && MyUser(state->sptr) &&
            (len > (feature_int(FEAT_AVBANLEN) * feature_int(FEAT_MAXBANS)) ||
@@ -2878,15 +2884,16 @@ mode_process_bans(struct ParseState *state)
                     ban->banstr);
          count--;
          len -= banlen;
-          MyFree(ban->banstr);
        } else {
+          char *bandup;
          /* add the ban to the buffer */
+          DupString(bandup, ban->banstr);
          modebuf_mode_string(state->mbuf, MODE_ADD | MODE_BAN,
-                             ban->banstr, 1);
+                             bandup, 1);
 
          if (state->flags & MODE_PARSE_SET) { /* create a new ban */
            newban = make_ban(ban->banstr);
-           DupString(newban->who, ban->who);
+            strcpy(newban->who, ban->who);
            newban->when = ban->when;
            newban->flags = ban->flags & BAN_IPMASK;
 
@@ -2902,13 +2909,6 @@ mode_process_bans(struct ParseState *state)
     prevban = ban;
   } /* for (prevban = 0, ban = state->chptr->banlist; ban; ban = nextban) { */
 
-  /* Release all masks of removed bans */
-  for (count = 0; count < state->numbans; ++count) {
-    ban = state->banlist + count;
-    if (ban->flags & BAN_DEL)
-      MyFree(ban->banstr);
-  }
-
   if (changed) /* if we changed the ban list, we must invalidate the bans */
     mode_ban_invalidate(state->chptr);
 }
@@ -3171,7 +3171,7 @@ mode_parse(struct ModeBuf *mbuf, struct Client *cptr, struct Client *sptr,
 
   for (i = 0; i < MAXPARA; i++) { /* initialize ops/voices arrays */
     state.banlist[i].next = 0;
-    state.banlist[i].who = 0;
+    state.banlist[i].who[0] = '\0';
     state.banlist[i].when = 0;
     state.banlist[i].flags = 0;
     state.cli_change[i].flag = 0;
@@ -3502,7 +3502,8 @@ int IsInvited(struct Client* cptr, const void* chptr)
 
 /* RevealDelayedJoin: sends a join for a hidden user */
 
-void RevealDelayedJoin(struct Membership *member) {
+void RevealDelayedJoin(struct Membership *member)
+{
   ClearDelayedJoin(member);
   sendcmdto_channel_butserv_butone(member->user, CMD_JOIN, member->channel, member->user, 0, ":%H",
                                    member->channel);
@@ -3511,14 +3512,15 @@ void RevealDelayedJoin(struct Membership *member) {
 
 /* CheckDelayedJoins: checks and clear +d if necessary */
 
-void CheckDelayedJoins(struct Channel *chan) {
+void CheckDelayedJoins(struct Channel *chan)
+{
   struct Membership *memb2;
-  
+
   if (chan->mode.mode & MODE_WASDELJOINS) {
     for (memb2=chan->members;memb2;memb2=memb2->next_member)
       if (IsDelayedJoin(memb2))
         break;
-    
+
     if (!memb2) {
       /* clear +d */
       chan->mode.mode &= ~MODE_WASDELJOINS;
index 8a567d6cd176c44b021fa726b69bf4508f8bc008..21eab14c8ae7c91fa3974b88d73a7656776cad91 100644 (file)
 #include <unistd.h>  /* close */
 #include <string.h>
 
-#ifdef DEBUGMODE
 /** Stores linked list statistics for various types of lists. */
 static struct liststats {
-  int inuse;
-} clients, connections, users, servs, links;
-#endif
+  size_t alloc; /**< Number of structures ever allocated. */
+  size_t inuse; /**< Number of structures currently in use. */
+  size_t mem;   /**< Memory used by in-use structures. */
+} clients, connections, servs, links;
 
-/** Count of allocated Client structures. */
-static unsigned int clientAllocCount;
 /** Linked list of currently unused Client structures. */
 static struct Client* clientFreeList;
 
-/** Count of allocated Connection structures. */
-static unsigned int connectionAllocCount;
 /** Linked list of currently unused Connection structures. */
 static struct Connection* connectionFreeList;
 
-/** Count of allocated SLink structures. */
-static unsigned int slinkAllocCount;
 /** Linked list of currently unused SLink structures. */
 static struct SLink* slinkFreeList;
 
@@ -87,21 +81,13 @@ void init_list(void)
     cptr = (struct Client*) MyMalloc(sizeof(struct Client));
     cli_next(cptr) = clientFreeList;
     clientFreeList = cptr;
-    ++clientAllocCount;
+    clients.alloc++;
 
     con = (struct Connection*) MyMalloc(sizeof(struct Connection));
     con_next(con) = connectionFreeList;
     connectionFreeList = con;
-    ++connectionAllocCount;
+    connections.alloc++;
   }
-
-#ifdef DEBUGMODE
-  memset(&clients, 0, sizeof(clients));
-  memset(&connections, 0, sizeof(connections));
-  memset(&users, 0, sizeof(users));
-  memset(&servs, 0, sizeof(servs));
-  memset(&links, 0, sizeof(links));
-#endif
 }
 
 /** Allocate a new Client structure.
@@ -115,13 +101,11 @@ static struct Client* alloc_client(void)
 
   if (!cptr) {
     cptr = (struct Client*) MyMalloc(sizeof(struct Client));
-    ++clientAllocCount;
+    clients.alloc++;
   } else
     clientFreeList = cli_next(cptr);
 
-#ifdef DEBUGMODE
   clients.inuse++;
-#endif
 
   memset(cptr, 0, sizeof(struct Client));
 
@@ -136,9 +120,7 @@ static void dealloc_client(struct Client* cptr)
   assert(cli_verify(cptr));
   assert(0 == cli_connect(cptr));
 
-#ifdef DEBUGMODE
   --clients.inuse;
-#endif
 
   cli_next(cptr) = clientFreeList;
   clientFreeList = cptr;
@@ -157,13 +139,11 @@ static struct Connection* alloc_connection(void)
 
   if (!con) {
     con = (struct Connection*) MyMalloc(sizeof(struct Connection));
-    ++connectionAllocCount;
+    connections.alloc++;
   } else
     connectionFreeList = con_next(con);
 
-#ifdef DEBUGMODE
   connections.inuse++;
-#endif
 
   memset(con, 0, sizeof(struct Connection));
   timer_init(&(con_proc(con)));
@@ -197,9 +177,7 @@ static void dealloc_connection(struct Connection* con)
   if (con_listener(con))
     release_listener(con_listener(con));
 
-#ifdef DEBUGMODE
   --connections.inuse;
-#endif
 
   con_next(con) = connectionFreeList;
   connectionFreeList = con;
@@ -337,9 +315,8 @@ struct Server *make_server(struct Client *cptr)
     serv = (struct Server*) MyMalloc(sizeof(struct Server));
     assert(0 != serv);
     memset(serv, 0, sizeof(struct Server)); /* All variables are 0 by default */
-#ifdef  DEBUGMODE
     servs.inuse++;
-#endif
+    servs.alloc++;
     cli_serv(cptr) = serv;
     cli_serv(cptr)->lag = 60000;
     *serv->by = '\0';
@@ -396,9 +373,8 @@ void remove_client_from_list(struct Client *cptr)
       MyFree(cli_serv(cptr)->client_list);
     MyFree(cli_serv(cptr)->last_error_msg);
     MyFree(cli_serv(cptr));
-#ifdef  DEBUGMODE
     --servs.inuse;
-#endif
+    --servs.alloc;
   }
   free_client(cptr);
 }
@@ -442,7 +418,7 @@ void verify_client_list(void)
     assert(cli_prev(client) == prev);
     /* Verify that the list hasn't become circular */
     assert(cli_next(client) != GlobalClientList);
-    assert(visited <= clientAllocCount);
+    assert(visited <= clients.alloc);
     /* Remember what should precede us */
     prev = client;
   }
@@ -461,12 +437,10 @@ struct SLink* make_link(void)
     slinkFreeList = lp->next;
   else {
     lp = (struct SLink*) MyMalloc(sizeof(struct SLink));
-    ++slinkAllocCount;
+    links.alloc++;
   }
   assert(0 != lp);
-#ifdef  DEBUGMODE
   links.inuse++;
-#endif
   return lp;
 }
 
@@ -479,9 +453,7 @@ void free_link(struct SLink* lp)
     lp->next = slinkFreeList;
     slinkFreeList = lp;
   }
-#ifdef  DEBUGMODE
   links.inuse--;
-#endif
 }
 
 /** Add an element to a doubly linked list.
@@ -522,42 +494,54 @@ void remove_dlink(struct DLink **lpp, struct DLink *lp)
   MyFree(lp);
 }
 
-#ifdef  DEBUGMODE
+/** Report memory usage of a list to \a cptr.
+ * @param[in] cptr Client requesting information.
+ * @param[in] lstats List statistics descriptor.
+ * @param[in] itemname Plural name of item type.
+ * @param[in,out] totals If non-null, accumulates item counts and memory usage.
+ */
+void send_liststats(struct Client *cptr, const struct liststats *lstats,
+                    const char *itemname, struct liststats *totals)
+{
+  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":%s: inuse %zu(%zu) alloc %zu",
+            itemname, lstats->inuse, lstats->mem, lstats->alloc);
+  if (totals)
+  {
+    totals->inuse += lstats->inuse;
+    totals->alloc += lstats->alloc;
+    totals->mem += lstats->mem;
+  }
+}
+
 /** Report memory usage of list elements to \a cptr.
  * @param[in] cptr Client requesting information.
  * @param[in] name Unused pointer.
  */
 void send_listinfo(struct Client *cptr, char *name)
 {
-  int inuse = 0, mem = 0, tmp = 0;
-
-  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Clients: inuse: %d(%d)",
-            clients.inuse, tmp = clients.inuse * sizeof(struct Client));
-  mem += tmp;
-  inuse += clients.inuse;
-  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, "Connections: inuse: %d(%d)",
-            connections.inuse,
-            tmp = connections.inuse * sizeof(struct Connection));
-  mem += tmp;
-  inuse += connections.inuse;
-  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Users: inuse: %d(%d)",
-            users.inuse, tmp = users.inuse * sizeof(struct User));
-  mem += tmp;
-  inuse += users.inuse;
-  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Servs: inuse: %d(%d)",
-            servs.inuse, tmp = servs.inuse * sizeof(struct Server));
-  mem += tmp;
-  inuse += servs.inuse;
-  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Links: inuse: %d(%d)",
-            links.inuse, tmp = links.inuse * sizeof(struct SLink));
-  mem += tmp;
-  inuse += links.inuse;
-  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Confs: inuse: %d(%d)",
-            GlobalConfCount, tmp = GlobalConfCount * sizeof(struct ConfItem));
-  mem += tmp;
-  inuse += GlobalConfCount;
-  send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Totals: inuse %d %d",
-            inuse, mem);
-}
+  struct liststats total;
+  struct liststats confs;
+  struct ConfItem *conf;
+
+  memset(&total, 0, sizeof(total));
+
+  clients.mem = clients.inuse * sizeof(struct Client);
+  send_liststats(cptr, &clients, "Clients", &total);
+
+  connections.mem = connections.inuse * sizeof(struct Connection);
+  send_liststats(cptr, &connections, "Connections", &total);
 
-#endif
+  servs.mem = servs.inuse * sizeof(struct Server);
+  send_liststats(cptr, &servs, "Servers", &total);
+
+  links.mem = links.inuse * sizeof(struct SLink);
+  send_liststats(cptr, &links, "Links", &total);
+
+  confs.alloc = GlobalConfCount;
+  confs.mem = confs.alloc * sizeof(GlobalConfCount);
+  for (confs.inuse = 0, conf = GlobalConfList; conf; conf = conf->next)
+    confs.inuse++;
+  send_liststats(cptr, &confs, "Confs", &total);
+
+  send_liststats(cptr, &total, "Totals", NULL);
+}
index d367e35301116187f14fd1620537e7a344d0719d..01be1a6a6c9dc6cf3c524ccb77b2e916e43ad1f5 100644 (file)
@@ -369,9 +369,7 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
              banstr[banpos++] = *ptr;
 
            newban = make_ban(ban); /* create new ban */
-
-            DupString(newban->who, 
-                      cli_name(feature_bool(FEAT_HIS_BANWHO) ? &me : sptr));
+            strcpy(newban->who, "*");
            newban->when = TStime();
 
            newban->flags = BAN_BURSTED; /* set flags */
@@ -550,9 +548,10 @@ int ms_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
 
       /* remove ban from channel */
       if (lp->flags & (BAN_OVERLAPPED | BAN_BURST_WIPEOUT)) {
+        char *bandup;
+        DupString(bandup, lp->banstr);
        modebuf_mode_string(mbuf, MODE_DEL | MODE_BAN,
-                           lp->banstr, 1); /* let it free banstr */
-        lp->banstr = NULL; /* do not free this string */
+                           bandup, 1);
        *lp_p = lp->next; /* clip out of list */
         free_ban(lp);
        continue;
index 8d45c607bc0636f26a21594e6793af7a881d1b3c..bd390f05bce3c73a84aaf971777ffe733401a550 100644 (file)
@@ -177,12 +177,12 @@ do_clearmode(struct Client *cptr, struct Client *sptr, struct Channel *chptr,
    */
   if (del_mode & MODE_BAN) {
     for (link = chptr->banlist; link; link = next) {
+      char *bandup;
       next = link->next;
 
+      DupString(bandup, link->banstr);
       modebuf_mode_string(&mbuf, MODE_DEL | MODE_BAN, /* delete ban */
-                         link->banstr, 1);
-      link->banstr = NULL; /* modebuf_mode_string() gave ownership of
-                            * banstr to mbuf */
+                         bandup, 1);
       free_ban(link);
     }
 
index cf5d039cc480286492f4da8be49d32e7d280ede3..05965e70a7b358ba6c608872f9df8c62d4a8e16e 100644 (file)
@@ -489,7 +489,6 @@ stats_servers_verbose(struct Client* sptr, const struct StatDesc* sd,
   }
 }
 
-#ifdef DEBUGMODE
 /** Display objects allocated (and total memory used by them) for
  * several types of structures.
  * @param[in] to Client requesting statistics.
@@ -499,10 +498,12 @@ stats_servers_verbose(struct Client* sptr, const struct StatDesc* sd,
 static void
 stats_meminfo(struct Client* to, const struct StatDesc* sd, char* param)
 {
+  extern void bans_send_meminfo(struct Client *cptr);
+
   class_send_meminfo(to);
+  bans_send_meminfo(to);
   send_listinfo(to, 0);
 }
-#endif
 
 /** Send a list of available statistics.
  * @param[in] to Client requesting statistics.
@@ -606,11 +607,9 @@ struct StatDesc statsinfo[] = {
   { 'w', "userload", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
     calc_load, 0,
     "Userload statistics." },
-#ifdef DEBUGMODE
   { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
     stats_meminfo, 0,
     "List usage information (Debug only)." },
-#endif
   { 'y', "classes", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_y,
     report_classes, 0,
     "Connection classes." },