branch: main
commit 3c4b2fc54acacb8f0ccf29f4182c50f7e594a400
Author: Ludovic Courtès <l...@gnu.org>
AuthorDate: Mon Jul 8 16:22:56 2024 +0200

    utils: Resource pool keeps track of contention.
    
    * src/cuirass/utils.scm (make-resource-pool): Add optional ‘name’
    argument.  Keep track of ‘get’ requests and contention.  Spawn fiber to
    periodically display stats.
    (display-resource-pool-statistics): New procedure.
    * src/cuirass/base.scm (jobset-evaluator): Pass second argument to
    ‘make-resource-pool’.
    * src/cuirass/database.scm (with-database): Likewise.
    * src/cuirass/scripts/remote-server.scm (fetch-worker): Likewise.
---
 src/cuirass/base.scm                  |  2 +-
 src/cuirass/database.scm              |  3 ++-
 src/cuirass/scripts/remote-server.scm |  2 +-
 src/cuirass/utils.scm                 | 40 +++++++++++++++++++++++++++++------
 4 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/src/cuirass/base.scm b/src/cuirass/base.scm
index f9cdf39..2bc9710 100644
--- a/src/cuirass/base.scm
+++ b/src/cuirass/base.scm
@@ -662,7 +662,7 @@ the ID of the new evaluation."
                            (max-parallel-evaluations
                             (current-processor-count)))
   (define pool
-    (make-resource-pool (iota max-parallel-evaluations)))
+    (make-resource-pool (iota max-parallel-evaluations) 'evaluations))
 
   (lambda ()
     (log-info "will perform up to ~a evaluations concurrently"
diff --git a/src/cuirass/database.scm b/src/cuirass/database.scm
index 2780e7a..686ae1c 100644
--- a/src/cuirass/database.scm
+++ b/src/cuirass/database.scm
@@ -385,7 +385,8 @@ dynamic extent."
           (lambda () body ...))
         (define result
           (if (current-scheduler)                 ;fiber context?
-              (parameterize ((%db-connection-pool (make-resource-pool 
connections)))
+              (parameterize ((%db-connection-pool
+                              (make-resource-pool connections 'database)))
                 (thunk))
               (thunk)))
         (close)
diff --git a/src/cuirass/scripts/remote-server.scm 
b/src/cuirass/scripts/remote-server.scm
index 748477a..4bf3da9 100644
--- a/src/cuirass/scripts/remote-server.scm
+++ b/src/cuirass/scripts/remote-server.scm
@@ -329,7 +329,7 @@ directory."
     (make-atomic-box 0))
 
   (lambda ()
-    (let ((pool (make-resource-pool (iota max-parallel-downloads))))
+    (let ((pool (make-resource-pool (iota max-parallel-downloads) 'fetch)))
       (log-info "starting fetch worker with up to ~a concurrent downloads"
                 max-parallel-downloads)
 
diff --git a/src/cuirass/utils.scm b/src/cuirass/utils.scm
index 7061c84..1f78509 100644
--- a/src/cuirass/utils.scm
+++ b/src/cuirass/utils.scm
@@ -59,7 +59,7 @@ value."
       ((_ symbol) value)
       ...)))
 
-(define (make-resource-pool resources)
+(define* (make-resource-pool resources #:optional name)
   "Return a channel implementing a pool over RESOURCES, a list of objects such
 as database connections.  The channel can then be passed to
 'with-resource-from-pool'."
@@ -69,27 +69,55 @@ as database connections.  The channel can then be passed to
   (spawn-fiber
    (lambda ()
      (let loop ((pool resources)
-                (waiters '()))
+                (waiters '())
+                (gets 0)
+                (contended 0))
        (match (get-message channel)
          (('get reply)
           (match pool
             (()
              (log-debug "queuing request on resource pool ~x"
                         (object-address channel))
-             (loop pool (cons reply waiters)))
+             (loop pool (cons reply waiters)
+                   (+ 1 gets) (+ 1 contended)))
             ((head . tail)
              (put-message reply head)
-             (loop tail waiters))))
+             (loop tail waiters
+                   (+ 1 gets) contended))))
          (('put resource)
           (match waiters
             (()
-             (loop (cons resource pool) waiters))
+             (loop (cons resource pool) waiters
+                   gets contended))
             ((rest ... reply)                     ;XXX: linear
              (put-message reply resource)
-             (loop pool rest))))))))
+             (loop pool rest
+                   gets contended))))
+         ('display-stats
+          (if (zero? gets)
+              (log-info "pool '~a' (~a) is unused"
+                        name
+                        (number->string (object-address channel) 16))
+              (log-info "pool '~a' (~a): ~a% contention (~a/~a)"
+                        name
+                        (number->string (object-address channel) 16)
+                        (inexact->exact (round (* 100. (/ contended gets))))
+                        contended gets))
+          (loop pool waiters gets contended))))))
+
+  (spawn-fiber
+   (lambda ()
+     (let loop ()
+       (sleep (* 15 60))
+       (display-resource-pool-statistics channel)
+       (loop))))
 
   channel)
 
+(define (display-resource-pool-statistics pool)
+  "Display statistics about POOL usage."
+  (put-message pool 'display-stats))
+
 (define (call-with-resource-from-pool pool proc)
   "Call PROC with a resource from POOL, blocking until a resource becomes
 available.  Return the resource once PROC has returned."

Reply via email to