Черная консоль и неуспехи.
Прежде всего, Сони новым фирмварем наконец-то закрыла дырку, через которую я пользовал RSX. Наковыривать новую не хочется, хотя наверняка возможно. Впрочем все грамотные пацаны фирмварь не апдейтят, ждут когда это сделают другие. Стратежно.
Пост про черную консоль будет выдержан в черных тонах.
С самого начала PS3 была WoW фактором. SPU изумляли мощью и красотой. Но с первого же момента знакомства разные червячки сомнения терзали меня.
Первым червячком была задача про гистограмму. Есть входной массив байт, надо посчитать гистограмму из 256 значений. Была реализация на CUDA, которая индексировала со скоростью вроде 7 гигабайт в секунду. Я прикидывал, что два SPU разделают под орех дурацкую нвидиевскую архитектуру. В IBM Cell SDK накопал пример, который как раз гистограммы и считает. Мое изумление, но на одном SPU получалось 0.7 гигабайт в секунду. Вяло. На каждый байт приходилось чтение, запись, шаффл и арифметика. Молодцы из IBM удачно развели по латентностям, но… Все одно – даже с 6 SPU получается полный отсос. Я сильно думал, как заиспользовать SIMD, но так ничего и не надумал.
Вторым червячком была задача про хеш строк. http://users.livejournal.com/_foreseer/26491.html#cutid1
Наперво показалось что один SPU порвет PC в десять раз. По всем спекам выходило. Да и по предварительным тестам, я уже пост наизготовился писать в блог. Авотхуй. Но обо всем по порядку.
Итак. Что умеет DMA engine SPU. В числе прочего умеет он собирающие ( gather ) чтения. Ты указываешь массив из пар ( указатель, длина ). Указываешь место в локальной памяти, куда собирать, рассеянные в памяти данные укладываются туда последовательно. Все это происходит асинхронно.
Я хотел определять попадание в хеш сразу для десятков ( или сотен ) строк. И через это побеждать. Сначала читаем строки, считаем по ним хеши. Делаем DMA gather из хеш-ячеек. Потом еще один раз делаем DMA gather, поскольку данные в хеш-таблице хранятся с одним уровнем косвенности, строки все же. Потом сравниваем.
Строки я хранил SIMD группами по 16 байт. Сразу написался быстрый и качественный хеш. В котором совсем не было ветвлений и который считался в среднем десять что ли тактов на строку. Кунштюками можно и быстрее, но я ликовал и так. Сравнения строк написались тоже очень быстрые. Написались DMA gather операции, все летало, пока строк было мегабайт суммарного объема. Как только их стало 10 мегабайт – скорость просела ниже плинтуса. Стал разбираться, писать тестовые примеры на DMA gather доступ.
Паттерн доступа такой – генерится DMA list на загрузку кусков данных размером по 16 байт, случайно распределенных в куске памяти. Выполнение хронометрируется, задача запускается на одном SPU. Пока кусок памяти меньше мегабайта – то я получаю примерно 100 миллионов запросов в секунду. Что соответствует 50 миллионам поискам строчки в хеше в секунду. Как только кусок памяти больше мегабайта – швах. Опытным путем установил, что дело не в мегабайте, а в числе активных страниц памяти ( по четыре килобайта ). Пока их меньше 256, то мы отлично живем. Когда больше – то выпадаем из TLB кеша. И получаем 6 миллионов запросов в секунду… Что эквивалентно 3 миллионам поискам строки в хеше.
Чудес нет, SPU оперируют в том же страничном адресном пространстве, что и центральный процессор.
Стал думать как мапить большие страницы. Включил в своем ядре Линукса поддержку больших страниц памяти. При попытке отмапить хоть одну страничку система повисла навечно в свопе. День мучений – и плюнул.
Вот такой противный червячок. Интересно, а в играх те же 4K страницы – или почти плоская память? Поди секрет…