;;; -*- lexical-binding: t -*- ;; ;; -------------------------------------------------------------------------------- ;; ;; this file: ;; https://dataswamp.org/~incal/.emacs.d/emacs-init/ll/ll-el-pa.el ;; ;; ----------------------------------------------------------------------------- (require 'cl-lib) (cl-pushnew "." load-path :test #'string=) (require 'luki-lisp) ;; -------------------------------------------------------------------------------- (-> '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) (verbose :initarg :verbose :custom boolean :initform nil) (data :initarg :data :type list :initform nil) (comps :initarg :comps :type list :initform nil) (beg-time :initarg :beg-time :type float :initform 0.0))) ;; ----------------------------------------------------------------------------- (defun el-pa-primes-num (beg end) (cl-loop for i from beg to end count (= 1 (calcFunc-prime i)))) (defun el-pa-primes-num-alt (beg end) (--- (cl-delete-if-not (L (n) (= 1 (calcFunc-prime n))) (number-sequence beg end)))) (defun el-pa-primes-test () (i) (let ((beg (float-time)) (res (el-pa-primes-num 1 (** 2 22)))) ($ "[elisp done] %d %.3f" res (- (float-time) beg)))) ;; (el-pa-primes-test) ;; ----------------------------------------------------------------------------- (cl-defmethod el-pa-compute ((p prop) &optional beg end) (~ (data comps verbose beg-time) p (cl-loop initially (if (! (lu comps)) (cl-return "No comp-units") (setf data (make-list comps-num 'not-set)) (setf beg-time (float-time))) with beg = (or beg 1) with end = (or end (+ beg (** 2 22))) with comps-num = (--- comps) with part-size = (/ (- end beg) comps-num) with i = 0 for c in comps 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 verbose ($ "%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) (++ i))))) ;; ----------------------------------------------------------------------------- (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 ((num (apply #'+ data)) (tme (- (float-time) beg-time))) ($ "[el-pa done] %d %0.3f" num tme) (when noninteractive (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 verbose) p (unless (processp proc) (setf proc (make-network-process :name name :service port :server t :filter (L (_ msg) (when verbose ($ "%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 prefix = "comp-" initially (el-pa-delete-processes prefix) with max = 6 with n = (min (or n max) max) with beg = (or beg 1111) for i from 1 to n for name = (@f "%s%d" prefix 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 () (setq el-pa-kill-when-done t) (el-pa-run-prop) (el-pa-run-comp) (when noninteractive (sleep-for 20) (kill-emacs))) (defun el-pa-test-prop () (setq el-pa-kill-when-done t) (el-pa-run-prop) (sleep-for 20) (kill-emacs)) (defun el-pa-test-comp (&optional n beg) (el-pa-run-comp n beg) (sleep-for 20) (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)