unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: ludo@gnu.org (Ludovic Courtès)
To: guix-devel <guix-devel@gnu.org>
Subject: What’s the weather like?
Date: Fri, 21 Jul 2017 17:13:06 +0200	[thread overview]
Message-ID: <87bmodkem5.fsf@gnu.org> (raw)

[-- Attachment #1: Type: text/plain, Size: 1345 bytes --]

Hello Guix!

Lately we’ve had a lot of nar URLs return 404, mostly for server-side
issues (setup issue on hydra.gnu.org that broke ‘guix publish’ cache
management, and a ‘guix publish’ cache eviction policy that’s too
aggressive.)

The attached tool allows you to query the status a substitute server
(and, as a side effect, triggers a nar regeneration if the server uses
‘guix publish --cache’).  So it goes like this:

--8<---------------cut here---------------start------------->8---
$ ./pre-inst-env guix weather --substitute-urls=https://hydra.gnu.org
computing 5,864 package derivations for x86_64-linux...
looking for 6,121 store items on https://hydra.gnu.org...
updating list of substitutes from 'https://hydra.gnu.org'... 100.0%
https://hydra.gnu.org
  81.2% substitutes available (4,970 out of 6,121)
  17,852.6 MiB of nars (compressed)
  46,415.5 MiB on disk (uncompressed)
  0.050 seconds per request (306.0 seconds in total)
  20.0 requests per second
--8<---------------cut here---------------end--------------->8---

Here it’s telling us that hydra.gnu.org has 81% of the substitutes for
x86_64 of the current public packages (those shown by “guix package
-A”).

We can add multiple -s flags, thought that quickly takes ages,
especially on that box.

Thoughts?

Ludo’.


[-- Attachment #2: the weather program --]
[-- Type: text/plain, Size: 8025 bytes --]

;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2017 Ludovic Courtès <ludo@gnu.org>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (guix scripts weather)
  #:use-module (guix ui)
  #:use-module (guix scripts)
  #:use-module (guix packages)
  #:use-module (guix derivations)
  #:use-module (guix monads)
  #:use-module (guix store)
  #:use-module (guix grafts)
  #:use-module (guix build syscalls)
  #:use-module (guix scripts substitute)
  #:use-module (gnu packages)
  #:use-module (srfi srfi-1)
  #:use-module (srfi srfi-19)
  #:use-module (srfi srfi-37)
  #:use-module (ice-9 match)
  #:use-module (ice-9 format)
  #:export (guix-weather))


(define (all-packages)
  "Return the list of public packages we are going to query."
  (fold-packages (lambda (package result)
                   (match (package-replacement package)
                     ((? package? replacement)
                      (cons* replacement package result))
                     (#f
                      (cons package result))))
                 '()))

(define* (package-outputs packages
                          #:optional (system (%current-system)))
  "Return the list of outputs of all of PACKAGES for the given SYSTEM."
  (define update-progress!
    (let ((total (length packages))
          (done  0)
          (width (max 10 (- (terminal-columns) 10))))
      (lambda ()
        (set! done (+ 1 done))
        (let* ((ratio (/ done total 1.))
               (done  (inexact->exact (round (* width ratio))))
               (left  (- width done)))
          (format (current-error-port) "~5,1f% [~a~a]\r"
                  (* ratio 100.)
                  (make-string done #\#)
                  (make-string left #\space))
          (when (>= done total)
            (newline (current-error-port)))
          (force-output (current-error-port))))))

  (format (current-error-port)
          (G_ "computing ~h package derivations for ~a...~%")
          (length packages) system)

  (foldm %store-monad
         (lambda (package result)
           (mlet %store-monad ((drv (package->derivation package system
                                                         #:graft? #f)))
             (update-progress!)
             (match (derivation->output-paths drv)
               (((names . items) ...)
                (return (append items result))))))
         '()
         packages))

(cond-expand
  (guile-2.2
   ;; Guile 2.2.2 has a bug whereby 'time-monotonic' objects have seconds and
   ;; nanoseconds swapped (fixed in Guile commit 886ac3e).  Work around it.
   (define time-monotonic time-tai))
  (else #t))

(define (call-with-time thunk kont)
  "Call THUNK and pass KONT the elapsed time followed by THUNK's return
values."
  (let* ((start  (current-time time-monotonic))
         (result (call-with-values thunk list))
         (end    (current-time time-monotonic)))
    (apply kont (time-difference end start) result)))

(define-syntax-rule (let/time ((time result exp)) body ...)
  (call-with-time (lambda () exp) (lambda (time result) body ...)))

(define (report-server-coverage server items)
  "Report the subset of ITEMS available as substitutes on SERVER."
  (define MiB (* (expt 2 20) 1.))

  (format #t (G_ "looking for ~h store items on ~a...~%")
          (length items) server)

  (let/time ((time narinfos (lookup-narinfos server items)))
    (format #t "~a~%" server)
    (let ((obtained  (length narinfos))
          (requested (length items))
          (sizes     (filter-map narinfo-file-size narinfos))
          (time      (+ (time-second time)
                        (/ (time-nanosecond time) 1e9))))
      (format #t (G_ "  ~2,1f% substitutes available (~h out of ~h)~%")
              (* 100. (/ obtained requested 1.))
              obtained requested)
      (let ((total (/ (reduce + 0 sizes) MiB)))
        (match (length sizes)
          ((? zero?)
           (format #t (G_  "unknown substitute sizes~%")))
          (len
           (if (= len obtained)
               (format #t (G_ "  ~,1h MiB of nars (compressed)~%") total)
               (format #t (G_ "  at least ~,1h MiB of nars (compressed)~%")
                       total)))))
      (format #t (G_ "  ~,1h MiB on disk (uncompressed)~%")
              (/ (reduce + 0 (map narinfo-size narinfos)) MiB))
      (format #t (G_ "  ~,3h seconds per request (~,1h seconds in total)~%")
              (/ time requested 1.) time)
      (format #t (G_ "  ~,1h requests per second~%")
              (/ requested time 1.)))))

\f
;;;
;;; Command-line options.
;;;

(define (show-help)
  (display (G_ "Usage: guix weather [OPTIONS]
Report the availability of substitutes.\n"))
  (display (G_ "
      --substitute-urls=URLS
                         check for available substitutes at URLS"))
  (display (G_ "
  -s, --system=SYSTEM    consider substitutes for SYSTEM--e.g., \"i686-linux\""))
  (newline)
  (display (G_ "
  -h, --help             display this help and exit"))
  (display (G_ "
  -V, --version          display version information and exit"))
  (newline)
  (show-bug-report-information))

(define %options
  (list  (option '(#\h "help") #f #f
                 (lambda args
                   (show-help)
                   (exit 0)))
         (option '(#\V "version") #f #f
                 (lambda args
                   (show-version-and-exit "guix challenge")))

         (option '("substitute-urls") #t #f
                 (lambda (opt name arg result . rest)
                   (apply values
                          (alist-cons 'substitute-urls
                                      (string-tokenize arg)
                                      (alist-delete 'substitute-urls result))
                          rest)))
         (option '(#\s "system") #t #f
                 (lambda (opt name arg result)
                   (alist-cons 'system arg result)))))

(define %default-options
  `((substitute-urls . ,%default-substitute-urls)))

\f
;;;
;;; Entry point.
;;;

(define (guix-weather . args)
  (with-error-handling
    (let* ((opts     (parse-command-line args %options
                                         (list %default-options)))
           (urls     (assoc-ref opts 'substitute-urls))
           (systems  (match (filter-map (match-lambda
                                          (('system . system) system)
                                          (_ #f))
                                        opts)
                       (() (list (%current-system)))
                       (systems systems)))
           (packages (all-packages))
           (items    (with-store store
                       (parameterize ((%graft? #f))
                         (concatenate
                          (run-with-store store
                            (mapm %store-monad
                                  (lambda (system)
                                    (package-outputs packages system))
                                  systems)))))))
      (for-each (lambda (server)
                  (report-server-coverage server items))
                urls))))

;;; Local Variables:
;;; eval: (put 'let/time 'scheme-indent-function 1)
;;; End:

             reply	other threads:[~2017-07-21 15:13 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-21 15:13 Ludovic Courtès [this message]
2017-07-23  7:25 ` What’s the weather like? Catonano
2017-07-24  9:07   ` Ludovic Courtès
2017-07-24 11:17     ` Vincent Legoll
2017-07-24 13:15       ` Ludovic Courtès
2017-07-24 14:48         ` Vincent Legoll
2017-07-23  7:58 ` Ricardo Wurmus
2017-07-23 10:26   ` Ricardo Wurmus
2017-07-23 11:02     ` Ricardo Wurmus
2017-07-25 10:26       ` Ludovic Courtès
2017-07-26 20:22         ` Alex Kost
2017-07-27  9:06           ` Ludovic Courtès
2017-07-27 11:39           ` Ricardo Wurmus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://guix.gnu.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87bmodkem5.fsf@gnu.org \
    --to=ludo@gnu.org \
    --cc=guix-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).