Алгоритм запуска майнинг-ригов
Риг работает на базе стандартной для Debian 7 системы инициализации sysv. Ключевые сервисы - cron, nodm и скрипт /etc/rc.local.
- nodm отвечает за запуск сессии X.org. Файл /etc/default/nodm сорсится стартовыми скриптами, поэтому представляет собой обычный шелл-скрипт с рядом переменных. В моем случае он слегка модифицирован - в начале добавлена строка
while test ! -e /etc/X11/xorg.conf ; do sleep 0.1 ; done
Иначе говоря, скрипт не выполнится до тех пор, пока не будет существовать файл /etc/X11/xorg.conf - а, если быть точным, то /tmp/xorg.conf, так как /etc/X11/xorg.conf представляет собой симлинк на файл в /tmp. После появления файла стартует X-сервер, где запускается простейшая сессия - xterm.
- /etc/rc.local на сейчас выполняет 2 функции:
- Первая - это сравнение файлов /etc/hostname и файла, размещенного в перезаписываемой области - /mnt/rw/hostname. Если они отличаются, то корневая ФС перемонтируется в RW и содержимое /mnt/rw/hostname копируется в /etc/hostname, после чего корень снова становится RO. Далее выполняется скрипт, заново устанавливающий hostname. Баг: нет гарантии того, что хостнейм установится до запуска основных скриптов.
- Вторая функция - содержимое /home/rain/hashtopus/hashlists_offline/ копируется в оперативную память - каталог /tmp/hashlists/. Использовалось на больших хэшлистах в Hashtopus'е.
- Основной запуск необходимых скриптов происходит из crontab:
@reboot /home/rain/start.sh * * * * * /mnt/rw/rain/bin/monit.sh 1>>/tmp/1 2>>/tmp/2 */10 * * * * rsync -a --delete /tmp/hashlists/ /home/rain/hashtopus/hashlists_offline/
- Основной стартовый скрипт - /home/rain/start.sh - выполняется разово после запуска crond. Содержит в себе установку необходимых переменных, создание конфига для X-сервера (см. выше), монтирование раздела dagstorage и вычитку последнего DAG-файла в кэш, а также запуск screen-сессии. screen-сессия не запускается до тех пор, пока не появится процесс xterm (т.е., пока не будет полностью запущена X-сессия). На время работы этого скрипта создается lock-файл для monit.sh.
- Файл ~/.screenrc содержит в себе перечень команд, служащих для запуска необходимых майнеров и подпрограмм, а также конфигурационные директивы для screen.
- Первая команда - запуск sgminer в обычном режиме. Служит (служил) для основного вида майнинга - через sgminer
- Вторая команда - запуск ffc.sh - скрипта управления частотами и вентиляторами, а также служащего для наблюдения за состоянием карт рига.
- Третья команда - запуск hashtopus.exe - агента распределенной сети перебора хэшей.
- Четвертая команда - запуск скрипта управления ethminerctl в режиме мониторинга - иначе говоря, запуск майнинга Ethereum.
- Кроме того, из crontab запускаются еще 2 команды: файла monit.sh, служащего для контроля работы sgminer при основном виде майнинга и периодический запуск rsync для бэкапа hashlist'ов.
sgminer
sgminer, запускаемый из ~/.screenrc, в качестве параметра принимает файл конфига /home/rain/config/pools.conf, где описывается перечень пулов и специфичных этим пулам настроек, с которым ему необходимо работать. В конце этого конфига подключается файл /home/rain/config/cards.conf, где описываются настройки железа - в частности, частоты видеокарт, а также включается API-интерфейс майнера.
monit.sh
monit.sh служит для отслеживания состояния майнера sgminer через API; уведомления об изменении состояния, а также для остановки майнера в случае переключения рига на перебор хэшей. В качестве параметра принимает 2 значения - lock и unlock, служащие для остановки работы скрипта мониторинга. Стоит заметить, что остановка работы происходит сейчас только при новых попытках запуска скрипта из crond.
Скрипт для работы использует вызов /home/rain/bin/getstat.sh, который в свою очередь использует api-example.py, идущий в комплекте майнера и организовывающий общение с майнером через его API. getstat.sh форматирует вывод API и преобразовывает его в удобочитаемую табличную форму.
Скрипт monit.sh вызывается раз в минуту, однако внутри скрипта внутренний цикл работает с интервалом в 10 секунд. Каждые 10 секунд по данным от getstat.sh проверяются такие параметры:
- Если нет данных от getstat.sh, то какие-то проблемы с API - возможно, майнер не смог запуститься или долго запускается. На первый раз создается файл-флаг /tmp/apifail. Если в течение 5 проверок (т.е., в течение одной минуты) getstat.sh не отдал содержимое, то считается, что API майнера действительно недоступно и риг отправляется на перезагрузку с уведомлением в jabber "API Fail".
- Проверяется наличие процесса sgminer. Если процесса нет - вероятно, произошел segfault и риг отправляется на перезагрузку с уведомлением в jabber. Функциональность данной проверки покрывается функциональностью проверки выше, однако эта более быстрая - перезагрузка срабатывает при первой же недоступности процесса.
- Проверка HW-ошибок в майнере. Если накопилось более 10 ошибок такого типа - делается уведомление в jabber и перезапуск майнера через API посредством /home/rain/bin/api-example.py. Полезно при отслеживании ошибок переразгона.
- Проверка активности карт. Если загрузка карты меньше 80 процентов - в первом случае создаем флаг /tmp/lowact. Если через 5 проверок активность все еще низкая - уведомляем об этом в jabber. Полезно при некоторых зависаниях карт, когда загрузка всех карт, кроме зависшей, просаживается; либо для уведомления о проблемах с пулом.
- Проверка состояния карт. Если состояние не равно Alive, то делается дополнительная проверка. Если больше двух проверок держится состояние Init - делается перезагрузка - такое бывает при некоторых зависаниях карты. Если состояние карты Sick или Dead - то делается безусловная перезагрузка. В обоих случаях делается уведомление в jabber.
- Проверка наличия процесса Hashcat. Его наличие свидетельствует о переключении на перебор хэшей. В таком случае вызывается скрипт /home/rain/bin/gpuoff, выключающий карты в sgminer, после чего их ресурсы становятся полностью доступны для Hashcat.
- Вне 10-секундного цикла выполняется еще одна проверка наличия процесса Hashcat. Если он пропал - включаем карты через скрипт /home/rain/bin/gpuon
ffc.sh
Скрипт служит для замены функций управления частотами и вентиляторами sgminer'а в случае, когда последний недоступен, а также для отображения состояния карт.
Из функций скрипта можно отметить следующие:
- Самостоятельная работа или передача управления функциям контроля в sgminer с автоматическим переключением между режимами.
- Работа с 5 зонами температуры чипа видеокарты
- Зона idle - медленное снижение вращения вентилятора до минимума fmin в случае температуры чипа ниже порога
- Зона fan1 - плавный рост оборотов вентилятора до достижения предела tfan
- Зона fan2 - более быстрый рост оборотов вентилятора до достижения предела fmax
- Зона overheat - установка оборотов на максимум и снижение частот ядра и памяти
- Зона cutoff - установка оборотов на максимум и завершение процессов майнинга
- Переход между зонами idle, fan1 и fan2 делается с учетом гистерезиса, заданного в настройках скрипта. Например, при гистерезисе в 1 градус и границе зоны idle/fan в 65 градусов в диапазоне от 64 до 66 градусов скрипт не будет делать попыток регулировки вентилятора.
- Уведомление в Jabber в случае выхода в зону overheat или cutoff
- Отображение температур карт, скорости вентиляторов, частот, а также загрузки с цветовым отображением состояния. В случае самостоятельной работы еще добавляются имена карт
- Вызов внешнего скрипта для установки powertune
- Частоты ядра и памяти берутся из настроек sgminer из файла /home/rain/config/cards.conf
- Возможность однократной работы и работы в цикле (по умолчанию)
- Возможность вызова скрипта исключительно для установки частот карт
- Помимо отображения статистики в терминале, при работе в цикле создается html-файл с результатами работы скриптов /home/rain/bin/sysinfo.sh, /home/rain/bin/ethspeed, а также выводом ffc.sh
Дефолтный вариант работы скрипта - работа в бесконечном цикле с паузой между циклами, заданной в $sleep.
Каждый цикл проверяется наличие API (localhost:4028). Если sgminer запустился и API есть - используются функции майнера по регулировке частот и скоростей, а ffc.sh служит только для отображения статуса. В таком случае состояние карт забирается через API скриптом /home/rain/bin/api-example.py, после чего вывод парсится и на основе этого строится таблица состояния карт.
Если API пропал или отсутствует, используется более сложный вариант. Данные о состоянии карт (частоты, загрузка, etc) забираются через aticonfig в начале каждого цикла. Кроме того, разово, а также каждый раз при смене состояния sgminer (появлении или пропадании процесса) инициализируется массив fan - туда вычитываются реальные установленные скорости вращения вентиляторов, после чего скрипт использует только собственные данные для работы с вентиляторами, без обращения к pplib. Переинициализация fan при смене состояния sgminer сделана из-за того, что он при запуске или остановке устанавливает вентиляторы на 50%, что иногда приводило к перегревам карт.
Данные, полученные через aticonfig, преобразовываются к такому же виду, как и с api-example.py - это сделано для более полного использования второй части кода - кроме того, эти части писались в разное время и независимо. Однако в API не предусмотрена передача имени карты, поэтому добавляется тег Devname, который игнорируется в случае реальной работы через API. Кроме того, так как в случае самостоятельной работы для минимизации вызовов aticonfig используются только внутренние данные по скоростям вентиляторов, то в сформированный вывод по данным о частотах, температурах и загрузке подмешиваются данные из массива fan.
Далее все передается на следующую часть скрипта, служащую для формирования данных в удобном для восприятия виде и отображении в терминале. Для этого необходимые данные сравниваются с порогами и в зависимости от результатов сравнения вывод окрашивается в разные цвета с помощью esc-последовательностей. Кроме того, реализовано отображение прогресс-баров. Итоговый результат помещается в переменную, содержимое которой выводится на экран сразу после вызова clear, чтобы исключить мерцание экрана.
Данные по температурам, помимо вывода, обрабатываются частью скрипта, ответственной за управление вентиляторами. В этой части, в зависимости от того, с каким условием совпадает текущая температура у карты, выполняется то или иное действие. В этой же части формируются и новые значения в массиве fan, что в дальнейшем используется и при отображении статистики.
Из дополнительных возможностей скрипта:
- Вызов в однократном режиме - параметр single. В таком случае основной цикл прерывается в конце выполнения.
- Подробный лог - при наличии при запуске переменной DEBUG=1 в файл /tmp/ffc.log пишется текущее состояние
- Вычитывание значений из /home/rain/config/cards.conf - допустимы одинарные значения, диапазоны (берется максимальное число) и одно значение на все карты.
- Для установки частот можно использовать параметр freqs для скрипта.
- При установке частот при наличии /home/rain/bin/atitweak он вызывается для установки powertune
- В обычном режиме работы данные, сформированные для отображения в терминале, дополнительно прогоняются через скрипт, заменяющий esc-последовательности на html-код и добавляющий необходимые теги, после чего результат сохраняется в /tmp/index.html для отображения через веб-сервер. Для тех же целей в начале работы скрипта разово вызываются sysinfo.sh и hostname, содержимое которых служит шапкой файла. Кроме того, в основном цикле вызывается ethspeed single, служащий для отображения скорости ethminer.
ethminerctl
ethminerctl служит для запуска, остановки, мониторинга состояния и прочих смежных функций майнера для Ethereum - ethminer. В зависимости от переданного параметра скрипт выполняет следующее:
- start
- Блокировка monit.sh через его lock-файл и снятие процесса monit.sh
- Остановка sgminer, если тот в данный момент работает
- Установка вентиляторов на 100% на время переходных процессов
- Запуск ethminerctl с параметром main, что выполняет основную часть скрипта по запуску. Введено из-за того, что в screen есть ограничение на длину передаваемой screen команды. Попутно устанавливаются необходимые переменные в существующей сессии screen'а, так как screen представляет собой отдельную shell-сессию и про переменные скрипта не знает.
- stop: Остановка процесса ethminer
- service: Выполнение сервисного обслуживания рига после запуска процесса ethminer:
- Поиск DAG-файлов, которые в данный момент не используются ethminer'ом - а, значит, устарели и могут быть удалены
- Принудительный sync, сбрасывающий кэшированный DAG на диск.
- Поиск видеокарты с максимальным объемом свободной памяти. Полученный результат служит в качестве параметра запускаемому следом sgminer, служащему в данном случае для регулировки частот и вентиляторов. Такое решение было сделано после того, как sgminer начал отжирать несколько гигабайт памяти в том случае, когда запускался на сложных алгоритмах (вроде X11) после ethminer. Запуск на одной карте вместо всех снижал расход памяти, а запуск на карте с большим числом свободной видеопамяти не приводил к отжиранию памяти sgminer'ом. Из недостатков такого запуска - проявившийся баг sgminer, когда в окне программы показывалось только 0-е устройство. Это было решено созданием ffc.sh
- После запуска sgminer после доступности его API видеокарты выключаются скриптом gpuoff, после чего sgminer занимается исключительно регулировками частот и вентилятов.
- lock и unlock - сервисные команды, служат для создания и удаления lock-файлов.
- main - основная ступень запуска майнера. Включает в себя непосредственно запуск команды майнера с передачей всех необходимых переменных, запись вывода майнера в файл /tmp/ethlog (раньше активно использовался для отслеживания событий, потом было сделано отслеживание событий прямо в потоке сообщений майнера. Сейчас используется разве что для подсчета скорости майнера, что тоже можно сделать без использования файла), а также обработчик потока сообщений майнера. Обработчик в свою очередь делает следующее:
- Отслеживание и уведомление в jabber состояния нехватки памяти видеокарты по наличию слова Bailing. По событию процесс майнера завершается.
- Подсчет числа шар и reject'ов, а также наличия ключевой фразы "gpuminer0 workLoop 1", что свидетельствует о начале нормальной работы майнера. По факту наличия первой шары, а также упомянутой ключевой фразы запускается "ethminerctl service" (см. выше), а также устанавливается флаг успешности запуска майнера.
- Если при наличии упомянутого флага в потоке сообщений появляется "Initialising miner" - значит, произошла смена эпохи и майнер будет загружать новый DAG-файл в память. Чтобы свести конфликты к минимуму - по данному событию майнер завершает работу (а скрипт мониторинга запускает новую копию майнера, которая будет работать уже исключительно с новым файлом, что позволит удалить старый) с уведомлением в jabber.
- Отлов сообщений о проблемах подключения. Если таких сообщений в потоке становится более 50% - делается остановка майнера с уведомлением в jabber.
- По принятым и отброшенным шарам строится статистика, которая отображается слева от основного потока сообщений майнера. Считается число принятых шар, процент reject'ов от общего числа шар, а также скорость генерации шар в минуту при усреднении за полчаса.
- При завершении работы майнера любым описанным выше способом в конце выводится дата завершения процесса, а также таймер для автоматического закрытия терминала в screen'е.
- notify - сервисный параметр, служит для передачи сообщений через jabber
- suspend и unsuspend - отправка процессу ethminer сигналов SIGSTOP и SIGCONT соответственно.
- monit - типичный режим запуска скрипта для майнинга. В данном блоке делается обрезание лога по достижению размера в 10 МБ, а также проверка наличия процесса ethminer и при его отсутствии - выполнение ethminerctl start. Кроме того, делается проверка температуры карт и в случае превышения 85 градусов - выполняется ethminerctl suspend (сделано на случай отказа других средств мониторинга) с уведомлением в jabber.
- power - проверка состояния электросети. Если напряжение ниже установленного предела - suspend'им майнер, если выше - запускаем в работу через unsuspend.
- restart - последовательный вызов ethminerctl stop и ethminerctl start с lock'ом и небольшой паузой