/racket-5-0-2-bin-i386-osx-mac-dmg/collects/setup/parallel-build.rkt

http://github.com/smorin/f4f.arc · Racket · 140 lines · 128 code · 8 blank · 4 comment · 9 complexity · 687b9807046bafadb7c7662d60a68e4a MD5 · raw file

  1. #lang racket/base
  2. (require compiler/cm
  3. racket/list
  4. racket/match
  5. racket/path
  6. setup/collects
  7. setup/parallel-do
  8. unstable/generics)
  9. (provide parallel-compile
  10. parallel-build-worker)
  11. (define-struct collects-queue (cclst hash collects-dir printer append-error) #:transparent
  12. #:mutable
  13. #:property prop:jobqueue
  14. (define-methods jobqueue
  15. (define (work-done jobqueue work workerid msg)
  16. (match (list work msg)
  17. [(list (list cc file last) (list result-type out err))
  18. (let ([cc-name (cc-name cc)])
  19. (match result-type
  20. [(list 'ERROR msg)
  21. ((collects-queue-append-error jobqueue) cc "making" (exn msg (current-continuation-marks)) out err "error")]
  22. ['DONE
  23. (when (or (not (zero? (string-length out))) (not (zero? (string-length err))))
  24. ((collects-queue-append-error jobqueue) cc "making" null out err "output"))])
  25. (when last ((collects-queue-printer jobqueue) (current-output-port) "made" "~a" cc-name )))]))
  26. ;; assigns a collection to each worker to be compiled
  27. ;; when it runs out of collections, steals work from other workers collections
  28. (define (get-job jobqueue workerid)
  29. (define (hash/first-pair hash)
  30. (match (hash-iterate-first hash)
  31. [#f #f]
  32. [x (cons (hash-iterate-key hash x) (hash-iterate-value hash x))]))
  33. (define (hash-ref!/true hash key thunk)
  34. (hash-ref hash key (lambda ()
  35. (match (thunk)
  36. [#f #f]
  37. [x (hash-set! hash key x) x]))))
  38. (define (take-cc)
  39. (match (collects-queue-cclst jobqueue)
  40. [(list) #f]
  41. [(cons h t)
  42. (set-collects-queue-cclst! jobqueue t)
  43. (list h)]))
  44. (let ([w-hash (collects-queue-hash jobqueue)])
  45. (define (build-job cc file last)
  46. (define (->bytes x)
  47. (cond [(path? x) (path->bytes x)]
  48. [(string? x) (string->bytes/locale x)]))
  49. (let* ([cc-name (cc-name cc)]
  50. [cc-path (cc-path cc)]
  51. [full-path (path->string (build-path cc-path file))])
  52. ;(printf "JOB ~a ~a ~a ~a\n" workerid cc-name cc-path file)
  53. (values (list cc file last) (list cc-name (->bytes cc-path) (->bytes file)))))
  54. (let retry ()
  55. (define (find-job-in-cc cc id)
  56. (match cc
  57. [(list)
  58. (hash-remove! w-hash id) (retry)]
  59. [(list (list cc (list) (list))) ;empty collect
  60. (hash-remove! w-hash id) (retry)]
  61. [(cons (list cc (list) (list)) tail) ;empty parent collect
  62. (hash-set! w-hash id tail) (retry)]
  63. [(cons (list cc (list) subs) tail) ;empty srcs list
  64. (hash-set! w-hash id (append subs tail)) (retry)]
  65. [(cons (list cc (list file) subs) tail)
  66. (hash-set! w-hash id (append subs tail))
  67. (build-job cc file #t)]
  68. [(cons (list cc (cons file ft) subs) tail)
  69. (hash-set! w-hash id (cons (list cc ft subs) tail))
  70. (build-job cc file #f)]))
  71. (match (hash-ref!/true w-hash workerid take-cc)
  72. [#f
  73. (match (hash/first-pair w-hash)
  74. [(cons id cc) (find-job-in-cc cc id)])]
  75. [cc (find-job-in-cc cc workerid)]))))
  76. (define (has-jobs? jobqueue)
  77. (define (hasjob? cct)
  78. (let loop ([cct cct])
  79. (ormap (lambda (x) (or ((length (second x)) . > . 0) (loop (third x)))) cct)))
  80. (or (hasjob? (collects-queue-cclst jobqueue))
  81. (for/or ([cct (in-hash-values (collects-queue-hash jobqueue))])
  82. (hasjob? cct))))
  83. (define (jobs-cnt jobqueue)
  84. (define (count-cct cct)
  85. (let loop ([cct cct])
  86. (apply + (map (lambda (x) (+ (length (second x)) (loop (third x)))) cct))))
  87. (+ (count-cct (collects-queue-cclst jobqueue))
  88. (for/fold ([cnt 0]) ([cct (in-hash-values (collects-queue-hash jobqueue))])
  89. (+ cnt (count-cct cct)))))))
  90. (define (parallel-compile worker-count setup-fprintf append-error collects-tree)
  91. (let ([collects-dir (current-collects-path)])
  92. (setup-fprintf (current-output-port) #f "--- parallel build using ~a processor cores ---" worker-count)
  93. (parallel-do-event-loop #f
  94. values ; identity function
  95. (list (current-executable-path)
  96. "-X"
  97. (path->string collects-dir)
  98. "-l"
  99. "setup/parallel-build-worker.rkt")
  100. (make-collects-queue collects-tree (make-hash) collects-dir setup-fprintf append-error)
  101. worker-count 999999999)))
  102. (define (parallel-build-worker)
  103. (let ([cmc (make-caching-managed-compile-zo)]
  104. [worker-id (read)])
  105. (let loop ()
  106. (match (read)
  107. [(list 'DIE) void]
  108. [(list name dir file)
  109. (let ([dir (bytes->path dir)]
  110. [file (bytes->path file)])
  111. (let ([out-str-port (open-output-string)]
  112. [err-str-port (open-output-string)])
  113. (define (send/resp type)
  114. (let ([msg (list type (get-output-string out-str-port) (get-output-string err-str-port))])
  115. (write msg)))
  116. (let ([cep (current-error-port)])
  117. (define (pp x)
  118. (fprintf cep "COMPILING ~a ~a ~a ~a\n" worker-id name file x))
  119. (with-handlers ([exn:fail? (lambda (x)
  120. (send/resp (list 'ERROR (exn-message x))))])
  121. (parameterize (
  122. [current-namespace (make-base-empty-namespace)]
  123. [current-directory dir]
  124. [current-load-relative-directory dir]
  125. [current-output-port out-str-port]
  126. [current-error-port err-str-port]
  127. ;[manager-compile-notify-handler pp]
  128. )
  129. (cmc (build-path dir file)))
  130. (send/resp 'DONE))))
  131. (flush-output)
  132. (loop))]))))