как заставить clisp или sbcl использовать все доступные ядра процессора?

Через удаленное соединение ssh я пытаюсь кросс-компилировать sbcl с помощью clisp. Шаги, которые я выполнил до сих пор, таковы:

Я загрузил самый последний исходный код sbcl (на данный момент sbcl-1.3.7), распаковал его и вошел в исходный каталог.

Затем, чтобы построить его:

root@remotehost:/sbcl-1.3.7# screen 
root@remotehost:/sbcl-1.3.7# sh make.sh --prefix=/usr --dynamic-space-size=2Gb --xc-host='clisp -q'
root@remotehost:/sbcl-1.3.7# Ctrl-A Ctrl-D
[detached from 4486.pts-1.remotehost]r/fun-info-funs.fas
root@remotehost:/sbcl-1.3.7# 

При втором удаленном ssh-подключении к тому же компьютеру top сообщает об использовании процессора на уровне 6%.

nproc говорит, что у меня 16 ядер (это вычислительный движок Google - я никак не мог позволить себе что-то с 16 ядрами :)

В моей среде для MAKEFLAGS установлено значение -j16, но я думаю, что clisp не знает об этом. Как я могу заставить эту сборку использовать все 16 ядер?


person slac.in.the.box    schedule 25.07.2016    source источник


Ответы (2)


Я рекомендую вам использовать библиотеку параллелизма, мне очень нравится библиотека lparallel

У него есть красивые утилиты для распараллеливания вашего кода между всеми процессорами вашей машины. Это пример для моего macbook pro (4 ядра) с использованием SBCL. Существует множество примеров параллелизма и параллелизма Common Lisp здесь

Но давайте создадим пример с родственными lparallel, обратите внимание, что этот пример не является хорошим упражнением в параллелизме, он только для того, чтобы показать силу leparallel и простоту его использования.

Рассмотрим рекурсивную функцию хвоста Фибоначчи из cliki:

(defun fib (n) "Хвост-рекурсивное вычисление n-го элемента последовательности Фибоначчи" (check-type n (integer 0 *)) (labels ((fib-aux (n f1 f2) (if (zerop n) f1 (fib-вспомогательная (1- n) f2 (+ f1 f2))))) (fib-вспомогательная n 0 1)))

Это будет пример алгоритма высокой стоимости вычислений. давайте использовать его:

CL-USER> (time (progn (fib 1000000) nil))
Evaluation took:
  17.833 seconds of real time
  18.261164 seconds of total run time (16.154088 user, 2.107076 system)
  [ Run times consist of 3.827 seconds GC time, and 14.435 seconds non-GC time. ]
  102.40% CPU
  53,379,077,025 processor cycles
  43,367,543,984 bytes consed

NIL

это расчет 1000000-го члена ряда Фибоначчи на моем компьютере.

Давайте, например, вычислим список чисел фибонначи с помощью mapcar:

CL-USER> (time (progn (mapcar #'fib '(1000000 1000001 1000002 1000003)) nil))
Evaluation took:
  71.455 seconds of real time
  73.196391 seconds of total run time (64.662685 user, 8.533706 system)
  [ Run times consist of 15.573 seconds GC time, and 57.624 seconds non-GC time. ]
  102.44% CPU
  213,883,959,679 processor cycles
  173,470,577,888 bytes consed

NIL

У Lparallell есть родственные слова:

Они возвращают те же результаты, что и их аналоги из CL, за исключением случаев, когда параллелизм должен играть роль. Например, premove ведет себя практически так же, как его версия для CL, но por немного отличается. или возвращает результат первой формы, которая оценивается как нечто отличное от нуля, в то время как por может возвращать результат любой такой формы, не равной нулю.

первая загрузка lparallel:

CL-USER> (ql:quickload :lparallel)
To load "lparallel":
  Load 1 ASDF system:
    lparallel
; Loading "lparallel"

(:LPARALLEL)

Итак, в нашем случае единственное, что вам нужно сделать, это изначально ядро ​​с доступным вам количеством ядер:

CL-USER> (setf lparallel:*kernel* (lparallel:make-kernel 4 :name "fibonacci-kernel"))
#<LPARALLEL.KERNEL:KERNEL :NAME "fibonacci-kernel" :WORKER-COUNT 4 :USE-CALLER NIL :ALIVE T :SPIN-COUNT 2000 {1004E1E693}>

а затем запустите родственников из семейства pmap:

CL-USER> (time (progn (lparallel:pmapcar #'fib '(1000000 1000001 1000002 1000003)) nil))
Evaluation took:
  58.016 seconds of real time
  141.968723 seconds of total run time (107.336060 user, 34.632663 system)
  [ Run times consist of 14.880 seconds GC time, and 127.089 seconds non-GC time. ]
  244.71% CPU
  173,655,268,162 processor cycles
  172,916,698,640 bytes consed

NIL

Вы можете видеть, как легко распараллелить эту задачу, у lparallel есть много ресурсов, которые вы можете изучить:

Я также добавляю данные об использовании процессора с первого mapcar и pmapcar на моем Mac:

первая загрузка - это mapcar, а вторая - из lparallel

person anquegi    schedule 23.10.2016

Кросс-компиляция SBCL (также известная как начальная загрузка) выполняется на 100% в ванильном CL, и в стандарте нет ничего о многопоточности или множественных процессах.

Использование прилагаемого бинарного файла SBCL для вашей машины также может не использовать многопоточность, хотя я знаю, что SBCL использует иметь поддержку потоков на языке.

Вам нужно сделать это только в том случае, если вы изменили исходный код SBCL, поскольку последняя поддерживаемая версия обычно уже предварительно скомпилирована. Я сам не компилировал SBCL, но сомневаюсь, что это заняло больше времени, чем мои компиляции Linux в 90-х, которые занимали меньше времени, чем мой ночной сон.

person Sylwester    schedule 26.07.2016
comment
Смутное воспоминание из 2002 года или около того, когда я работал над тем, что в конечном итоге превратилось в текущую диагностику времени компиляции SBCL, заключается в том, что сборка SBCL с нуля занимала ~ 30-40 минут на ноутбуке, который у меня был в то время ( это был 3-4-летний ноутбук Dell с оперативной памятью ~ 1 ГБ, если мне не изменяет память). - person Vatine; 26.07.2016
comment
Спасибо, что сообщили мне, что это невозможно! Правда, компиляция sbcl на моем ThinkPad не занимает много времени (около часа), но вычислительный движок Google превращает часы в минуты на стандартных компиляциях gcc, которые распознают makeflags: я надеялся узнать что-то подобное для lisp. - person slac.in.the.box; 26.07.2016