Upload
iosif-itkin
View
2.697
Download
1
Embed Size (px)
Citation preview
Антон Евдокимов ([email protected])
Дмитрий Цителов ([email protected])
Роман Елизаров ([email protected])
Виталий Трифанов ([email protected])
Автоматическое тестирование
линеаризуемости реализаций
многопоточных структур
данных
В чем проблема?
─ Процессоры многоядерные
─ Нужно писать многопоточный код
─ Это не так просто
─ В многопоточной среде появляются
специфические проблемы
─ Одновременный доступ к разделяемым
ресурсам
В чем проблема?
В чем проблема?
─ Стандартные подходы к тестированию
не работают
─ Но проверять корректность
реализации все равно хочется
Линеаризуемость
─ Любое параллельное исполнение эквивалентно
некоторому последовательному
Метод
─ Взять небольшое количество потоков
─ В каждом несколько операций над
структурой данных
─ Запустить много-много раз и
попытаться объяснить результаты
последовательной перестановкой
─ Повторить
Метод
Границы применимости метода
─ Подходит для популярных структур
данных
─ Очереди, множества, хеш-таблицы…
─ Но
─ Структура данных не зависит от
внешней среды
─ Не блокируется
─ Метод точен, но не полон
Очередь
Генерация тестовых наборов
─ Наивно?
─ Операции
─ Изменяют структуру данных
─ Не изменяют
─ Аргументы
─ Влияют на логику поведения
структуры данных
─ Не влияют
Генерация тестовых наборов
Генерация тестовых наборов
Генерация тестовых наборов
P Q
offer(1);
offer(2);
poll();
poll();
Последовательные исполнения
─ Перестановки исходного набора
операций
─ С сохранением порядка операций для
каждого потока
Последовательные исполнения
P Q
offer(1);
offer(2);
poll();
poll();
offer(1); poll() {1}; offer(2); poll() {2};
Последовательные исполнения
offer(1); offer(2); poll() {1}; poll() {2};
offer(1); poll() {1}; offer(2); poll() {2};
offer(1); poll() {1}; poll() {Exception}; offer(2);
poll() {Exception}; poll() {Exception}; offer(1); offer(2);
poll() {Exception}; offer(1); offer(2); poll() {1};
poll() {Exception}; offer(1); poll() {1}; offer(2);
Параллельные исполнения
─ Множественные запуски
─ Синхронизация старта
─ Все служебные структуры создаем
вне многопоточной системы
─ Можно вызывать методы через
Reflection API, но используется ASM
─ Две фазы запусков (без/с задержками)
Проверка
─ Ищем последовательное исполнение,
соответствующее по результатам
параллельному
─ Если не нашли, то структура
нелинеаризуема!
offer(1); poll() {1}; offer(2); poll() {1};
Результаты
─ Синтетические примеры
─ Очередь, счетчик, некоторые другие
─ Потеря synchronized, volatile,
ошибочное использование
неатомарных переменных
─ Нашлись наборы операций,
приводящие к ошибке
Результаты
─ java.util.concurrent ✓
─ Google Guavа ✓
Результаты
─ jctools [1]
─ MpmcArrayQueue ✗
─ zchannel [2]
─ GenericMPMCQueue ✗
─ high_scale_lib [3]
─ NonBlockingHashMap ✗
[1] https://github.com/JCTools/JCTools
[2] http://landz.github.io/
[3] https://github.com/stephenc/high-scale-lib
Результаты
─ zchannel – GenericMPMCQueue
P Q
offer(9); {true}
poll(); {null}
offer(1); {true}
poll(1); {1}
Результаты
Структура данных Время (мс); мин-макс (средн.)
Counter 4 – 110 (33)
Queue 5 – 38786 (8635)
Accounts 3 – 50606 (18697)
NonBlockingSetInt 52 – 10414 (4291)
NonBlockingHashSet 5 – 66975 (16111)
MpmcArrayQueue(2) 2352 – 45628 (19974)
MPMCQueue(2) 1814 – 33958 (19714)
MPMCQueue(16) 1877 – 33858 (8651)
LockFreeQueue 8825 – 342199 (135202)
Что дальше?
─ Генерация параллельных исполнений
с помощью управляемого
переключения между потоками
─ Конкретная последовательность
инструкций
─ Лучшее покрытие состояний
Где посмотреть
─ Lincheck
─ https://github.com/Devexperts/lin-check
Вопросы?
Спасибо