Update.
authorUlrich Drepper <drepper@redhat.com>
Sat, 26 Apr 2003 04:15:50 +0000 (04:15 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sat, 26 Apr 2003 04:15:50 +0000 (04:15 +0000)
* nscd/cache.c (cache_search): Keep track of how many chain links
we searched and update table statistics.
(cache_add): Keep track of how many values are in the table.
(prune_cache): Likewise.  Keep track of locking success.
Print messages about removed entries in separate pass.
* nscd/connections.c (handle_request): Don't print debug message here.
The caller will do it.  Keep track of locking success.
(nscd_run): Print debug message.  Also print PID of the client process.
* nscd/nscd.c (start_time): New variable.
(main): Remember start time.
* nscd/nscd.h: Declare start_time.
(struct database): Add more members for new statistics.
* nscd/nscd_stat.c: Add support for sending, receiving, and printing
of new statistics.

13 files changed:
ChangeLog
linuxthreads/descr.h
linuxthreads/pthread.c
linuxthreads/sysdeps/ia64/tcb-offsets.sym
linuxthreads/sysdeps/powerpc/tls.h
linuxthreads/sysdeps/sh/tcb-offsets.sym
linuxthreads/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
linuxthreads/sysdeps/unix/sysv/linux/sh/sysdep-cancel.h
nscd/cache.c
nscd/connections.c
nscd/nscd.c
nscd/nscd.h
nscd/nscd_stat.c

index 6e6c17f..329ea7d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,20 @@
 2003-04-25  Ulrich Drepper  <drepper@redhat.com>
 
+       * nscd/cache.c (cache_search): Keep track of how many chain links
+       we searched and update table statistics.
+       (cache_add): Keep track of how many values are in the table.
+       (prune_cache): Likewise.  Keep track of locking success.
+       Print messages about removed entries in separate pass.
+       * nscd/connections.c (handle_request): Don't print debug message here.
+       The caller will do it.  Keep track of locking success.
+       (nscd_run): Print debug message.  Also print PID of the client process.
+       * nscd/nscd.c (start_time): New variable.
+       (main): Remember start time.
+       * nscd/nscd.h: Declare start_time.
+       (struct database): Add more members for new statistics.
+       * nscd/nscd_stat.c: Add support for sending, receiving, and printing
+       of new statistics.
+
        * sysdeps/posix/getaddrinfo.c: Include <stdbool.h>.
 
 2003-04-22  Jakub Jelinek  <jakub@redhat.com>
index dd496f6..a9aaa55 100644 (file)
@@ -120,14 +120,17 @@ struct _pthread_descr_struct
       union dtv *dtvp;
       pthread_descr self;      /* Pointer to this structure */
       int multiple_threads;
-# define p_multiple_threads(descr) (descr)->p_header.data.multiple_threads
 # ifdef NEED_DL_SYSINFO
       uintptr_t sysinfo;
 # endif
     } data;
     void *__padding[16];
   } p_header;
+# define p_multiple_threads p_header.data.multiple_threads
+#elif TLS_MULTIPLE_THREADS_IN_TCB
+  int p_multiple_threads;
 #endif
+
   pthread_descr p_nextlive, p_prevlive;
                                 /* Double chaining of active threads */
   pthread_descr p_nextwaiting;  /* Next element in the queue holding the thr */
@@ -186,22 +189,7 @@ struct _pthread_descr_struct
 #endif
   size_t p_alloca_cutoff;      /* Maximum size which should be allocated
                                   using alloca() instead of malloc().  */
-  /* New elements must be added at the end before __multiple_threads.  */
-#if TLS_MULTIPLE_THREADS_IN_TCB
-  /* This field here isn't necessarily multiple_threads, which is really
-     the last integer in struct _pthread_descr_struct.  */
-  int __multiple_threads;
-# define p_multiple_threads(descr) \
-  (((union                                                                   \
-     {                                                                       \
-       struct _pthread_descr_struct s;                                       \
-       struct                                                                \
-       {                                                                     \
-        char dummy[sizeof (struct _pthread_descr_struct) - sizeof (int)];    \
-        int multiple_threads;                                                \
-       } m;                                                                  \
-     } *)(descr))->m.multiple_threads)
-#endif
+  /* New elements must be added at the end.  */
 } __attribute__ ((aligned(32))); /* We need to align the structure so that
                                    doubles are aligned properly.  This is 8
                                    bytes on MIPS and 16 bytes on MIPS64.
index 38a9f7d..d13207f 100644 (file)
@@ -571,7 +571,7 @@ int __pthread_initialize_manager(void)
 
   __pthread_multiple_threads = 1;
 #if TLS_MULTIPLE_THREADS_IN_TCB || !defined USE_TLS || !TLS_DTV_AT_TP
-  p_multiple_threads (__pthread_main_thread) = 1;
+  __pthread_main_thread->p_multiple_threads = 1;
 #endif
   *__libc_multiple_threads_ptr = 1;
 
@@ -620,7 +620,7 @@ int __pthread_initialize_manager(void)
 #if !defined USE_TLS || !TLS_DTV_AT_TP
   mgr->p_header.data.tcb = tcbp;
   mgr->p_header.data.self = mgr;
-  p_multiple_threads (mgr) = 1;
+  mgr->p_header.data.multiple_threads = 1;
 #elif TLS_MULTIPLE_THREADS_IN_TCB
   p_multiple_threads (mgr) = 1;
 #endif
index c1d307d..f7793f7 100644 (file)
@@ -3,7 +3,7 @@
 
 --
 #ifdef USE_TLS
-MULTIPLE_THREADS_OFFSET -sizeof(int)
+MULTIPLE_THREADS_OFFSET offsetof (struct _pthread_descr_struct, p_multiple_threads) - sizeof (struct _pthread_descr_struct)
 #else
 MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads)
 #endif
index 55e915e..9bae084 100644 (file)
@@ -32,6 +32,8 @@ typedef union dtv
   void *pointer;
 } dtv_t;
 
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
 #endif /* __ASSEMBLER__ */
 
 #ifdef HAVE_TLS_SUPPORT
index 7537daa..328eb05 100644 (file)
@@ -3,7 +3,7 @@
 
 --
 #ifdef USE_TLS
-MULTIPLE_THREADS_OFFSET ((char *) &p_multiple_threads ((struct _pthread_descr_struct *)0) - (char *) 0)
+MULTIPLE_THREADS_OFFSET offsetof (struct _pthread_descr_struct, p_multiple_threads)
 TLS_PRE_TCB_SIZE       sizeof (struct _pthread_descr_struct)
 #else
 MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads)
index fb6ca06..2d191d1 100644 (file)
@@ -21,8 +21,6 @@
 #include <tls.h>
 #ifndef __ASSEMBLER__
 # include <linuxthreads/internals.h>
-#else
-# include <tcb-offsets.h>
 #endif
 
 #if !defined NOT_IN_libc || defined IS_IN_libpthread
@@ -87,7 +85,7 @@
 
 # ifndef __ASSEMBLER__
 #  define SINGLE_THREAD_P                                              \
-  __builtin_expect (p_multiple_threads (THREAD_SELF) == 0, 1)
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, p_multiple_threads) == 0, 1)
 # else
 #  define SINGLE_THREAD_P                                              \
   lwz 10,MULTIPLE_THREADS_OFFSET(2);                                   \
index 57cced9..e6d0cca 100644 (file)
 # ifndef __ASSEMBLER__
 #  if defined FLOATING_STACKS && USE___THREAD && defined PIC
 #   define SINGLE_THREAD_P \
-  __builtin_expect (p_multiple_threads (THREAD_SELF) == 0, 1)
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF, p_multiple_threads) == 0, 1)
 #  else
 extern int __local_multiple_threads attribute_hidden;
 #   define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1)
index 6492092..10b04c3 100644 (file)
@@ -44,11 +44,14 @@ cache_search (request_type type, void *key, size_t len, struct database *table,
 {
   unsigned long int hash = __nis_hash (key, len) % table->module;
   struct hashentry *work;
+  unsigned long int nsearched = 0;
 
   work = table->array[hash];
 
   while (work != NULL)
     {
+      ++nsearched;
+
       if (type == work->type && len == work->len
          && memcmp (key, work->key, len) == 0 && work->owner == owner)
        {
@@ -58,13 +61,16 @@ cache_search (request_type type, void *key, size_t len, struct database *table,
          else
            ++table->poshit;
 
-         return work;
+         break;
        }
 
       work = work->next;
     }
 
-  return NULL;
+  if (nsearched > table->maxnsearched)
+    table->maxnsearched = nsearched;
+
+  return work;
 }
 
 /* Add a new entry to the cache.  The return value is zero if the function
@@ -109,6 +115,12 @@ cache_add (int type, void *key, size_t len, const void *packet, size_t total,
     ++table->negmiss;
   else if (last)
     ++table->posmiss;
+
+  /* Instead of slowing down the normal process for statistics
+     collection we accept living with some incorrect data.  */
+  unsigned long int nentries = ++table->nentries;
+  if (nentries > table->maxnentries)
+    table->maxnentries = nentries;
 }
 
 /* Walk through the table and remove all entries which lifetime ended.
@@ -165,10 +177,10 @@ prune_cache (struct database *table, time_t now)
 
   /* We run through the table and find values which are not valid anymore.
 
-   Note that for the initial step, finding the entries to be removed,
-   we don't need to get any lock.  It is at all timed assured that the
-   linked lists are set up correctly and that no second thread prunes
-   the cache.  */
+     Note that for the initial step, finding the entries to be removed,
+     we don't need to get any lock.  It is at all timed assured that the
+     linked lists are set up correctly and that no second thread prunes
+     the cache.  */
   do
     {
       struct hashentry *runp = table->array[--cnt];
@@ -195,7 +207,11 @@ prune_cache (struct database *table, time_t now)
 
       /* Now we have to get the write lock since we are about to modify
         the table.  */
-      pthread_rwlock_wrlock (&table->lock);
+      if (__builtin_expect (pthread_rwlock_trywrlock (&table->lock) != 0, 0))
+       {
+         ++table->wrlockdelayed;
+         pthread_rwlock_wrlock (&table->lock);
+       }
 
       while (first <= last)
        {
@@ -208,6 +224,7 @@ prune_cache (struct database *table, time_t now)
                  table->array[first]->dellist = head;
                  head = table->array[first];
                  table->array[first] = head->next;
+                 --table->nentries;
                  if (--mark[first] == 0)
                    break;
                }
@@ -221,6 +238,7 @@ prune_cache (struct database *table, time_t now)
                      head = runp->next;
                      runp->next = head->next;
                      --mark[first];
+                     --table->nentries;
                    }
                  else
                    runp = runp->next;
@@ -232,29 +250,35 @@ prune_cache (struct database *table, time_t now)
       /* It's all done.  */
       pthread_rwlock_unlock (&table->lock);
 
-      /* And another run to free the data.  */
-      do
+      /* One extra pass if we do debugging.  */
+      if (__builtin_expect (debug_level > 0, 0))
        {
-         struct hashentry *old = head;
+         struct hashentry *runp = head;
 
-         if (debug_level > 0)
+         while (runp != NULL)
            {
              char buf[INET6_ADDRSTRLEN];
              const char *str;
 
-             if ((old->type == GETHOSTBYADDR || old->type == GETHOSTBYADDRv6)
-                 && (old->last || old->data == (void *) -1))
+             if (runp->type == GETHOSTBYADDR || runp->type == GETHOSTBYADDRv6)
                {
-                 inet_ntop (old->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
-                            old->key, buf, sizeof (buf));
+                 inet_ntop (runp->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
+                            runp->key, buf, sizeof (buf));
                  str = buf;
                }
              else
-               str = old->last ? old->key : (old->data == (void *) -1
-                                             ? old->key : "???");
+               str = runp->key;
 
-             dbg_log ("remove %s entry \"%s\"", serv2str[old->type], str);
+             dbg_log ("remove %s entry \"%s\"", serv2str[runp->type], str);
+
+             runp = runp->next;
            }
+       }
+
+      /* And another run to free the data.  */
+      do
+       {
+         struct hashentry *old = head;
 
          /* Free the data structures.  */
          if (old->data == (void *) -1)
index 2e87269..3628877 100644 (file)
@@ -256,10 +256,6 @@ invalidate_cache (char *key)
 static void
 handle_request (int fd, request_header *req, void *key, uid_t uid)
 {
-  if (__builtin_expect (debug_level, 0) > 0)
-    dbg_log (_("handle_request: request received (Version = %d)"),
-            req->version);
-
   if (__builtin_expect (req->version, NSCD_VERSION) != NSCD_VERSION)
     {
       if (debug_level > 0)
@@ -309,7 +305,11 @@ cannot handle old request version %d; current version is %d"),
        }
 
       /* Be sure we can read the data.  */
-      pthread_rwlock_rdlock (&db->lock);
+      if (__builtin_expect (pthread_rwlock_tryrdlock (&db->lock) != 0, 0))
+       {
+         ++db->rdlockdelayed;
+         pthread_rwlock_rdlock (&db->lock);
+       }
 
       /* See whether we can handle it from the cache.  */
       cached = (struct hashentry *) cache_search (req->type, key, req->key_len,
@@ -465,6 +465,9 @@ nscd_run (void *p)
          request_header req;
          char buf[256];
          uid_t uid = 0;
+#ifdef SO_PEERCRED
+         pid_t pid = 0;
+#endif
 
          if (__builtin_expect (fd, 0) < 0)
            {
@@ -505,6 +508,17 @@ nscd_run (void *p)
              if (req.type < GETPWBYNAME || req.type > LASTDBREQ
                  || secure[serv2db[req.type]])
                uid = caller.uid;
+
+             pid = caller.pid;
+           }
+         else if (__builtin_expect (debug_level > 0, 0))
+           {
+             struct ucred caller;
+             socklen_t optlen = sizeof (caller);
+
+             if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED,
+                             &caller, &optlen) == 0)
+               pid = caller.pid;
            }
 #endif
 
@@ -535,6 +549,19 @@ nscd_run (void *p)
                  continue;
                }
 
+             if (__builtin_expect (debug_level, 0) > 0)
+               {
+#ifdef SO_PEERCRED
+                 if (pid != 0)
+                   dbg_log (_("\
+handle_request: request received (Version = %d) from PID %ld"),
+                            req.version, (long int) pid);
+                 else
+#endif
+                   dbg_log (_("\
+handle_request: request received (Version = %d)"), req.version);
+               }
+
              /* Phew, we got all the data, now process it.  */
              handle_request (fd, &req, keybuf, uid);
 
index 5844b38..3d55741 100644 (file)
@@ -72,6 +72,8 @@ int secure[lastdb];
 int secure_in_use;
 static const char *conffile = _PATH_NSCDCONF;
 
+time_t start_time;
+
 static int check_pid (const char *file);
 static int write_pid (const char *file);
 
@@ -131,6 +133,9 @@ main (int argc, char **argv)
   if (check_pid (_PATH_NSCDPID))
     error (EXIT_FAILURE, 0, _("already running"));
 
+  /* Remember when we started.  */
+  start_time = time (NULL);
+
   /* Behave like a daemon.  */
   if (go_background)
     {
index f500b15..89ac777 100644 (file)
@@ -77,6 +77,13 @@ struct database
   unsigned long int posmiss;
   unsigned long int negmiss;
 
+  unsigned long int nentries;
+  unsigned long int maxnentries;
+  unsigned long int maxnsearched;
+
+  unsigned long int rdlockdelayed;
+  unsigned long int wrlockdelayed;
+
   struct hashentry **array;
 };
 
@@ -99,6 +106,9 @@ extern int secure_in_use; /* Is one of the above 1 ? */
 /* User name to run server processes as */
 extern const char *server_user;
 
+/* Time the server was started.  */
+extern time_t start_time;
+
 /* Prototypes for global functions.  */
 
 /* nscd.c */
index 2d46278..d55ca74 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998 Free Software Foundation, Inc.
+/* Copyright (c) 1998, 2003 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
 
@@ -46,6 +46,13 @@ struct dbstat
   unsigned long int neghit;
   unsigned long int posmiss;
   unsigned long int negmiss;
+
+  unsigned long int nentries;
+  unsigned long int maxnentries;
+  unsigned long int maxnsearched;
+
+  unsigned long int rdlockdelayed;
+  unsigned long int wrlockdelayed;
 };
 
 /* Record for transmitting statistics.  */
@@ -53,6 +60,7 @@ struct statdata
 {
   char version[sizeof (compilation)];
   int debug_level;
+  time_t runtime;
   int ndbs;
   struct dbstat dbs[lastdb];
 };
@@ -66,6 +74,7 @@ send_stats (int fd, struct database dbs[lastdb])
 
   memcpy (data.version, compilation, sizeof (compilation));
   data.debug_level = debug_level;
+  data.runtime = time (NULL) - start_time;
   data.ndbs = lastdb;
 
   for (cnt = 0; cnt < lastdb; ++cnt)
@@ -79,6 +88,11 @@ send_stats (int fd, struct database dbs[lastdb])
       data.dbs[cnt].neghit = dbs[cnt].neghit;
       data.dbs[cnt].posmiss = dbs[cnt].posmiss;
       data.dbs[cnt].negmiss = dbs[cnt].negmiss;
+      data.dbs[cnt].nentries = dbs[cnt].nentries;
+      data.dbs[cnt].maxnentries = dbs[cnt].maxnentries;
+      data.dbs[cnt].maxnsearched = dbs[cnt].maxnsearched;
+      data.dbs[cnt].rdlockdelayed = dbs[cnt].rdlockdelayed;
+      data.dbs[cnt].wrlockdelayed = dbs[cnt].wrlockdelayed;
     }
 
   if (TEMP_FAILURE_RETRY (write (fd, &data, sizeof (data))) != sizeof (data))
@@ -120,7 +134,7 @@ receive_print_stats (void)
   if (TEMP_FAILURE_RETRY (read (fd, &data, sizeof (data))) != sizeof (data)
       || (memcmp (data.version, compilation, sizeof (compilation)) != 0
          /* Yes, this is an assignment!  */
-         && errno == EINVAL))
+         && (errno = EINVAL)))
     {
       /* Not the right version.  */
       int err = errno;
@@ -131,6 +145,36 @@ receive_print_stats (void)
   printf (_("nscd configuration:\n\n%15d  server debug level\n"),
          data.debug_level);
 
+  /* We know that we can simply subtract time_t values.  */
+  unsigned long int diff = data.runtime;
+  unsigned int ndays = 0;
+  unsigned int nhours = 0;
+  unsigned int nmins = 0;
+  if (diff > 24 * 60 * 60)
+    {
+      ndays = diff / (24 * 60 * 60);
+      diff %= 24 * 60 * 60;
+    }
+  if (diff > 60 * 60)
+    {
+      nhours = diff / (60 * 60);
+      diff %= 60 * 60;
+    }
+  if (diff > 60)
+    {
+      nmins = diff / 60;
+      diff %= 60;
+    }
+  if (ndays != 0)
+    printf (_("%3ud %2uh %2um %2lus  server runtime\n"),
+           ndays, nhours, nmins, diff);
+  else if (nhours != 0)
+    printf (_("    %2uh %2um %2lus  server runtime\n"), nhours, nmins, diff);
+  else if (nmins != 0)
+    printf (_("        %2um %2lus  server runtime\n"), nmins, diff);
+  else
+    printf (_("            %2lus  server runtime\n"), diff);
+
   for (i = 0; i < lastdb; ++i)
     {
       unsigned long int hit = data.dbs[i].poshit + data.dbs[i].neghit;
@@ -153,14 +197,19 @@ receive_print_stats (void)
 
       printf (_("\n%s cache:\n\n"
                "%15s  cache is enabled\n"
-               "%15Zd  suggested size\n"
-               "%15ld  seconds time to live for positive entries\n"
-               "%15ld  seconds time to live for negative entries\n"
-               "%15ld  cache hits on positive entries\n"
-               "%15ld  cache hits on negative entries\n"
-               "%15ld  cache misses on positive entries\n"
-               "%15ld  cache misses on negative entries\n"
-               "%15ld%% cache hit rate\n"
+               "%15Zu  suggested size\n"
+               "%15lu  seconds time to live for positive entries\n"
+               "%15lu  seconds time to live for negative entries\n"
+               "%15lu  cache hits on positive entries\n"
+               "%15lu  cache hits on negative entries\n"
+               "%15lu  cache misses on positive entries\n"
+               "%15lu  cache misses on negative entries\n"
+               "%15lu%% cache hit rate\n"
+               "%15lu  current number of cached values\n"
+               "%15lu  maximum number of cached values\n"
+               "%15lu  maximum chain length searched\n"
+               "%15lu  number of delays on rdlock\n"
+               "%15lu  number of delays on wrlock\n"
                "%15s  check /etc/%s for changes\n"),
              dbnames[i], enabled,
              data.dbs[i].module,
@@ -168,7 +217,10 @@ receive_print_stats (void)
              data.dbs[i].poshit, data.dbs[i].neghit,
              data.dbs[i].posmiss, data.dbs[i].negmiss,
              (100 * hit) / all,
-             check_file, dbnames[i]);
+             data.dbs[i].nentries, data.dbs[i].maxnentries,
+             data.dbs[i].maxnsearched,
+             data.dbs[i].rdlockdelayed,
+             data.dbs[i].wrlockdelayed, check_file, dbnames[i]);
     }
 
   close (fd);