Аппаратная транзакционная память. Обзор решений. Часть 1. Введение

Довольно длительное время моё внимание привлекает тематика использования транзакционной памяти (англ. transactional memory, далее TM) для построения параллельных программ, не использующих классические замки (англ. locks) для защиты ресурсов.

В этом цикле статей я расскажу об известных мне аппаратных реализациях TM различных вендоров, как уже доступных на рынке, так и о нескольких несостоявшихся или отложенных проектах, дальнейшая судьба которых неизвестна.
Сама концепция TM не нова и была предложена ещё в 1993 году [3]. Я буду вводить необходимые понятия по мере их использования. Заинтересованным же в полной классификации, истории вопроса следует обратиться к монографии [2].

Обзор TM

О принципах работы TM написано достаточно много. Основная идея состоит в оптимистичном исполнении параллельных частей приложений. ТМ позволяет им исполняться параллельно внутри транзакций, несмотря на риск возникновения гонок данных (англ. data race). При этом конфликты совместного обращения к памяти детектируются, и некоторые участвующие в них потоки откатываются до состояния начала их входа в транзакцию и исполняются повторно. В случаях, когда конфликты нечасты, мы получаем прирост в производительности за счёт отсутствия необходимости ожидать освобождения замков. Кроме того, утверждается, что само параллельное программирование с использованием транзакций легче, чес с использованием классических механизмов синхронизации.

Можно обеспечить семантику TM с помощью библиотеки и/или расширения некоторого языка программирования. Такие работы есть, в том числе у Intel [5]. Однако чисто программные реализации часто показывают низкую эффективность результирующего кода по сравнению с программами, написанными с использованием замков. Напрашивается необходимость аппаратной поддержки.

Аппаратная транзакционная память (англ. hardware transactional memory, далее HTM) расширяет набор инструкций процессора новыми, позволяющими ему входить в спекулятивный режим, в котором все записи в память задерживаются в промежуточном хранилище. При выходе из такого режима, если не возникло конфликтов чтения-записи между двумя или более потоками, содержимое хранилища атомарно переносится в общую память и становится видимым для остальных процессоров. Если принято решение отменить некоторую транзакцию, то этот буфер сбрасывается, а состояние регистров восстанавливается из точки сохранения, созданной на начало транзакции.

Успешному завершению транзакции, кроме собственно конфликтов с другими потоками, могут помешать многочисленные факторы, различающиеся от реализации к реализации. Среди них наиболее частыми являются:

  • Обращение к регионам памяти, не поддерживающим кэширование, например, к MMIO (англ. memory mapped input-output).
  • Чрезмерно большой объём данных, требуемых для хранения в транзакции, превышающий возможности аппаратуры. 
  • Запрещённые инструкции, не поддерживаемые внутри транзакций.
  • Исключительные ситуации, в том числе аппаратные и программные прерывания.

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

В следующих постах мы рассмотрим известные на данный момент проекты по поддержке HTM в центральных процессорах. 

For more complete information about compiler optimizations, see our Optimization Notice.