Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет kouzdra ([info]kouzdra)
@ 2011-12-23 15:10:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Задачка программстское
Имеется язык. С вполне традиционной модульной структурой - ala Modula, ML etc - причем в "современном варианте" - модули не могут взаимно ссылаться друг на друга даже в части реализации.

Имеется компилятор - со структурой не вполне трационной - он сначала все модули парсит (заодно при этом выясняется собственно какие модули нужны), потом все typecheck'ает, потом генерит код.

На последнем этапе он в числе прочего пишет объектные файлы (которые может использовать при компиляции вместо того, чтобы проделывать весь этот долгий и мучительный процесс).

Задача: научить несколько процессов (это именно отделные процессы в обычном смысле) компиляции идти параллельно на программах с сильно весьма пересекающимися наборами модулей.

Проблема понятно отчасти в блокировках (что сделать несложно), но задача в другом: как избежать дедлоков (модуль X запрашивает А и B, модуль Y - B и A, соотвественно они лочат каждый свое и дальше ...).

Проблема в том, что локи в силу специфической структуры компилятора приходится ставить в самом начале на все подлежащие перекомпиляции модули.


(Добавить комментарий)


[info]gregory_777
2011-12-23 14:55 (ссылка)
Составлять список модулей, подлежащих перекомпиляции, а затем сортировать их по количеству взаимных запросов по возрастанию. После компиляции каждого модуля пересортировывать список, каждый раз компилятор берёт из стека модуль с наименьшим количеством связей. Параллельные процессы должны брать для компиляции модули, не имеющие связей в соседнем процессе.

(Ответить) (Ветвь дискуссии)


[info]kouzdra
2011-12-23 16:49 (ссылка)
Ньюанс (довольно обычный для такого рода схем) в том, что список модулей выясняется только в процессе компиляции - по списку импортов.

(Ответить) (Уровень выше)


[info]lolepezy
2011-12-23 20:13 (ссылка)
Я, видимо, чего-то не понял, но вроде тут обычного read-write lock'а
хватает (в смысле, read - объектный модуль читается, write - генерируется).

(Ответить) (Ветвь дискуссии)


[info]kouzdra
2011-12-23 20:26 (ссылка)
Ну так это я с дуру и сделал - и нарвался на классический дедлок - оба процесса заблокировали ресурсы, которые им нужны чтобы освободить ранее заблокрированные.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]lolepezy
2011-12-24 13:05 (ссылка)
Всё равно туплю. Как дедлок получается, если граф
зависимостей ациклический? Как может возникнуть цикл
в графе блокировок?

> модуль X запрашивает А и B, модуль Y - B и A
Отсортировать зависимости в каждом модуле?
Тогда лочиться будут в одном порядке.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]kouzdra
2011-12-24 13:07 (ссылка)
Отсортировать зависимости в модуле сработает на данном примере - если деревяшка чуть посложнее - то через одну уже косвенность проблема воспроизведется.

(Ответить) (Уровень выше)


[info]lqp
2011-12-23 21:16 (ссылка)
В два прохода тогда. Сначала строить таблицу зависимостей. Потом создать список "доступных для компиляции модулей" (в смысле, без неразрешенных еще зависимостей). Компиляторы берут из этого списка и по окончании компиляции посылают сигнал планировщику, который обновляет список. Как-то так я представляю.

Как вариант - при наличии неразрешенных зависимостей прекращать компиляцию (это довольно скоро после старта, как я понимаю) и отдавать эту информацию планировщику.

(Ответить) (Ветвь дискуссии)


[info]lqp
2011-12-23 21:19 (ссылка)
А проще всего - оторвать компилятору излишний интеллект вообще, а зависимости строить посредством make (+ какой-нибудь скриптовой приблуды для рисования мейкфайлов, навряд-ли она будет сложной).

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]nikto
2011-12-25 20:26 (ссылка)
Подтверждаю - у нас такое решение (make плюс скрипт, генерирующий makefile) хорошо себя показало в эксплуатации. При том, что все, что делает скрипт - проходит по модулям и читает их зависимости.

(Ответить) (Уровень выше)


[info]ketmar
2011-12-24 23:57 (ссылка)
раз: строим зависимости и запоминаем.
два: спокойно собираем всю лабуду с использованием информации из пункта 1.

натурально, перестраивать зависимости, если что-то поменялось. в принципе, это вряд ли постоянно будет новый репарзинг.

(Ответить)


[info]tzirechnoy.livejournal.com
2011-12-28 12:58 (ссылка)
Можно вообще lock-free попробовать, с атомарным mv объектника. Да, будет overhead по две компиляцыи если не повезёт. Но это, скорее всего, изредка.

(Ответить)