chicken-hackers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [patch] chicken-install: support building/installing eggs in paralle


From: Pietro Cerutti
Subject: Re: [patch] chicken-install: support building/installing eggs in parallel
Date: Thu, 16 Nov 2023 15:09:41 +0000
User-agent: NeoMutt/20231103-71-942491

I have revised the implementation, see the commit message: the functionality is now self-contained into a (reduce-dag) function that I will also publish as an egg. That'll make it easier to test in isolation and to advance as bugs / new features / optimizations are discovered.

As discussed on IRC, we'll duplicate the code in the egg and in chicken-install. I will take care to poke the maintainers if/when relevant changes are made to the egg (this, always under the assumption that you guys want this feature). Thanks!

On Nov 13 2023, 15:59 UTC, Pietro Cerutti <gahr@gahr.ch> wrote:
See the commit message in the patch attached. Thanks!

--
Pietro Cerutti
I have pledged to give 10% of income to effective charities
and invite you to join me - https://givingwhatwecan.org

From fbc75dc62ccdb39d0b87117a60d069231d1acc58 Mon Sep 17 00:00:00 2001
From: Pietro Cerutti <gahr@gahr.ch>
Date: Mon, 13 Nov 2023 15:22:40 +0000
Subject: [PATCH] chicken-install: support building/installing eggs in parallel

This adds the -j / -max-procs command line argument to chicken-install.
The work scheduler implementation is identical to the one I contributed
for the csm egg [1].

I have tried to keep the diffs to the (install-eggs) function to a
minimum and I avoided reindenting the whole thing, at the cost of a
clumsy "make-egg" definition at the top of the function. I can do it
prettier and produce a larger diff due to whitespace. As you guys
prefer.

As a smoke test, I measured the time it takes to install srfi-19 from a
clean environment with no eggs installed and an empty cache with -j 1
(the default) and -j 4. Time goes down from 5m30.00s to 4m21.98s.
Reasonably good.

[1] http://bugs.call-cc.org/changeset/42311/project
---
chicken-install.scm | 94 +++++++++++++++++++++++++++++++++++++++++----
1 file changed, 86 insertions(+), 8 deletions(-)

diff --git a/chicken-install.scm b/chicken-install.scm
index 56c741db..2d578cad 100644
--- a/chicken-install.scm
+++ b/chicken-install.scm
@@ -97,6 +97,7 @@
(define keepfiles #f)
(define print-repository #f)
(define cached-only #f)
+(define max-procs 1)

(define platform
  (if (eq? (software-version) 'mingw32) 'windows 'unix))
@@ -857,11 +858,79 @@
                       (loop2 (cdr srvs))))))
          (loop1 (cdr eggs)))))))

+(define (to-levels tree topo)
+  (define (depends-on? elem level)
+    (any (lambda (lvl)
+           (let ((adj-list-of-a (assoc elem tree)))
+             (and adj-list-of-a (member lvl adj-list-of-a))))
+         level))
+  (let loop ((topo (reverse topo)) (levs '()))
+    (if (null? topo)
+      levs
+      (if (and (pair? topo) (null? levs))
+        (let ((curr (car topo))
+              (next (cdr topo)))
+          (loop next (list (list curr))))
+        (if (and (pair? topo) (pair? levs))
+          (let ((curr (car topo))
+                (next (cdr topo))
+                (x    (car levs))
+                (y    (cdr levs)))
+            (let lvl-loop ((seen-lvl '())
+                           (cand-lvl '())
+                           (curr-lvl x)
+                           (next-lvl y))
+              (if (depends-on? curr curr-lvl)
+                (loop next
+                      (append seen-lvl
+                              (cons (cons curr cand-lvl)
+                                    (cons curr-lvl next-lvl))))
+                (if (null? next-lvl)
+                  (loop next
+                        (append seen-lvl
+                                (list cand-lvl)
+                                (list (cons curr curr-lvl))))
+
+                  (lvl-loop
+                    (append seen-lvl (if (null? cand-lvl) '() (list cand-lvl)))
+                    curr-lvl
+                    (car next-lvl)
+                    (cdr next-lvl)))))))))))
+
+(cond-expand
+  (windows
+    (define (bfork p) (p))
+    (define (bjoin _) (values #f #f 0)))
+  (else
+    (define bfork process-fork)
+    (define bjoin process-wait)))
+
+(define (spawn levels fun)
+  (define (make-level lvl)
+    (if (eq? 1 max-procs)
+      (for-each fun lvl)
+      (let ((n (length lvl)))
+        (if (eq? n 1)
+          (fun (car lvl))
+          (let ((slots (min n max-procs)))
+            (let loop ((idx 0) (chunk lvl) (pids '()))
+              (if (or (null? chunk) (eq? idx slots))
+                (begin
+                  (for-each
+                    (lambda (x)
+                      (let-values (((pid succ rc) (bjoin x)))
+                        (unless (eq? 0 rc) (exit 1))
+                        succ))
+                    pids)
+                  (unless (null? chunk) (loop 0 chunk '())))
+                (let ((pid (bfork (lambda () (fun (car chunk))))))
+                  (loop (+ 1 idx) (cdr chunk) (cons pid pids))))))))))
+  (for-each make-level levels))

;; perform installation of retrieved eggs

(define (install-eggs)
-  (for-each
+  (define make-egg
    (lambda (egg)
      (let* ((name (car egg))
             (dir (cadr egg))
@@ -928,16 +997,18 @@
                      (run-script dir bscript platform)
                      (unless (if (member name requested-eggs) no-install 
no-install-dependencies)
                        (print "installing " name " (target)")
-                        (run-script dir iscript platform)))))))))
-    (order-installed-eggs)))
+                        (run-script dir iscript platform))))))))))

-(define (order-installed-eggs)
-  (let* ((dag (reverse (sort-dependencies dependencies string=?)))
-         (ordered (filter-map (cut assoc <> canonical-eggs) dag)))
+  (let* ((dag (sort-dependencies dependencies string=?))
+         (lvl (reverse (to-levels dependencies dag))))
    (unless quiet
      (d "install order:~%")
-      (pp dag))
-    ordered))
+      (pp lvl))
+    (spawn
+      lvl
+      (lambda (egg-name)
+        (let ((egg (assoc egg-name canonical-eggs)))
+          (when egg (make-egg egg)))))))

(define (test-egg egg platform)
  (let* ((name (car egg))
@@ -1092,6 +1163,7 @@ usage: chicken-install [OPTION ...] [NAME[:VERSION] ...]
       -force                   don't ask, install even if versions don't match
  -k   -keep                    keep temporary files
  -s   -sudo                    use external command to elevate privileges for 
filesystem operations
+  -j   -max-procs NUM           use NUM processes in parallel for building
  -l   -location DIRECTORY      get egg sources from DIRECTORY.  May be 
provided multiple times.
                                Locations specified on the command line have 
precedence over the
                                ones specified in setup.defaults.
@@ -1201,6 +1273,12 @@ EOF
                  ((member arg '("-n" "-no-install"))
                   (set! no-install #t)
                   (loop (cdr args)))
+                  ((member arg '("-j" "-max-procs"))
+                   (when (null? (cdr args))
+                     (fprintf (current-error-port) "-j|-max-procs: missing 
argument.~%")
+                     (exit 1))
+                   (set! max-procs (string->number (cadr args)))
+                   (loop (cddr args)))
                  ((equal? arg "-purge")
                   (set! purge-mode #t)
                   (loop (cdr args)))
--
2.42.0



--
Pietro Cerutti
I have pledged to give 10% of income to effective charities
and invite you to join me - https://givingwhatwecan.org

Attachment: 0001-chicken-install-support-building-installing-eggs-in-.patch
Description: Text document


reply via email to

[Prev in Thread] Current Thread [Next in Thread]