Category: компьютеры

Category was added automatically. Read all entries about "компьютеры".

with Cat The Cat

Сайт модульбанка

Если кто не знает, но основным достижением айфона была возможность работать (худо-бедно, но!) с обычными сайтами, а не с ухудшенными специальными мобильными версиями.

Это 2008 год. Вы работаете с 2014 года.

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

Если вам, руководители модульбанка, сказали, что такая версия нужна, то вас обманули и вытянули деньги ни за что. Если вы сами так решили, это прискорбно. В любом случае, получилось плохо и вы выглядите некомпетентно.

Это я к чему - где в мобильной версии вашего сайта вход в интернет-банк?
with Cat The Cat

Надо отметить, что был неправ.

http://science.energy.gov/~/media/ascr/pdf/program-documents/docs/Arch_tech_grand_challenges_report.pdf

Похоже, существуют определенные физические ограничения на интерфейс с памятью, которые не дают сделать баланс лучше, чем 1/5 (как у Эльбруса) даже гигантам типа Интела.

У Xeon Phi баланс примерно 1/5 и сходная тактовая частота, у NVidia Tesla - 1/10 и даже меньше, при этом тактовая частота даже меньше Эльбрусовской.

"Был неправ. Вспылил. Прошу разрешения загладить, искупить."
with Cat The Cat

Теперь не просто про VLIW вообще, а про новый планируемый Эльбрус конкретно.

Вот ссылка, которой со мной поделились в предыдущем посте: http://alexanius-blog.blogspot.ru/2014/11/8.html

Готовится новый Эльбрус, со скоростью в 1,2ГГц и пиковой производительностью в 250ГФЛОПС на числах одинарной точности.

Долго распространяться не буду, вот главное: на 250ГФЛОПС пропускной способности памяти 51Гбайт/с.

Вот другая ссылка: http://www.scientificcomputing.com/articles/2007/01/hpc-balance-and-common-sense

На один ФЛОПС производительности необходимо иметь один байт в секунду пропускной способности. Не менее одного байта, если быть точным. Два первых камня Эльбруса имели пропускной способности с запасом, примерно полтора байта на ФЛОПС.

Поэтому новый Эльбрус будет стоять. Даже не так. Он будет СТОЯТЬ!!! Как ни один VLIW не стоял до этого.

Про кадровые решения, которые должны воспоследовать, я умолчу.
with Cat The Cat

Почему VLIW это плохо.

Надо просуммировать, ибо считать Эльбрус 2СМ хорошим процессором в смысле качества архитектуры я смысла не вижу.

VLIW, Very Large Instruction Word, выдает несколько RISC-подобных команд за один такт. Команды эти двух-трёх операндные, наподобие команд MIPS. Команды группируются в длинное слово разными способами, ни один из которых не является хорошим.

Выдача длинного слова на выполнение не производится до тех пор, пока аргументы ВСЕХ команд длинного слова не готовы. То есть, если одна команда использует результат команды деления (с переменным числом тактов, для наглядности), то все команды длинного слова будут стоять в ожидании.

Источников непредсказуемой задержки у нас не так уж и много - это деление и обращение к памяти. Обращение к памяти в некоторых случаях может быть предсказано, таких случаев не много. В основном, это простая линейная алгебра и простая обработка сигналов. Все остальные задачи будут требовать устойчивости к задержкам обращения в память.

Практически все VLIW процессоры плохо работают на обычном коде, представленном в SPECint.

В обзоре Эльбруса он отставал на 7Zip от Intel Core i7 в семь раз, примерно. Отличие тактовых частот было почти 12 раз. Если бы мы замедлили Intel Core i7 до тактовой частоты Эльбруса, то его конвейер сократился бы до 5 шагов (с 20) и скорость выполнения увеличилась бы вчетверо, если не больше. А это означает, что на тактовой частоте Эльбруса гипотетический медленный i7 с длинным конвейером работал бы примерно в полтора раза медленней, а с укороченным - примерно втрое быстрее.

Команды в VLIW группируются либо по числу устройств (и дополняются NOOP до нужного числа), либо присутствует специальный бит остановки. Оба способа плохи с точки зрения двоичной совместимости. Если вы сделаете процессор с меньшим числом исполнительных устройств, то вы не можете просто так выполнять код процессора с большим числом исполнительных устройств. Потому, что одна команда может переписывать регистр, используемый другой командой длинного слова. И если вы начнёте выполнять команды последовательно, то результат будет другим, нежели при параллельном выполнении. Или вам придётся так распределять регистры, чтобы команды не пересекались по зависимостям, что не улучшает эффективности использования регистров.

Практически все VLIW процессора не имеют прямой и обратной двоичной совместимости.

Последнее прямо запрещает делать линейки процессоров с одной системой команд, как делает ARM и даже Intel. В результате VLIW это практически всегда один представитель.

VLIW требует гигантского регистрового файла. Его никто не смог сделать быстрым и небольшим (что помогает сделать его быстрым). Даже Intel с его бешеными ресурсами имеет Itanium на частоте в полтора гигагерца, когда i7 на тех же процессах давно работает на частоте вдвое большей.

Плотность кода VLIW меньше RISC в несколько раз. RISC вдвое менее плотный, чем CISC x86. Это настолько серьёзная проблема, что для VLIW DSP делают специальные компиляторы, что часть программы выдают в виде стекового кода, для компактности.

Последнее. Составление расписания выдачи инструкций базового блока (не функции и не программы!) является NP-сложной задачей. Это когда и вычисление расписания, и проверка его на оптимальность являются NP-полными задачами.

В результате, если вы делаете VLIW процессор, вы сразу ставите на нём крест, как на процессоре общего назначения. MS Word на нём будет работать плохо, процессор для телефона и для сервера вы так не сделаете.

Все эти данные известны с 2006 года, примерно.

Поэтому Эльбрус 2СМ хорош, как пример реальной системы с реализованными для него сложными протоколами периферии. Мы можем. Как процессор он плох. Но это не мешает ему быть замечательным примером, что мы можем.
with Cat The Cat

Не могу молчать.

Итак, как конфигурируется память в FPGA. Память в FPGA двухпортовая, то есть, в неё можно читать и писать одновременно. Что прикольней, у неё можно конфигурировать ширину входов (на запись) и выходов (на чтение). То есть, я могу записывать, допустим, два байта, а читать четыре. При этом на запись есть маски, чтобы можно было записать один из байтов, не трогая другой.

Если это доступно на FPGA, то это доступно и на ASIC. Потому, что это почти тривиально.

Представим себе, что мы можем писать и читать сразу 8 регистров. В восемь регистров можно уложить счетчик команд, указатель стека возвратов, указатель стека данных, регистр с вершиной стека, и ещё четыре регистра на разные нужды. Это означает, что мы можем за один такт выполнить, практически, одну команду стековой машины.

Если у нас 64 регистра, то мы можем вести 7 таких машин на одном RISC ядре. Это означает, что мы можем иметь глубину конвейера у ядра в 7 шагов и полностью загрузить наше ядро. Мы, также, можем добавить признаки готовности к нашим машинам и у нас получится приятное OOO для стекового кода.

Почему 7 машин? Потому, что одно окно будет занято обычными регистрами RISC, включая регистр с константой 0.

Что это даст?

Во-первых, компактность кода. Код для стековой машины в стиле Форт в 2+ раз компактней кода однооперандной регистровой машины типа x86. При этом код x86 (не x86-64) в два+ раз компактней кода типичного RISC.

Те, кто хотят сослаться на Dalvik vs JVM, прошу заметить, что JVM стековая машина, но код в ней не в стиле Форта. Единственный возможный вызов в JVM это вызов метода, поэтому там нет вынесения одинакового кода в подпрограмму, как это принято в Форте.

Плюс, выполняя команды RISC в определенном окне стековой машины, мы можем сэкономить на адресации регистров - 3 бита вместо 6. Это 9 бит, то есть, 23 бита при сохранении кодирования вместо 32. Четверть код урезана просто так. Principled Thumb, так сказать.

Во-вторых, чрезвычайно дешевые зеленые нити и "hyperthreading". Дешевле, чем у библиотеки времени поддержки ghc. Переключение контекста в пяток тактов - самое то.

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

В-четвертых, стековая машина чрезвычайно удобна для выполнения языков программирования с ленивой семантикой. См. TIGRE и Reduceron. ;)

Потребуется более сложный кэш данных - на два запроса (выборка команд и чтение/запись операндов/результата) одновременно.

Да, и сам регистровый код RISC никто не отменял. Достаточно дождаться окончания работы всех машин (состояние синхронизируется в регистры) и начать выполнять обычный код.

И напоследок можно это всё отлакировать сверху векторной машиной. С векторами слов в 128-256. Тогда стековая машина будет всего лишь управлять векторной, на которую и падёт проблема обеспечения производительности. По идее, это ещё и сократит размер кода.
with Cat The Cat

Умножение матриц.

Прочитал про алгоритм Кэннона.

Думается мне, его можно получить преобразованием из систолического алгоритма путём укрупнения вычислений на процессорах.

Я провёл эксперимент на своей давней модели машины потока данных, вроде, при увеличении размера обрабатываемых на одном узле подматриц получается ускорение работы.

В README дана командная строка, так вот вот чем больше сдвиг, задаваемый в параметре --taskOption=shift=n, тем быстрее выполняется умножение. При n=0 на одном узле выполняется 32 умножения матриц 1x1, n=1 - 8 умножений матриц 2x2, n=2 - 2 умножения матриц 4x4. При этом количество операций пересылки между процессорами (весьма затратная процедура, много затратней полезных операций сложения и умножения, которые считаются выполняющимися за один такт) значений падает вдвое с ростом размера подматрицы.

И напоследок алгоритмы умножения для сравнения. Простой алгоритм:
for (i=0;i < N;i&plus&plus)
    for (j=0;j < N; j&plus&plus) {
        C [i][j] = 0;
        for (k=0; k < N;k&plus&plus) {
            m = A[i][k] * B[k][j];
            C [i][j] = C [i][j] + m;
        }
    }
И алгоритм, по своим зависимостям и порядку выполнения наиболее приближенный к систолическому:
for (i=0;i < N;i&plus&plus)
    for (j=0;j < N; j&plus&plus)
        C [i][j] = 0;
for (k=0; k < N;k&plus&plus)
    for (i=0;i < N;i&plus&plus)
        for (j=0;j < N; j&plus&plus) {
            m = A[i][k] * B[k][j];
            C [i][j] = C [i][j] + m;
        }
Совершенно неправильное построение обращений к памяти с точки зрения эффективности на обычной машине. А вот на параллельной работает на ура.
with Cat The Cat

В связи с iteratees...

Вот их тип:
data Iteratee el m a = IE_done ! a
		     | IE_cont ! (Maybe ErrMsg)
		               (Stream el -> m (Iteratee el m a, Stream el))
data Stream el = EOF (Maybe ErrMsg) | Chunk [el] deriving Show
Взят отсюда.

В нём два варианта, "завершить с результатом" и "продолжить, получив кусок входных данных".

Хочу напомнить про Fudgets, а точнее, про их stream processors.

И вот их тип:
data SP i o = Nil | O o (SP i o) | I (i -> SP i o)
Здесь три варианта: "стоа", "выдать кусок результата и продолжить" и "продолжить, получив вход".

IE_done выше может быть записано, как O a Nil. IE_cont maybeErrMsg cont записывается, как O maybeErrMsg (I cont).

Ну, я немного слукавил. Сейчас исправлюсь.

Что, если мы SP параметризуем монадами? Получится вот, что:
data SPM m i o = Nil | O o (m (SP m i o)) | I (i -> SPM m i o)
Тогда IE_done result эквивалентно O (Right result) Nil. А IE_cont mbMsg cont эквивалентно O (Left mbMsg) cont.

Полный эквивалент получается такой:
newtype SPIteratee m el a = SPIteratee (SPM m (Stream el) (Either (Maybe ErrMsg) (Stream el,SPIteratee m el a)))
Правда, не проверял, работает ли. Но всё равно, получилось близко, наверняка. Ещё подкрутить, и заработает. ;)

И iteratee, и потоковые процессоры растут ногами из ленивых списков, поэтому структура у них похожа.

Давно уже хотел сделать это - напомнить о потоковых процессорах в связи с бумом iteratee.

Если что, то потоковые процессоры были одним из первых более-менее работающих вариантов взаимодействия с внешним миром в чистых функциональных языках. Они были параллельно сделаны для Haskell и LazyML. Что ещё интересней, на них была построена библиотека пользовательского интерфейса - те самые фуджеты. В начале 2000-ных я даже играл в Space Invaders, дав программе на фуджетах подключиться к моему X Window Server-у.

Пожалуй, всё.
with Cat The Cat

Вуаля!

Итак, моя модель MIPS начала выдавать первые выборки (если возвращать NOP ;).

Я добавил тест, вот результат его запуска:
*MIPS_with_mem> fetchesOfMIPSWithSeroesMemory_S
40000000
40000004
40000008
4000000c
40000010
40000014
40000018
4000001c
40000020
40000024
*MIPS_with_mem>
(запускать надо "ghci -fcontext-stack=100 -istreams -icommon MIPS_with_mem.hs")

Мы всегда передаём 0 в качестве результата выборки, в системе команд MIPS это NOP, поэтому наш процессор последовательно перебирает адреса команд.

(достаточно сложная система вдруг заработала с первого раза, хоть и на простом тесте)

Что же там происходит.

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

Однако, в обычной функции отсутствует понятие (дискретного) времени, она не может напрямую работать с бесконечными списками данных. В основном, это ограничение операции сравнения с образцом case: если я сравниваю со значением, погруженным в конструктор (бесконечного списка), то мне надо этот конструктор разобрать. Все остальные операции могут быть подняты на бесконечные списки простой перегрузкой с помощью map_S, zipWith_S и тп.

Поэтому для введения дискретного времени необходимо прозрачно поднять эти операции. Это выполняет модуль Trans в каталоге streams, функцию transform которого можно использовать для проведения такого преобразования.

Преобразования оставляют исходные функции. Их можно рассматривать, как самый первый такт работы системы. А если ваша система сделана модульно и в ней разнесены функции, вычисляющие значения и функции, защёлкивающие значения - содержащие функцию register, - то тестирование сведётся к тестированию первой из них. На дискретное время всё будет распространено довольно прозрачно.

Вот кусочек исходного текста:
cond = case cmd of
	JALR rs rd -> True
	JR rs -> True
        ...
Вот, как он поднимается на бесконечные списки:
cond_14 = S.map_S (\caseExprVar_15 -> case caseExprVar_15 of
    MIPS.JALR rs_16 rd_17 -> GHC.Bool.True
    MIPS.JR rs_18 -> GHC.Bool.True
    ...
Всё незамысловато.

Если кому интересно, то при работе transform создаётся trans_log, куда пишутся результаты преобразований. Однако там слишком много информации.

Что хочу сделать.

Надо сделать ассемблер MIPS и запустить пару программ посложнее.

Хочу сделать ведение отчётов. Чтобы можно было написать в преобразуемой функции что-то вида currentAddressTwoLeastBits = report (currAddr .&. 3) и в результаты работы, в выходы функции, попадали бы все такие report в виде строки "currentAddressTwoLeastBits = 3".

После того, как заработает модель MIPS на реальной программе, я хочу сделать создание текста на настоящем HDL в виде иерархии сущностей. Само собой, сразу должен получаться синтезируемый код. Пока в качестве основного претендента выступает VHDL, он поудобней будет, хотя и многословен. Вариант - SystemC, для повышения скорости моделирования.

Далее преобразование функции в конвейер (чтобы поднять тактовую частоту, будет и для модели на бесконечных списках и для синтезируемого HDL) и тому подобные мелкие улучшения.
with Cat The Cat

Тут у ivan_ghandhi случилось обсуждение...

...и я выяснил кое-что про Reduceron.

Вся его реализация занимает 14% от 17300 слайсов (slices) Xilinx Viertex-5. Прикинув, что слайс равен 4-м 4И-НЕ вентилям, я получил оценку в 10000 вентилей. Или 80000 транзисторов.

Ещё он занимает 90% полуторакилобайтной памяти. Это, исходя из оценки в 6 транзисторов на бит памяти, даёт ещё 66000 транзисторов.

Итого, 150 тысяч транзисторов. Это уровень количества транзисторов процессоров GreenArrays, творений Чака Мура.

В тысячи раз меньше, чем современные процессоры уровня Core2 Duo. Да добавим кэш, всё равно площадь будет в сотни раз меньше - единицы квадратных миллиметров.

Тактовая частота синтеза в ASIC поднимается раз в 8-10 по сравнению с частотой FPGA. Reduceron получит частоту в районе 700-800 MHz. Отставая сейчас в три раза, он будет быстрее в два раза, если сделать ASIC.

Получается, что эта штука будет работать быстрее и меньше занимать.

Сейчас в haskell-cafe напишу. ;)

PS
http://www.1-core.com/library/digital/fpga-logic-cells/

Ошибся в количестве эквивалентных 4И-НЕ. Там их 8 на slice. Ошибся в два раза.

Ну, не в 10, и то хорошо. ;)
PPS
С частотой я тоже поторопился. 5-8 раз.