Write cache что это
FAQ : RAID : Общие вопросы
Избежать описанной проблемы можно или с помощью установки на RAID контроллер BBU (см. ниже), или посредством подключения всего сервера через источник бесперебойного питания (UPS) с функцией программируемого выключения.
Существуют три разновидности BBU :
Обратите внимание: резервирование позволяет восстановить данные, находившиеся на неисправном диске, если все диски подключены к одному и тому же RAID контроллеру.
«Резервный» диск может быть создан одним из двух способов:
В течение процесса автоматического восстановления система продолжает нормально функционировать, однако производительность системы может слегка ухудшиться.
Для того, что бы использовать восстанавливающую особенность резервирования, Вы должны всегда иметь резервный диск ( Hotspare ) в вашей системе. В случае сбоя дисковода, резервный дисковод автоматически заменит неисправный диск, и данные будут восстановлены. После этого, системный администратор может отключить и удалить неисправный диск, заменить его новым диском и сделать этот новый диск резервным.
В этом разделе использованы материалы с сайта «3dnews».
В: Нужно ли заниматься архивированием данных в случае использования RAID?
О: Конечно да! RAID это вовсе не замена архивированию, основное его назначение это повышение скорости и надежности доступа к данным в нормальном режиме работы. Но только регулярное архивирование данных гарантировано обеспечит их сохранность при любых отказах оборудования, пожарах, потопах и прочих неприятностях.
Тестирование технологии кэширования RAID–массивов Adaptec
Решения для работы с RAID-массивами из жестких дисков используются уже очень давно. В целом они продолжают оставаться популярными во многих областях, когда требуется относительно недорогой отказоустойчивый массив большого объема. Учитывая размеры современных винчестеров, их скорость, а также и другие причины, наибольший практический интерес вызывают массивы RAID6 (или RAID60, если дисков много). Но этот тип массивов имеет невысокую производительность на операциях случайной записи и сделать что-либо с этим непросто.
Конечно, в данном случае речь идет о скорости «сырого тома». В реальной жизни к нему добавляется файловая система, операционная система, приложения и все такое. Так что на самом деле не все так плохо. Однако есть и программно-аппаратные способы увеличения производительности, независимые от указанных подсистем. Речь идет о технологиях кэширования, когда к массиву из жестких дисков добавляется существенно более быстрый накопитель на базе флэшпамяти.
В частности в RAID- контроллерах Adaptec эта технология называется maxCache и ее версия 3.0 реализована в моделях ASR-8885Q и ASR-81605ZQ. При ее использовании необходимо учитывать несколько особенностей: допускается наличие только одного тома maxCache на контроллер, максимальный объем тома maxCache составляет 1 ТБ, для работы кэширования записи необходимо иметь отказоустойчивую конфигурацию самого тома maxCache (например, зеркало). При этом пользователь может самостоятельно указывать для каждого логического тома как конкретно он будет работать с maxCache – на чтение и/или на запись и в каком режиме.
Для тестирования использовался сервер на базе материнской платы Supermicro X10SLM-F, процессора Intel Xeon E3-1225 v3 (4C/8T, 3,2 ГГц), 32 ГБ оперативной памяти, работающий под ОС Debian 9.
Тестируемый контроллер ASR-81605ZQ штатно имеет блок защиты памяти и при работе с массивом из жестких дисков у него активны кэши и на чтение и на запись. Напомним, что объем собственной памяти у этой модели – 1 ГБ. Массив RAID6 с блоком в 256 КБ создавался из шести жестких дисков Seagate ST10000NM0086 с интерфейсом SATA и объемом 10 ТБ. Общий объем тома составил около 36 ТБ.
В качестве SSD-накопителей для тома maxCache выступали две пары устройств: два Samsung 850 EVO второго поколения по 1 ТБ с интерфейсом SATA и два Seagate 1200 SSD (ST400FM0053) по 400 ГБ с интерфейсом SAS, из которых создавались массивы RAID1. Конечно, первая модель уже может считаться устаревшей и не только морально. Но для иллюстрации бюджетного сценария она подойдет. Вторая формально лучше подходит под «корпоративную» категорию, но и ее сложно считать современной. В настройках самого массива maxCache есть только опция Flush and Fetch Rate, которая оставалась на значении по умолчанию (Medium). Возможности выбрать приоритет по операциям или дисковым томам нет. Отметим, что накопители были не в новом состоянии и TRIM в данной конфигурации не используется.
После создания тома maxCache нужно включить в свойствах логического тома параметры для его использования. Всего здесь предусмотрено три опции: включение кэша на чтение, включение кэша на запись и тип кэша на запись.
В качестве тестового инструмента применялась утилита fio, а набор сценариев включал в себя последовательные и случайные операции с разным числом потоков. Стоит заметить, что исследование производительности продуктов с кэширующими технологиями синтетическими тестами сложно признать оптимальным вариантом. Адекватно оценивать эффект лучше на реальных задачах, поскольку синтетическая нагрузка в определенной степени противоречит самой идее кэширования. Кроме того, в данном случае мы рассматриваем низкоуровневые операции, а по факту пользователь обычно имеет дело с файлами и в работу с ними включаются, как мы говорили выше, файловая система тома, операционная система и непосредственно программное обеспечение. Так что именно синтетика, привлекательная своей простотой и повторяемостью, имеет смысл не сама по себе, а в основном для сравнения «как было и как стало» в сложных для алгоритмов кэширования сценариях и достаточно грубой оценки эффекта.
Посмотрим сначала, на что способен наш массив сам по себе. Напомним, что в последовательных операциях интересна скорость в МБ/с и задержки (в логарифмическом масштабе), а на случайных – IOPS и тоже задержки.
Скорость потоковых операций с массивом данной конфигурации находится на уровне 900 МБ/с. При этом задержки не превышают 70 мс даже при большом числе потоков.
Для жестких дисков случайные операции являются самой сложной нагрузкой, что видно по результатам. Если поставить порог времени ожидания на уровне 100 мс, то на чтении можно получить около 1100 IOPS, а на записи независимо от нагрузки массив способен дать около 300 IOPS. Отметим, что с массивом RAID60 из 36-ти дисков на том же контроллере можно получить и более интересные цифры, благодаря конфигурации трех блоков по 12 винчестеров. Это позволяет добавить чередование и поднять скорости до 3500 и 1200 IOPS на случайном чтении и записи соответственно (в этой конфигурации были достаточно старые SAS-винчестеры от HGST по 2 ТБ). Отрицательная сторона такого варианта – дополнительные расходы на объем, поскольку «теряется» не два диска на том, а два на каждую группу.
Итак, без кеширования наш массив смотрится достаточно грустно на случайных операциях. Конечно это «сырая» скорость тома и программы редко дают исключительно случайную нагрузку (напомним, что здесь у нас все-таки массив для хранения файлов большого объема, а не базы данных).
Посмотрим, чем могут помочь в данной ситуации SSD. В тестах будет использоваться четыре доступных варианта конфигурации – только чтение, чтение и запись Write Through, чтение и запись Write Back, чтение и запись Instant Write Back:
На операциях последовательного чтения массив показывает стабильные результаты независимо от типа используемого кэша, что вполне ожидаемо. При этом они мало отличаются от массива без кэша – все те же 900 МБ/с и задержки около 70 мс.
На последовательной записи есть две группы – только на чтение и с Write Back демонстрируют результаты аналогичные массиву без кэша – около 900 МБ/с и до 100 мс, а Write Through и Instant Write Back способны вытянуть не более 100 МБ/с и с существенно большими задержками.
Напомним, что на чтении массив из винчестеров показал максимальное около 1100 IOPS, но на этой границе задержки уже начали превышать 100 мс. С кэшированием SATA SSD можно добиться немного более высоких результатов – около 1500 IOPS и с теми же задержками.
На операциях случайной записи мы видим наибольший эффект – рост показателей в два с половиной раза с одновременным увеличением нагрузочной способности. При использовании кэша можно иметь задержки до 100 мс при в два-три раза большем числе потоков.
Общие заключение по данной конфигурации: на последовательном чтении не мешает, на последовательной записи в некоторых конфигурациях не мешает, на случайном чтении добавляет около 35%, на случайной записи увеличивает производительность в пару раз.
Посмотрим теперь на вариант кэширующего тома второй пары накопителей SSD. Отметим, что в нашем случае у них был существенно меньший объем, интерфейс SAS 12 Гбит/с и более высокие скоростные характеристики (заявленные производителем).
На последовательном чтении результаты не отличаются от приведенных ранее, что вполне ожидаемо.
На последовательной записи теперь у нас три группы – отстает конфигурация с кэшем записи Write Through, примерно половину максимальной скорости показывает Instant Write Back и только Write Back не отличается от массива без кэша. Такой же расклад и со временем ожидания.
Зато на случайном чтении Instant Write Back показал себя лучше всего, достигая 2500 IOPS, тогда как остальные конфигурации способны вытянуть только до 1800 IOPS. Заметим, что все варианты с кэшированием записи заметно быстрее «чистого» массива. При этом время ожидания не превышает 100 мс даже при большом числе потоков.
На операциях случайного чтения Instant Write Back снова выходит вперед, показывает почти 2000 IOPS. Во второй группе находятся конфигурации Write Through и Write Back c 1000 IOPS.
Последний участник, не использующий кэш на операциях записи, показывает около 300 IOPS, как и просто массив из винчестеров.
Пожалуй, для этого кэширующего тома интереснее всего смотрится вариант Instant Write Back. Правда он медленнее на операциях потокового чтения. Возможно, это получится исправить использованием конфигурации RAID10 для тома maxCache, но это будет «стоить» уже четырех отсеков в корпусе СХД.
В целом, можно говорить о том, что применение технологии maxCache действительно может быть полезно для повышения производительности массивов из жестких дисков, особенно если в нагрузке много случайных операций. Однако считать, что это настолько же эффективно, как замена жесткого диска на SSD в настольном компьютере или рабочей станции, все-таки нельзя.
Наибольший эффект, который был отмечен в тестах – увеличение скоростей случайных операций в 2-3 раза. Конечно, были использованы не самые быстрые SSD, что явно сказывалось в некоторых тестах (например, последовательной записи в режиме Write Through). Кроме того, хотелось бы еще раз обратить внимание на то, что выбор конфигурации кэширования существенно влияет на результаты. Учитывая, что изменение настроек возможно «на лету» без потери данных, стоит самостоятельно проверить все варианты на своих задачах и выбрать оптимальный вариант.
О кэшах в микроконтроллерах ARM
Привет!
В предыдущей статье мы для ускорения графики на микроконтроллере в Embox применяли процессорный кэш. При этом мы использовали режим «write-through». Тогда мы писали о некоторых преимуществах и недостатках связанных с «write-through» режимом, но это был лишь беглый обзор. В этой статье я, как и обещал, хочу подробней рассмотреть типы кэшей в ARM микроконтроллерах, а также сравнить их. Конечно, все это будет рассмотрено с точки зрения программиста, и вдаваться в детали работы контроллера памяти в данной статье мы не планируем.
Начну с того на чем остановился в предыдущей статье, а именно, на разнице между «write-back» и «write-through» режимами, поскольку именно эти два режима чаще всего используются. Если кратко, то:
Write-through
Преимуществами режима write-through считается простота использования, что потенциально уменьшает количество ошибок. Действительно, в этом режиме память всегда находится в корректном состоянии и не требует дополнительных процедур обновления.
Конечно кажется будто это должно сильно сказаться на производительности, но сам STM в этом документе говорит, что это не так:
Write-through: triggers a write to the memory as soon as the contents on the cache line are written to. This is safer for the data coherency, but it requires more bus accesses. In practice, the write to the memory is done in the background and has a little effect unless the same cache set is being accessed repeatedly and very quickly. It is always a tradeoff.
То есть, изначально мы предполагали, что раз запись происходит в память, то на операциях записи производительность будет примерно такой же как и совсем без кэша, а основной выигрыш происходит за счет повторных чтений. Однако, STM это опровергает, говорится что данные в в память попадают “в фоне”, поэтому производительность на записи практически такая же как и в режиме «write-back». Это, в частности, может зависеть от внутренних буферов контроллера памяти (FMC).
Минусы режима «write-through»:
Write-back
Как уже говорилось выше, в этом режиме (в отличие от «write-through») данные в общем случае не попадают в память по записи, а попадают только в кэш. Как и у «write-through», у этой стратегии имеются два “под варианта” — 1) «write allocate», 2) «no write allocate». Об этих вариантах мы поговорим дальше.
Write Allocate
Как правило, в кэшах всегда используется «read allocate» — то есть по промаху (cache miss) на чтение данные забираются из памяти и размещаются в кэше. Аналогично, при промахе на запись данные могут подгружаться в кэш («write allocate») или не подгружаться («no write allocate»).
Обычно на практике используются сочетания “write-back write allocate” или “write-through no write allocate”. Далее в тестах мы попробуем чуть более детально проверить в каких ситуациях использовать «write allocate», а в каких «no write allocate».
Прежде чем переходить к практической части нам необходимо разобраться как же задавать параметры региона памяти. Для выбора режима кэша (или его отключения) для определенного региона памяти в архитектуре ARMv7-M используется MPU (Memory Protection Unit).
В контроллере MPU поддерживается задание регионов памяти. Конкретно в архитектуре ARMV7-M может быть до 16 регионов. Для этих регионов можно независимо устанавливать: стартовый адрес, размер, права доступа (read/write/execute и т.д.), атрибуты — TEX, cacheable, bufferable, shareable, а так же и другие параметры. С помощью такого механизма, в частности, можно добиться любого типа кэширования для определенного региона. Например, мы можем избавиться от необходимости вызывать cache_clean/cache_invalidate просто выделив регион памяти под все операции DMA и пометив эту память как не кэшируемую.
Нужно отметить важный момент при работе с MPU:
The base address, size and attributes of a region are all configurable, with the general rule that all regions are naturally aligned. This can be stated as:
RegionBaseAddress[(N-1):0] = 0, where N is log2(SizeofRegion_in_bytes)
Иными словами, стартовый адрес региона памяти должен быть выровнен на его собственный размер. Если у вас, к примеру, регион 16 Кб, то выравнивать нужно на 16 Кб. Если регион памяти 64 Кб, то выравниваем на 64 Кб. И так далее. Если этого не сделать, то MPU может автоматически “обрезать” регион под размер соответствующий его стартовому адресу (проверено на практике).
Кстати, в STM32Cube есть несколько ошибок. Например:
Видно, что стартовый адрес выровнен на 64 Кб. А размер региона хотим 256 Кб. В этом случае придется создавать 3 региона: первый 64 Кб, второй — 128 Кб, и третий 64 Кб.
Задавать нужно только регионы с отличными от стандартных свойствами. Дело в том, что атрибуты всех памятей при включении кэша процессора описаны в архитектуре ARM. Есть стандартный набор свойств (к примеру, поэтому память SRAM STM32F7 имеет режим “write-back write-allocate” по умолчанию), Поэтому если вам понадобится не стандартный режим для какой-то из памятей, то нужно будет задать его свойства через MPU. При этом внутри региона можно задать подрегион со своими свойствами, Выделив внутри этого региона еще один с большим приоритетом с требуемыми свойствами.
Как следует из документации (раздел 2.3 Embedded SRAM), первые 64 Кб SRAM в STM32F7 некэшируемые. В самой архитектуре ARMv7-M по адресу 0x20000000 находится память SRAM. TCM тоже относится к SRAM, но находится на другой шине относительно остальных памятей (SRAM1 и SRAM2), и располагается “ближе” к процессору. Из-за этого данная память очень быстрая, по сути дела, имеет такую же скорость как и кэш. И из за этого кэширование не нужно, и этот регион не возможно сделать кэшируемым. По сути TCM это еще один такой вот кэш.
Instruction cache
Стоит отметить, что все рассмотренное выше относится к кэшу данных (D-Cache). Но кроме кэша данных в ARMv7-M предусмотрен и кэш инструкций — Instruction cache (I-Cache). I-Cache позволяет перенести часть исполняемых (и следующих) инструкций в кэш, что может значительно ускорить работу программы. Особенно, в тех случаях, когда код находится в более медленной памяти чем FLASH, к примеру, QSPI.
Чтобы уменьшить непредсказуемость в тестах с кэшем ниже, мы намеренно отключим I-Cache и будем думать исключительно о данных.
При этом хочу отметить, что включается I-Cache достаточно просто и не требует никаких дополнительных действий со стороны MPU в отличие от D-Cache.
Синтетические тесты
Так как тесты с кэшами очень капризные и находятся под влиянием всего и вся в системе — сделаем код линейным и непрерывным. Для этого отключаем прерывания. Так же, замерять время будем не таймерами, а DWT (Data Watchpoint and Trace unit), в котором есть 32 битный счетчик процессорных тактов. На его основе (на просторах интернета) люди делают микросекундные задержки в драйверах. Счетчик довольно быстро переполняется на системной частоте 216 МГц, но до 20 секунд померить можно. Просто будем об этом помнить, и сделаем тесты в этом временном интервале, предварительно обнуляя счетчик тактов перед стартом.
Посмотреть полные коды тестов можно тут. Все тесты были проведены на плате 32F769IDISCOVERY.
Non-cacheable memory VS. write-back
Итак, начнем с совсем простых тестов.
Просто последовательно пишем в память.
Так же последовательно пишем в память, но не по одному байту за раз, а немного развернем циклы.
Так же последовательно пишем в память, но теперь еще и чтение добавим.
Если запустить все эти три теста, то они дадут абсолютно одинаковый результат какой бы режим вы не выбрали:
И это резонно, SDRAM не такая уж и медленная, особенно если учесть внутренние буферы FMC, через который она подключена. Тем не менее, я ожидал небольшой вариации в цифрах, но оказалось что ее на этих тестах нет. Ну что же, будем думать дальше.
Давайте попробуем “подпортить” жизнь SDRAM смешивая чтения и записи. Для этого развернем циклы добавим такую распространенную на практике вещь как инкремент элемента массива:
Уже лучше — с кэшем оказалось на пол секунды быстрей. Давайте попробуем еще усложнить тест — добавим доступ по “разреженным” индексам. К примеру, с одним индексом:
Теперь разница с кэшем стала более чем заметна! И в довершение введем второй такой индекс:
Видим как время для не кэшируемой памяти подросло еще почти на секунду, в то время как для кэша осталось прежним.
Write allocate VS. no write allocate
Теперь давайте разберемся с режимом “write allocate”. Тут еще сложней увидеть разницу, т.к. если в ситуации между не кэшируемой памятью и “write-back” становятся хорошо видны уже начиная с 4-го теста, то различия между “write allocate” и “no write allocate” до сих пор тестами не вскрылись. Давайте подумаем — когда “write allocate” будет быстрей? Например, когда у вас есть много записей в последовательные ячейки памяти, а чтений из этих ячеек памяти мало. В этом случае в режиме “no write allocate” будем получать постоянные промахи, и подгружаться по чтению в кэш будут совсем не те элементы. Давайте смоделируем такую ситуацию:
Здесь в 15 из 16 записей выставляется константа VALUE, в то время как чтение осуществляется из разных (и не связанных с записью) элементов arr[i % 1024 + (j % 256) * 128]. Получается, что при стратегии no write allocate только эти элементы и будут загружаться в кэш. Причина по которой используется такая индексация (i % 1024 + (j % 256) * 128) — “ухудшение скорости” FMC/SDRAM. Так как обращения к памяти по существенно различным (не последовательным) адресам, могут существенно сказываться на скорости работы.
Наконец-то получили разницу, пусть и не настолько заметную, но уже видимую. То есть наша гипотеза подтвердилась.
И наконец, самый сложный, на мой взгляд, случай. Хотим понять когда “no write allocate” лучше чем “write allocate”. Первый лучше если мы “часто” обращаемся к адресам, с которыми в ближайшее время работать не будем. Такие данные, не нужно заносить в кэш.
В следующем тесте в случае “write allocate” данные будут заполняться по чтению и по записи. Я сделал массив “arr2” на 64 Кб, поэтому кэш будет сбрасываться, чтобы подкачать новые данные. В случае же с “no write allocate” я сделал массив “arr” на 4096 байт, и только он попадет в кэш, а значит данные кэша сбрасываться в память не будут. За счет этого и попробуем получить хотя бы небольшой выигрыш.
Видно, что “write-back” “write allocate” режим чуть-чуть быстрей. Но главное, что быстрей.
Лучшей демонстрации у меня добиться не получилось, но я уверен, что есть практические ситуации, когда разница более ощутима. Читатели могут предложить свои варианты!
Практические примеры
Давайте перейдем от синтетических примеров к реальным.
OpenCV
Еще одним примером реальной задачи на которой мы хотели попробовать работу подсистемы cache это OpenCV на STM32F7. В той статье было показано, что запустить вполне реально, но производительность была довольно низкая. Мы используем для демонстрации стандартный пример, который выделяет границы на основе фильтра Canny. Давайте измерим время работы с кешами (и D-cache и I-cache) и без.
То есть, 926ms и 134ms ускорение почти в 7 раз.
На самом деле у нас достаточно часто спрашивают про OpenCV на STM32, в частности какая производительность. Получается FPS конечно не высокий, но 5 кадров в секунду, вполне реально получить.
Не кэшируемая или кэшируемая память, но с cache invalidate?
В реальных устройствах повсеместно используется DMA, естественно с ним связаны трудности, ведь нужно синхронизировать память даже для режима “write-through”. Возникает естественное желание просто выделить кусок памяти который будет не кэшируемый и использовать его при работе с DMA. Немного отвлекусь. В Linux это делается функцию через dma_coherent_alloc(). И да, это очень эффективный метод, например, когда идет работа с сетевыми пакетами в ОС, пользовательские данные проходят большой этап обработки прежде чем дойти до драйвера, а в драйвере подготовленные данные со всем шапками копируются в буферы, которые используют не кэшируемую память.
А есть случаи когда в драйвере с DMA более предпочтителен clean/invalidate? Да, есть. К примеру, видеопамять, которая нас и побудила более подробно разобраться с работой cache (). В режиме двойной буферизации у системы есть два буфера, в которые она поочередно рисует, а потом отдает видеоконтроллеру. Если делать такую память не кэшируемой, то случится падение в производительности. Поэтому лучше сделать clean перед тем как отдать буфер в видеоконтроллер.
Заключение
Мы немного разобрались с разными вида кэшей в ARMv7m: write-back, write-through, а также настроек “write allocate” и “no write allocate”. Построили синтетические тесты, в которых попытались выяснить когда один режим лучше другого, а также рассмотрели практические примеры с ping и OpenCV. В Embox мы еще только занимаемся данной тематикой, поэтому соответствующая подсистема пока прорабатывается. Хотя достоинства в использовании кэшей определенно заметны.
Все примеры можно посмотреть и воспроизвести собрав Embox из открытого репозитория.
Если вам интересна тема системного программирования и OSDev, то уже завтра будет проходить конференция OS Day! В этом году она проходит в онлайне, так что желающие не пропустите! Embox выступает завтра в 12.00
- Абс что это в спорте
- Авторитарная страна что это значит