У меня есть симуляция, которая состоит из N шагов, запускаемых последовательно. Каждый из этих шагов изменяет глобальное состояние в памяти до последнего шага, который является результатом. После выполнения шага можно записать на диск промежуточное состояние, которое этот шаг только что рассчитал, и загрузить такое промежуточное состояние вместо того, чтобы начинать с нуля. Написание и загрузка промежуточных состояний требует немалых затрат.
Я хочу запустить много вариантов симуляции на кластере Slurm. Каждый вариант будет изменять параметр некоторых шагов.
Пример
Шаг моделирования
S1 --> S2 --> S3 --> S4
Вариации
run1: S2.speed=2, S3.height=12
run2: S2.speed=2, S3.height=20
run3: S2.speed=2, S3.height=40
run4: S2.speed=5, S3.height=12
run5: S2.speed=5, S3.height=80
Что я хочуdo предназначен для различных прогонов для совместного использования общих вычислений путем сброса промежуточного состояния общих шагов. Это сформирует дерево этапов:
S1
├─ S2 (speed=2)
│ ├─ S3 (height=12)
│ │ └─ S4
│ ├─ S3 (height=20)
│ │ └─ S4
│ └─ S3 (height=40)
│ └─ S4
└─ S2 (speed=5)
├─ S3 (height=12)
│ └─ S4
└─ S3 (height=80)
└─ S4
Я знаю, что могу получить результат 5 запусков, запустив 5 процессов:
run1: S1 --> S2 (speed=2) --> S3 (height=12) --> S4
run2: (dump of run1.S2) --> S3 (height=20) --> S4
run3: (dump of run1.S2) --> S3 (height=40) --> S4
run4: (dump of run1.S1) --> S2 (speed=5) --> S3 (height=12) --> S4
run5: (dump of run4.S2) --> S3 (height=80) --> S4
Это уменьшает вычисления с 20 шаговиспользуя наивный подход, до 13 шагов с 3 дампами и 4 загрузками.
Теперь мой вопрос: как смоделировать это с помощью Slurm, чтобы наилучшим образом использовать планировщик?
Одно решениеЯ могу думать о том, что каждый прогон отвечает за передачу заданий тех прогонов, которые зависят от него, после сброса промежуточного состояния. Run1 отправит run4 после сброса S1, а затем отправит run2 и run3 после сброса S2, а run4 отправит run5 после сброса S2. С этим решением, есть ли смысл объявлять зависимость при отправке задания в Slurm?
Еще одно решение, которое я вижу, - разорвать длинные цепочки вычислений в нескольких зависимых заданиях. Список работ для отправки и их зависимостей будет в основном тем деревом, которое я нарисовал выше (за исключением пар S3 / S4, которые будут объединены в одной и той же работе). Это 8 заданий вместо 5, но я могу отправить их сразу с самого начала, с правильными зависимостями. Тем не менее, я не уверен, каковы будут преимущества этого подхода. Будет ли Slurm лучше работать в качестве планировщика, если он знает полный список заданий и их зависимостей с самого начала? Есть ли какие-то преимущества с точки зрения пользователя, чтобы все задания были отправлены и связаны с зависимостями (например, чтобы отменить все задания, которые зависят от корневого задания)? Я знаю, что могу отправлять много заданий одновременно с массивом заданий, но я не вижу способа объявить зависимости между заданиями одного и того же массива. Возможно или даже желательно?
Наконец, есть ли другие подходы, о которых я не задумывался?
Edit
Пример, который я привел, конечно, сильно упрощен. Реальные симуляции будут содержать сотни шагов, около тысячи вариантов. Масштабируемость выбранного решения важна.