;;; -*- lexical-binding: t -*- ;; ;; ----------------------------------------------------------------------------- ;; this file: ;; https://dataswamp.org/~incal/emacs-init/ll/ll-el-pa.el ;; ----------------------------------------------------------------------------- (require 'cl-lib) (cl-pushnew (expand-file-name ".") load-path :test #'string=) (require 'luki-lisp) ;; ----------------------------------------------------------------------------- (-> 'benchmark) (-> 'calc-comb) (-> 'eieio) ;; ----------------------------------------------------------------------------- (defclass prop () ((name :initarg :name :type string :initform "prop") (host :initarg :host :type string :initform "localhost") (port :initarg :port :type integer :initform 9999) (proc :initarg :proc :type (or null process) :initform nil) (vrb :initarg :vrb :custom boolean :initform nil) (data :initarg :data :type list :initform nil) (beg-time :initarg :beg-time :type (or null float) :initform nil) (comps :initarg :comps :type list :initform nil))) ;; ----------------------------------------------------------------------------- (defun el-pa-primes-num (beg end &optional vrb) (cl-loop for i from beg to end count (= 1 (calcFunc-prime i)) into res finally do (& vrb ($ "%d" res)) finally return res)) ;; (el-pa-primes-num 1 99 t) ;; ----------------------------------------------------------------------------- (defun el-pa-primes-test (&optional beg end) (let* ((res) (beg (or beg 1)) (end (or end (** 2 22))) (tme (benchmark-elapse (setf res (el-pa-primes-num beg end))))) ($ "[elisp done] %d %.4f" res tme) tme)) ;; (el-pa-primes-test) ;; ----------------------------------------------------------------------------- (cl-defmethod el-pa-compute ((p prop) &optional beg end) (~ (data comps vrb beg-time) p (setf beg-time (float-time)) (cl-loop with comps-num = (& (lu comps) (--- comps)) with beg = (or beg 1) with end = (or end (** 2 22)) with part-size = (/ (- end beg) comps-num) initially (if comps-num (setf data (make-list comps-num 'not-set)) (cl-return "No comp-units")) for c in comps for i from 0 to comps-num for from = (+ beg (* i part-size)) for upto = (+ from part-size) for code = (@f "(%s %d %d)" (symbol-name #'el-pa-primes-num) from upto) do (pcase-let ((`(,name-dst ,host-dst ,port-dst) c)) (when vrb ($ "%s %s %s %s %s" name-dst host-dst port-dst i code)) (el-pa-ask p name-dst host-dst port-dst i code))))) ;; ----------------------------------------------------------------------------- (cl-defmethod el-pa-ask ((p prop) (name-dst string) (host-dst string) (port-dst integer) (i integer) (code string)) (~ (name host port) p (when-let* ((proc (open-network-stream name-dst nil host-dst port-dst)) (msg (@f "%s@%s:%s;%s.%s" name host port i code))) (process-send-string proc msg) (delete-process proc)))) ;; ----------------------------------------------------------------------------- (cl-defmethod el-pa-reply ((_ prop) (name-dst string) (host-dst string) (port-dst integer) (i integer) (ret string)) (when-let* ((proc (open-network-stream name-dst nil host-dst port-dst)) (msg (@f "%d.%s" i ret))) (process-send-string proc msg) (delete-process proc))) ;; ----------------------------------------------------------------------------- (cl-defmethod el-pa-ready ((p prop) (name-dst string) (host-dst string) (port-dst integer)) (~ (name host port) p (when-let* ((proc (open-network-stream name-dst nil host-dst port-dst)) (msg (@f "%s@%s:%s" name host port))) (process-send-string proc msg) (delete-process proc)))) ;; ----------------------------------------------------------------------------- (cl-defmethod el-pa-receive ((p prop) (msg string)) (let ((dta (split-string msg "[@:.;]"))) (pcase-let* ((`(,sender ,host ,port ,idx ,code) dta)) ;; (1) receive as a `comp-', compute (if (& sender host port idx code) (when-let* ((res (@f "%s" (eval (1st (read-from-string code)))))) (el-pa-reply p sender host (string-to-number port) (string-to-number idx) res)) ;; (2) receive as `prop', a comp is ready (if (& sender host port) (~ (comps) p (cl-pushnew (list sender host (string-to-number port)) comps) (when (= 6 (--- comps)) (el-pa-compute p))) ;; (3) receive as `prop', data from a comp (when-let* ((ridx (string-to-number sender)) (res (string-to-number host))) (~ (data beg-time) p (setcar (nthcdr ridx data) res) (unless (cl-find 'not-set data) (let ((r (apply #'+ data))) ($ "[el-pa done] %d %.4f" r (- (float-time) beg-time)) (when noninteractive (delete-process (@ p proc)) (kill-emacs))))))))))) ;; +-------------------------+ ;; | CRAZY SEARCHING THE WEB | ;; | FOR BACK ISSUES OF LOST | ;; | QUALITY ELISP SOFTWARE? | ;; +-------------------------+ (cl-defmethod el-pa-make-proc ((p prop)) (~ (proc name port vrb) p (unless (processp proc) (setf proc (make-network-process :name name :service port :server t :filter (L (_ msg) (when vrb ($ "%s <- [ %s ]" name msg)) (el-pa-receive p msg))))))) ;; ----------------------------------------------------------------------------- (cl-defmethod el-pa-proc-start ((p prop) &optional ready) (unless (@ p proc) (el-pa-make-proc p)) (when ready (pcase-let ((`(,name-dst ,host-dst ,port-dst) ready)) (el-pa-ready p name-dst host-dst port-dst)))) ;; ----------------------------------------------------------------------------- (cl-defmethod el-pa-proc-kill ((p prop)) (~ (proc) p (when proc (delete-process proc)))) ;; ----------------------------------------------------------------------------- (defun el-pa-run-prop () (el-pa-delete-processes "prop") (el-pa-proc-start (prop))) ;; ----------------------------------------------------------------------------- (defun el-pa-delete-processes (prefix) (cl-loop for p in (process-list) for name = (process-name p) do (when (string-prefix-p prefix name) (delete-process p)))) ;; ----------------------------------------------------------------------------- (defun el-pa-run-comp (&optional n beg) (cl-loop with pfx = "comp-" with max = 6 with n = (min (or n max) max) with beg = (or beg 1111) initially (el-pa-delete-processes pfx) for i from 1 to n for name = (@f "%s%d" pfx i) for port = (+ beg i) for eiob = (prop :name name :port port) do (el-pa-proc-start eiob '("prop" "localhost" 9999)))) ;; ----------------------------------------------------------------------------- (defun el-pa-process-list () (i) (let ((ps (process-list))) (cl-case (--- ps) (0 ($ "No processes")) (1 (let ((p (1st ps))) ($ "the only process is %s (%s)" (process-name p) (process-status p)) p)) (t (list-processes))))) (defalias 'ps #'el-pa-process-list) ;; ----------------------------------------------------------------------------- (defun el-pa-test-prop () (el-pa-run-prop) (when noninteractive (sleep-for 10) (el-pa-delete-processes "prop-") (kill-emacs))) (defun el-pa-test-comp (&optional n beg) (el-pa-run-comp n beg) (when noninteractive (sleep-for 10) (el-pa-delete-processes "comp-") (kill-emacs))) ;; ----------------------------------------------------------------------------- ;; START PARALLEL COMPUTING ;; by spawning 1 propagator `prop' and ;; 6 compute-units `comp-1' ... `comp-6' ;; ;; start the propagator: ;; (el-pa-run-prop) ;; ;; start the compute-units: ;; (el-pa-run-comp) ;; ;; +--------------------------------------------+ ;; | el-pa v1 2025-05-02 by efti with luki-lisp | ;; | wanna help? do it today in a different way | ;; +--------------------------------------------+ ;; ;; ----------------------------------------------------------------------------- (<- 'll-el-pa) ;; -----------------------------------------------------------------------------