Быстрое перемножение матриц — конкурс
Автор: ZealintФев 8
Время: 2 недели (8 февраля — 22 февраля 2010 г.)
Конкурс завершён.. Здесь подводятся его итоги.
На своем блоге я буду проводить много конкурсов, связанных (прямо или косвенно) с научными задачами. Конкурсы будут как с платным, так и с бесплатным участием. Это первый конкурс, и чтобы не распугать людей, он будет с бесплатным участием, но и призовой фонд будет не слишком большим — 1000 р.. По этой причине предлагается задача, которую любой опытный программист сможет реализовать за 10-15 минут (а при знании продвинутых алгоритмов — за час): перемножение двух квадратных матриц с заданным размером n на n. Победителем станет тот, чья реализация будет работать быстрее реализаций остальных участников (подробности о числе победителей ниже). Хотите заработать 1000 р. за (максимум) час работы? Тогда участвуйте!
Положения
Общие правила и ограничения
- Операционная система — Windows XP SP3.
- Тестирование производится на компьютере с процессором Intel Core 2 Duo 8400 (3000 MHz) 2GB DDR2-800.
- Программа должна использовать не более одного процесса и одного потока в нём. Несмотря на то, что процессор двухъядерный, разрешается использовать только одно ядро на 100% его мощности.
- Запрещено использовать динамически-подключаемые библиотеки (dll).
- Программа должна быть представлена в виде одного только исполняемого EXE файла и работать корректно без необходимости установки дополнительного ПО. Исходите из варианта, что у Вас есть лишь «голый» Windows XP.
- Программа должна использовать не более 1Gib (230 байт) оперативной памяти.
- Время работы программы на каждом тесте не должно превышать 900 секунд.
- Максимальный порядок матрицы в тесте n = 5000.
- Элементы матрицы — целые числа, не превосходящие по модулю 600.
- Программа должна работать в консольном режиме, то есть никаких графических интерфейсов писать не нужно. Ваша программа считывает матрицы из входного файла (который будет находится в той же директории), перемножает их и выводит ответ в другой файл (в ту же директорию). Подробнее о формате ввода / вывода см. ниже.
- Конкурс завершается 22 февраля ровно в 12 ч. 00 м.
- Оплата только через Яндекс.Деньги или WebMoney.
- Я оставляю за собой право менять правила проведения конкурса, если в них обнаружатся неточности.
Порядок проведения конкурса
- Во время проведения конкурса участники посылают на электронный адрес «zealint.comp@gmail.com» письмо с темой «Быстрое Перемножение Матриц — Конкурс». В теме необходимо указать свой ник, язык программирования и название компилятора, которым вы пользовались, укажите какими надстройками вы пользовались (boost, atlas, blas и т. д.) или вы реализовали алгоритм самостоятельно (ручная реализация). Прикрепите к письму EXE файл, который будет тестироваться. Файл назовите «<ваш ник>.exe». Внимание: узнал, что gmail не пропускает EXE файлы даже в сжатом виде. Давайте переименовывать их в mp3 и архивировать rar или zip.
- По мере тестирования поступающих программ, результат их работы будет указываться в таблице рейтинга, внизу этой страницы. Участник может присылать новые версии программы не более одного раза в сутки. Если участник посылает более одной версии за сутки, учитывается только последняя, а остальные удаляются.
- Присланная участником версия программы засчитывается и попадает в рейтинг только в том случае, если она выполняет все тесты без ошибок, укладывается в указанные ограничения по времени и по памяти, а также (если это не первая версия автора) работает хотя бы на 2% быстрее его предыдущей программы.
- Победившим считается тот участник, программа которого оказалась самой быстрой на момент завершения конкурса. Но при условии, что она работает хотя бы на 1% быстрее, чем программа его ближайшего соперника. Если времена работы лучших программ у нескольких человек отличаются менее, чем на 1%, то приз делится между победителями поровну.
- (Дополнено 10.02.2010) Поскольку я тоже участник конкурса, мне проще участвовать. Поэтому я предлагаю уровнять шансы: как только моя программа оказывается в ТОПе, или просто начинает работать быстрее, я сразу делюсь подсказками о том, как я её улучшил. Только не ждите, что это будут прямые подсказки типа листингов кода.
Формат входных и выходных данных
- Программа должна считывать данные из файла «input.txt».
- Программа должна записывать ответ в файл «output.txt» (и должна сама создавать его по мере необходимости). Запрещается выводить какую-либо информацию на экран.
- Во входном файле содержится следующая информация: в первой строке записано число n — порядок матриц. В следующих n строках, в каждой из которых n чисел, записаны строки первой матрицы, а дальше точно так же (n строк по n чисел) записана вторая матрица. Например, так может выглядеть входной файл:
2
1 3
3 4
2 1
0 3
в нем две матрицы 2×2. В выходной файл нужно записать результат произведения матриц:
2 10
6 15
Все числа отделяются друг от друга пробелом или табуляцией, а также символом перевода строки.
Гарантии
Я гарантирую, что победитель(и) получит(ат) приз в соответствии с правилами. Во-первых, я собираюсь проводить другие конкурсы. Зачем мне кого-то обманывать? Во-вторых, вы же мне ничего не платите, и я даже не требую предоставлять мне исходный код программы. В-третьих, если вы подумали, будто мне нужна программа перемножения матриц и будто я сам не могу её нормально написать, то это далеко не так. Тысячу рублей я так просто не отдам — соревнуйтесь со мной и заберите приз! : ) После завершения конкурса я предоставлю тесты, на которых проверялись ваши программы, и вы сами сможете потестировать. Заметьте, что я не запрещаю пользоваться самыми продвинутыми на сегодняшний день средствами программирования, в том числе библиотеками, в которых есть функции работы с матрицами. Мне нужен только один исполняемый файл, все честно. Так что не волнуйтесь.
Пожелания
По мере проведения конкурса привлекайте новых участников. Мой блог не так сильно раскручен, поэтому участие хотя бы 10 человек я буду считать большим успехом.
После окончания конкурса я, по вашему желанию, установлю ссылки с этой страницы на главные страницы вашего сайта, при условии, что вы установите ссылку со своей не главной страницы на эту. Все ссылки без noindex и nofollow. Также любой участник может поделиться своим исходным кодом, который я выложу для общего доступа вместе с моими тестами и программами всех участников.
Если пишите комментарии, то подписывайтесь тем ником, который у вас отображается в таблице рейтинга (если отображается).
FAQ
Некоторые участники форумов программистов начинают задавать одни и те же вопросы (или высказывать соображения), на которые надоедает отвечать. Поэтому делаю список часто задаваемых вопросов
- Что за тупой конкурс? Ответ: идите нафиг.
- Вы правда думаете, что за 1000 р. люди сразу побегут к вам писать программы? Ответ: не нравится — не участвуйте. 1000 р. за 15 минут (или за час) работы я считаю нормальным. Конкурс не для всех, а для тех, кому интересно писать оптимальный код. В будущем я сделаю другие конкурсы. Но они будут гораздо сложнее. Настолько, что даже профессионалам будет здесь делать нечего. Это будут конкурсы для математиков-программистов, а не для промышленных программистов. И призы будут на порядок больше. Но все это так сразу не делается, я провожу свой первый конкурс, поэтому он такой простой и недорогой.
- Тут без ассемблера и SSE не обойтись! Ответ: я совершенно не ограничиваю вас в выборе инструмента. Такой вопрос часто задают те, кто плохо понимает для чего нужен ассемблер. Предупреждаю, что машинной оптимизацией лучше заниматься после того, как выполнили все алгоритмические оптимизации. Например, посмотрите на время работы моих программ v0 и v1. Разница почти в пять раз. Оптимизация до жути простая — замена второй матрицы на транспонированную с соответствующим изменением порядка суммирования. И ВСЕ! Причина простая — кэш стал использоваться более оптимально. Так что думайте прежде, чем садиться за машинный код.
- Я 5 лет работаю программистом и понятия не имею что такое Перемножение Матриц. Ответ: программисты бывают разными, например, web-программисты и т. д. Конечно же, если вы не понимаете в чем состоит задача и почему в ней надо думать — это конкурс не для вас. Это для тех, кто умеет писать оптимальный код для вычислительных задач, то есть для тех, кто на этом специализируется. Конечно же этим конкурсом я не хочу обидеть остальных программистов, которые сильны в какой-то своей области. Это просто не для них и все.
- То, что вы являетесь участником и организатором дает вам те или иные преимущества — это нечестно, например, вдруг Вы мега-крутой программист и уже написали кучу программ, а самую лучшую оставили на потом и «спалите» её в конце, когда не будет времени отыграться? Ответ: ничего подобного. Моя самая лучшая программа — это та, которая в рейтинге. Я точно так же, как и все участники начинаю думать «что делать?», когда меня кто-то обгоняет. Здесь, конечно, вам придется поверить на слово. Скажите тогда, а зачем мне надо было делать конкурс? Чтобы поиздеваться над народом? Нет, я делаю его для того, чтобы понять чего можно выжать из различных подходов и пр. Вот если бы конкурс был с платным участием, то я бы понимал ваши опасения, а так, что волноваться-то? Впрочем, я понимаю, что одно преимущество у меня все-таки есть — я получаю программы в своё распоряжение и могу делать с ними что угодно, например, анализировать время работы на самых разных тестах (не выпадающих из условий). Что это даёт? Появляется интуитивное ощущение того, что лучше а что — хуже. Поэтому я, пожалуй, изменю немного правила. Как только улучшается время работы моей программы, я сообщаю, каким методом я это время улучшил. Итак, почему моя v1 работает быстрее v0 я написал в ответе на вопрос 3. Остальное будут выписывать в комментариях. В конце конкурса сделаю резюме.
- Что значит «голая» винда? Ответ: Windows XP SP3 32-bit. Хотя если я не указал этого ранее, то, видимо, не так важно. В целом, они все довольно хорошо совместимы и все-таки понятно, что XP пока более распространена (из всех Windows). Главное здесь пожалуй — 32 бита.
- А вы учли, что размер входного вайла 238Mб и оно долго считывается? Ответ: Конечно, в моей программе ввод занимает 12 секунд и вывод около того. Эту часть кода я буду оптимизировать после того, как время самих вычислений окажется более-менее сравнимым с временем ввода. Считывание из файла — принципиальное ограничения конкурса. И вообще, ограничения обсуждению не подлежать. С одним замечанием только соглашусь — я обидел тех, кто любит Linux. Но для них конкурс ещё будет.
Окончательный рейтинг
Конкурс завершён. Здесь подводятся его итоги.
Таблица ниже будет постоянно обновляться по мере поступления новых программ. Внимание: прежде чем присылать программу, убедитесь, пожалуйста, что она укладывается в отведённое время на самом большом тесте и при этом не использует оперативной памяти больше, чем указано в правилах. Также убедитесь, что она работает не намного медленнее, чем реализация текущего лидера (учтите также разницу между вашим процессором и тем, на котором я тестирую). Удачи!
- venco[v4] :: C++ GCC 4.0.2 :: 21.02.10 :: 7,52 с.
- venco[v3] :: C++ GCC 4.0.2 :: 20.02.10 :: 8,86 с.
- venco[v2] :: C++ GCC 4.0.2 :: 18.02.10 :: 9,3 с.
- venco[v1] :: C++ GCC 4.0.2 :: 16.02.10 :: 10,84 с.
- blackmirror[v1] :: fasm :: 22.02.10 :: 11,13 с.
- Zealint [v7] :: Intel C++ 11.1 + ASM (Вин.-Штр.) :: 22.02.10 :: 11,33 с.
- Zealint [v6] :: Intel C++ 11.1 + ASM (Вин.-Штр.) :: 21.02.10 :: 12,66 с.
- venco[v0] :: GCC 4.0.2 + GCC Intrinsics :: 15.02.10 :: 13,22 с.
- Zealint [v5] :: Intel C++ 11.1 + ASM (р. реал.) :: 19.02.10 :: 18,34 с.
- alexBlack [v3] :: Delphi (ручн. реал.) + MMX :: 14.02.10 :: 19,2 с.
- blackmirror[v0] :: Microsoft Visual C++ 2008 :: 18.02.10 :: 22,14 с.
- alexBlack [v2] :: Delphi (ручн. реал.) + MMX :: 12.02.10 :: 22,8 с.
- Zealint [v4] :: Intel C++ 11.1 + ASM (р. реал.) :: 16.02.10 :: 33,00 с.
- ghoul [v2] :: GCC 3.4.5 + gotoBLAS2 1.13 :: 12.02.10 :: 35,84 с.
- Zealint [v3] :: Intel C++ 11.1 (ручн. реал.) :: 13.02.10 :: 55,09 с.
- Ulex :: Masm 6.14.8444 :: 11.02.10 :: 57,74 с.
- covax :: MS VC 2010 :: 15.02.10 :: 62,89 с.
- Zealint [v2] :: Intel C++ 11.1 (ручн. реал.) :: 11.02.10 :: 94,58 с.
- alexBlack [v1] :: Delphi (ручн. реал.) :: 11.02.10 :: 106,3 с.
- alexBlack [v0] :: Delphi (ручн. реал.) :: 10.02.10 :: 112,2 с.
- ghoul [v1] :: GCC 3.4.5 + gotoBLAS2 1.13 :: 11.02.10 :: 124,31 с.
- yakasuka :: VS6 (ручн. реал.) :: 10.02.10 :: 144,44 с.
- Zealint [v1] :: GCC 3.4.5 (ручн. реал.) :: 10.02.10 :: 154,78 с.
- ghoul [v0] :: GCC 3.4.5 + BLAS :: 10.02.10 :: 310,88 с.
- Zealint [v0] :: GCC 3.4.5 (ручн. реал.) :: 8.02.10 :: 805,56 с.
Следите за конкурсами на моём блоге, дальше будет сложнее и интереснее.
Информационные спонсоры
КиберФорум — форум начинающих и профессиональных программистов, системных администраторов, администраторов баз данных. Компьютерный форум.
Клуб ПРОграммистов — Форум программистов.
Обсуждение конкурса на форуме в этой теме.
Число комментариев: 65
Комментарий от on 08.02.2010 - 20:26
Может пару больших тестов открыть? Потому как большие будет трудно самому генерировать(при тестировании до отсыла решения). Одной матрицы порядка 5000 будет достаточно))
Комментарий от on 09.02.2010 - 10:05
Постараюсь поучаствовать!
Комментарий от on 09.02.2010 - 10:55
Михаил, нет смысла это делать. Сгенерировать файл с тестом — это два цикла написать. Сделайте, скажем, простой тест из одних единиц в матрице. Ответом будет матрица из чисел «5000″. Или вообще заполните матрицу случайными числами. Не вижу проблемы. В любом случае, если ваша программа завалится на меленьком тесте, я подскажу, в чем проблема, переслав Вам аналогичный тест. Кстати, Михаил, Ваш комментарий почему-то попал ко мне в спам, поэтому так долго не появлялся… сейчас все в порядке.
Комментарий от on 09.02.2010 - 16:24
Да, действительно не нужно)) Я сгенерировал пару матриц, файл получается размером более 200 мб.
Комментарий от on 09.02.2010 - 17:03
Есть мнение, ассемблер надо юзать
Комментарий от on 09.02.2010 - 17:16
Тов. worm2, можете юзать что угодно — я специально не ограничиваю выбор, чтобы посмотреть на что народ способен. Но я бы предложил начать с малого! Уверен, что и без ассемблера можно раз в 5 ускорить. А вы хотите сразу рекорд поставить! Предлагаю простой ход — давайте сначала переплюнем границу в 300-400 секунд? Жду программ… и сам тоже пишу…
Комментарий от on 09.02.2010 - 17:22
А… я сначала подумал, что Вы уже свой вариант оптимизировали как могли, и больше уже не можете. Оказывается, можете
Комментарий от on 09.02.2010 - 17:31
Могу, например, я еще не учел то, что на указанной машине кэш L2 6Мб. Возможно, это как-то может помочь, я пока не знаю, как именно. Теоретические, сделать быстрее 300 секунд можно обычным решением «в лоб». Думаем…
Комментарий от on 09.02.2010 - 17:37
Да, пожалуй, я был не прав. В первую очередь мозги надо юзать. Алгоритмическая оптимизация на таких больших матрицах, наверное, даст большой выигрыш. Небось, алгоритм Штрассена был бы тут как раз… Но это уже задача не на час работы
Комментарий от on 09.02.2010 - 18:18
Да? Вы, кстати, зря всем рассказываете, что можно делать — остальные возьмут ваши идеи и все : ) Штрассена я буду делать в последнюю очередь, если проигрывать сильно начну. Пишется он меньше, чем за час, семь матриц туда, три — туда и готово… Только полтора десятка сложений вместо одного умножения дает log 7 в показателе степени, что не сильно меньше 3… так что нужны будут мозги, чтобы это чудо работало.
Комментарий от on 09.02.2010 - 20:16
Ну, идеи стоят 10 копеек за пучок
А вот реализовать их с максимальной эффективностью на конкретной платформе — это повозиться надо.
Комментарий от on 09.02.2010 - 21:33
И как это обойти?
Комментарий от on 10.02.2010 - 05:33
Время чтения/записи данных тоже учитывается при замерах?
Комментарий от on 10.02.2010 - 06:01
Товарищи, только что узнал, что gmail блокирует EXE, некоторые уже послали программы, но они не прошли. Давайте менять расширение на mp3 и потом архивировать rar или zip!
При замерах учитывается все от начала работы программы до её завершения.
Комментарий от on 10.02.2010 - 10:15
>> При замерах учитывается все от начала работы программы до её завершения.
А ничего что при объёмах данных порядка 200 мб время на чтение/запись уже является достаточно большим относительно выполняемых операций?
Комментарий от on 10.02.2010 - 11:09
Тов W4FhLF, да, это много. У меня целых 12 секунд ввод, если через scanf, и около секунды, если делать ввод руками. Вывод — почти аналогично. Кэш диска — 16Мб. Ну и что? Это время все равно больше, чем время счета, так что пока не важно.
Комментарий от on 10.02.2010 - 11:13
Несколько человек уже прислали программы, но у всех те или иные ошибки (несоблюдение правил). Друзья, давайте внимательнее читать правила, я специально так подробно написал, чтобы не было недоразумений. Тем временем я оптимизировал свою программу немного. Жду, кто быстрее!
Чуть выше таблицы рейтинга появилось FAQ. Советую прочитать, если кто-то чувствует, что он в танке.
Комментарий от on 10.02.2010 - 12:40
Можно узнать как проводится валидация результата? Числа сравниваются с учётом машинной погрешности?
Комментарий от on 10.02.2010 - 13:10
W4FhLF, числа целые, какая тут может быть погрешность? Ответ совершенно однозначный.
Комментарий от on 10.02.2010 - 14:29
Меня победили: 144 против 154. Итак, что дальше? Штрассена я писать не хочу и не факт, что он будет быстрее… Но как одну из возможностей, её нельзя упускать. Попробую сменить компилятор. По условиям можно посылать новую версию через сутки, этого хватит, чтобы скачать что-нибудь получше GCC.
ВОПРОС: Можем ли мы преодолеть 100 секунд?
Комментарий от on 10.02.2010 - 14:31
Zealint, да, я не заметил. Но это не очень хорошая идея. Современные процессоры лучше оптимизированы для работы с float числами. Т.е. это аппаратные особенности. Если рассматривать продвинутые возможности расширенного набора инструкций, то при прочих равных целочисленная арифметика в несколько раз (!) медленнее арифметики с одинарной точностью.
Комментарий от on 10.02.2010 - 15:24
Товарищь W4FhLF, вы заблуждаетесь и вот почему: даже если при некоторых условиях (скажем, которые вы назвали) плавающие данные обрабатываются быстрее, то никто вам не мешает Вам интерпретировать входные данные как числа с плавающей точкой и проводить вычисления для них. А потом выводить ответ с 0 знаков после запятой. Кто вас ограничивает? Пусть будет float — те же 4 байта, что int.
Комментарий от on 10.02.2010 - 15:31
Еще один участник всех обогнал со временем 112,2. Что любопытно — программа была на Delphi. Еще любопытнее то, что на маленьких тестах (до n=500) программа работала гораздо медленнее моей.
Комментарий от on 10.02.2010 - 15:41
Zealint, вы заблуждаетесь, ибо если рассматривать целые числа как float, то будет накапливаться ошибка и при переводе float -> int мы получим погрешность (начиная с 5го знака). При больших значениях результаты совпадать не будут.
Но да ладно, я уже сделал для целых чисел )
Комментарий от on 10.02.2010 - 15:57
Нет, W4FhLF, все-таки Вы заблуждаетесь. В задаче принципиально то, что максимальные элемент в матрице (в ответе) близок к 2 000 000 000. Это означает, что float вам не помог бы при всем желании, и я просто пошутил. Но я же не сказал, что запрещено использовать double. Если у Вас получится сделать вычисления с плавающей точкой быстрее — это будет здорово, но я сильно сомневаюсь в успехе. И более того, еще будут конкурсы, где числа будут гораздо больше по размеру…
Комментарий от on 10.02.2010 - 16:20
В порядке брюзжания замечу, что замена второй матрицы на транспонированную — это не алгоритмическая оптимизация, а самая что ни на есть машинная
Лично у меня других идей, кроме тех, что уже высказаны, нет. А реализовывать их ломает. Так что я лучше на других посмотрю
Комментарий от on 10.02.2010 - 16:40
worm2, может быть, но это, по крайней мере, не низкоуровневый подход. Это просто как два индекса местами поменять : )
Кстати, я немного изменил правила своего участия в конкурсе. Решил, что когда моя программа начинает работать быстрее, я сразу пишу в комментариях подсказки, типа, каким образом я сделал её быстрее. Это даст всем участникам равные шансы, поскольку подсказки не будут очевидными и, возможно, далеко не все эти подсказки смогут воплотить в жизнь. Скажем, не все захотят реализовывать Штрассена. Да? Кроме того, реализовать ту или иную оптимизацию тоже надо уметь грамотно. С одной стороны это делает конкуренцию сложнее, а с другой — упрощает жизнь тем, кто плохо (как и я) разбирается в линейной алгебре. При этом, конечно же, я не рекомендую остальным тоже подсказывать. Если выиграю не я, то победитель, я надеюсь, пару слов напишет о том, что он сделал…
Комментарий от on 11.02.2010 - 12:33
Итак, барьер в 100 секунд мы преодолели. Как? Во-первых, так как процессор Intel Core 2, то логичнее было бы использовать родной для него компилятор, да ещё и с опциями максимальной оптимизации и с разрешением подключения SSSE3. Такой подход, уменьшил время работы программы v1 на 33 секунды, но этого все равно не хватало для того, чтобы догнать лидера. Радикальный скачок произошёл снова благодаря правильному использованию кэша. Смотрите сами: числа в исходных матрицах меньше 32767, а большими они становятся только в ответе. Значит как надо хранить исходные матрицы? Все, подсказал дальше некуда : )
Комментарий от on 11.02.2010 - 15:35
Отличный результат у тов. Ulex: 57 секунд! Что ж, ассемблер (в умелых руках) конечно лучше, кто бы сомневался : ) А меньше 50 секунд мы можем сделать? Это будет следующая цель! Вот к ней сейчас и пойду… Кто со мной?
Комментарий от on 11.02.2010 - 20:08
Меня все время спрашивают на форумах, почему я Linux не хочу добавить в список ОС… На самом деле я был бы рад это сделать. Например так: Windows и Linux имеют отдельный рейтинг. Участник имеет право участвовать и там, и там. Приз за Linux тоже будет 1000 р. (то есть самый опытный сможет выиграть 2000). Просто соревноваться друг с другом на разных операционках не вижу смысла — не объективно. Поэтому будет как бы два конкурса.
НО ВОТ ПРОБЛЕМА: какой Linux выбрать? Что бы я не выбрал, кто-то обязательно скажет, что ему такая система не нравится (и даже найдёт этому обоснование). Кроме того, Linux будет «голым», а на нем будет ли запускаться программа, скажем, на boost, если не установлены специальные .os файлы? Наверно не будет. Так что же делать? Я не знаю, поэтому от Linux и отказался с самого начала.
Если никто не предложит разумного варианта, при котором мне не придется ставить 50 линуксов и на каждый ставить по 10 библиотек, то и не будем добавлять его в конкурс. Надо так: Linux должен быть один и «голый» — чтобы у всех были равные возможности.
Комментарий от on 11.02.2010 - 21:25
Все-таки зашел посмотреть, что за конкурс.
В общем, имхо, под виндой не корректно по времени работы оценивать подобные приложения.
Сейчас тупо влом приводить тут все аргументы.
Более подробно отвечал тут: (в теме с объявой о конкурсе).
З.Ы. а на блог надо бы контента понаписать, перед тем, как продвигать его .
Комментарий от on 12.02.2010 - 07:56
3V, ответил Вам на форуме. Кстати, я блог и не продвигаю : ) Продвигать буду еще не скоро. Мне сейчас хочется делать конкурсы.
Комментарий от on 12.02.2010 - 07:58
Товарищи, некий тов. ghoul сделал невероятный прорыв: почти полминуты! Я начинаю подозревать, что все-таки можно сделать < 30 секунд. Кто первый?
Комментарий от on 12.02.2010 - 19:43
Можно попробовать оценить теоретическую нижнюю границу времени счёта, просто считывая операнды из памяти, но не перемножая их (разумеется, читать нужно так, как будто мы бы хотели перемножить, только само умножение исключать). На моём компе, например, эта граница около 70 сек (тривиальный алгоритм, без Штрассенов, также без чтения/записи данных; правда, возможно ещё как-то оптимизировать за счёт хитрой перестановки элементов для оптимизации по кэшу…).
Комментарий от on 12.02.2010 - 20:28
Итак, у нас новый лидер, который ещё и первым преодолел 30 секунд!
Кстати, я напоминаю, что берётся процессорное время работы программы. То есть у всех бывают моменты, когда программа ждёт жёсткий диск. В этот момент загрузка процессора равна 2-3 процента (особенно если мышкой шевелить). Конечно, это время счётчик не учитывает. При запуске всех программ, у которых быстрый вывод в файл, диск страшно трещит, но процессор почти не работает. Это продолжается секунды 4 (поскольку диск один и тот же, сравнение разных программ остаётся объективным). То есть теперь, когда у нас такие небольшие времена работы, учтите, что реально к ним надо прибавить где-то 4 секунды (зависит от диска).
Ну что, двигаемся к отметке 20 секунд? Страшно подумать…
Комментарий от on 13.02.2010 - 14:43
Немного ускорил программу (версия v3) следующим образом: развернул матрицу в массив, затем провел оптимизацию кода так, чтобы в циклах вообще не было умножения чисел, кроме умножения самих элементов матрицы. То есть вместо A[i][j] при разворачивании матрицы надо использовать A[i*n+j] (если отсчёт от 0), так вот, все такие умножения я полностью убрал. Заменил их сложением и вычитанием указателей с числом n в нужных местах. Потом скомпилировал с опциями
/fast /QxSSSE3
Комментарий от on 13.02.2010 - 20:56
Zealint, не отставай от конкурентов!
Комментарий от on 14.02.2010 - 07:04
Ну, во-первых, они не конкуренты, а участники (для меня — соперники). А во вторых, соперники довольно сильны, что меня очень радует. Есть у кого поучиться!
Комментарий от on 14.02.2010 - 20:54
Итак, 20 секунд преодолены! Я в значительной мере удивлен. А меньше 17 кто сможет? Если это вообще возможно… Хотя, до недавнего времени многие были уверены, что меньше 30 — нереально : )
Комментарий от on 15.02.2010 - 06:49
Друзья, 13 секунд! А ещё только неделя прошла. Нереально быстро. Ничего не остаётся, как двигаться к 10 секундам. Это будет феноменальным результатом!
Комментарий от on 16.02.2010 - 06:50
Лидер venco творит чудеса: уже подошёл к 10-ти секундной черте! Осталось сделать лишь небольшой шаг.
Свою программу я тоже начал улучшать, ещё 22 секунды снял следующим образом: матрицу разбиваю на блоки, которые помещаются в кэш, перемножаю блоки отдельно и складываю в нужном порядке. При перемножение блоков «в лоб» использую инструкции MMX, в частности ту, которая перемножает и попарно складывает 4 слова за одну команду. Узкое место: два обращения к памяти во внутреннем цикле.
Комментарий от on 16.02.2010 - 13:39
Сдаётся мне, у лидеров старина Штрассен уже задействован на полную катушку (а то и что позабористей
). Иначе никак не могу объяснить производительность в почти 4 операции умножения на такт (PMADDWD, конечно, 4 умножения и 2 сложения умеет, но она вроде как 2 такта просит), а ведь там ещё нужны сложения…
Али тут конвейер какой крутой (к сожалению, особенностей конвейера Core2Duo не разумею) и по 5 команд на-гора выдаёт за такт?
Но чего я никак не могу понять, как память такую скорость держит. Понятно, что маленькие матрицы влезают в L1, но ведь их ещё потом складывать и складывать промеж собою…
Комментарий от on 16.02.2010 - 13:42
Но GCC Intrinsics’ам по любому респект и уважуха
Если там кода на асме нет, снимаю перед ними шляпу.
Комментарий от on 17.02.2010 - 21:21
Во первых это не ММХ, давайте лучше называть это SIMD.
Во вторых GCC Intrinsics’ам это и есть ассемблер только команды записаны в виде процедур нужно чтобы компилятор понимал какие регистры задействованы.
pmaddwd (4 умножения + 2 сложения)требует 1 такта.
Сложение paddd (2 сложения) занимает на его процессоре 0.3 такта, на предыдущем поколении 1 такт.
Считывание из кеша L1 тоже 1 такт.
А еще не забываем что у нас несколько АЛУ. За такт можно выполнить две pmaddwd за такт и параллельно считывая данные из кэша в регистры.
> и по 5 команд на-гора выдаёт за такт?
В идеале 6 сможет.
Все времени нет программу написать. Но пару тестов прогнал и теоретически с практическими выкладками таковы.
На прямом алгоритме. С оптимизацией обращений к кэшам и распределением регистров получаем. 13.2с тормоза на чтение. Мне регистров не хватила для качественной оптимизации. А вот если бы регистров хватило то имели бы 10.5с
Основные тормоза классического алгоритма это работа с кэшем. Просто блоками считать.
А вот Штрассен он примерно в 10 раз быстрее классического алгоритма.
Комментарий от on 17.02.2010 - 23:55
> А вот Штрассен он примерно в 10 раз быстрее классического алгоритма.
Каким образом в 10 раз? Даже без потерь на сложения Штрассен теоретически может быть быстрее в 5000^(3-log_2 7) = 5 раз.
В реале из за потери на сложения у меня Штрассен получился максимум в полтора раза быстрее.
Комментарий от on 18.02.2010 - 01:46
Еще потери на перевод числа туда-сюда из-в десятичной записи, тоже думаю пару секунд на это потратится.
venco, подскажите длину линии L1 на этом процессоре, 64 байта? Попробую переделать с учетом кеша, хочу секунд в 20 уместиться.
Комментарий от on 18.02.2010 - 06:20
Ну вот, 10 секунд уже не предел… Следующая цель — меньше 8 секунд.
А кроме Штрассена есть что-либо, работающее быстро на таких ограничениях?
Комментарий от on 18.02.2010 - 07:41
А кто-нибудь знает, как реализована команда _mm_set1_ps(x)?
У меня нет возможности проверить и в man не нашёл, но я подозреваю, что это нечто вроде:
movaps xmm0, x
shufps xmm0, xmm0, 0
Да?
Комментарий от on 18.02.2010 - 20:01
Почти так:
movss xmm0,x
shufps xmm0, xmm0, 0
Комментарий от on 18.02.2010 - 20:20
> А кроме Штрассена есть что-либо, работающее быстро на таких ограничениях?
Может оказаться быстрее какой-нибудь специализированный алгоритм, если в матрицах есть какая-либо структура.
Комментарий от on 18.02.2010 - 22:21
>А кроме Штрассена есть что-либо, работающее быстро на таких >ограничениях?
Вы не поверите, но кажется я придумал.
Комментарий от on 19.02.2010 - 00:38
Не, я сдаюсь. venco, покажите код
Комментарий от on 19.02.2010 - 08:16
> А кроме Штрассена есть что-либо, работающее быстро на таких ограничениях?
Алгоритм Копперсмита — Винограда. Как-раз для квадратных матриц. Сложность O(n^2.38)
Комментарий от on 19.02.2010 - 08:21
Правда толку от него немного.
Комментарий от on 19.02.2010 - 09:11
Сложность мало о чём что говорит, поскольку выводится из соображений, что n стремится к бесконечности. А у нас всего 5000, поэтому, этот «самый лучший» алгоритм не подходит. Было бы интересно написать и убедиться в этом. У меня есть статья авторов алгоритма, но читать её жутко.
Комментарий от on 19.02.2010 - 21:13
Наконец-то и мне удалось преодолеть 20-ти секундный барьер. До этого я использовал mm регистры (64 бита), теперь узнал, что на xmm регистрах операция pmaddwd выполняет 8 умножений и 4 сложения за один такт. Это позволяет за один такт перемножить две 2×2 матрицы. Еще несколько операций нужны для считывания матриц из памяти и перемешивания элементов внутри xmm регистра. Далее, чтобы перемножать матрицу блоками по 2×2 элемента, приходится её особым образом считывать, сразу перемешивая элементы в нужном порядке, а потом ещё нужно правильно вывести. К сожаление, 4-5 секунд тратится именно на ввод и вывод.
Узким местом в программе по-прежнему является обращение к памяти. В среднем на 8 умножений нужно 1 обращение к памяти. Но можно уменьшить это число, перемножая одну строку матрицы A на две строки транспонированной матрицы B. Это позволяет на 32 умножения тратить 3 обращения к памяти вместо 4, то есть 0.75 вместо 1 на 8 умножений. Попытка уменьшить это число до 0.5 не увенчалась успехом, так как узким местом уже являются вычисления.
Будем ускорять ввод / вывод, потом ещё Штрассена напишу.
Итак, сейчас у меня обычный кубический алгоритм, который делит матрицу на блоки по размеру кэша (чтобы оба блока помещались в кэш, то есть по 1250 эл. каждый — это в самый раз), каждый из этих блоков, в свою очередь, разделяется на блоки 2×2, которые и перемножаются. Потом всё в нужном порядке складывается. Дополтинельная оптимизация — «одновременное» перемножение одной строки A[i] на две строки B[i] и B[i+1]. То есть Вместо четырёх обращений к памяти нужно три, а объем вычислений не меняется.
Комментарий от on 19.02.2010 - 21:22
Zealint, вы, вижу, пользуетесь компилятором Intel.
Не подскажете, где его можно взять?
Комментарий от on 19.02.2010 - 23:09
Первые из λ-алгоритмов (Bini et al.) можно попробовать, но, скорее всего, ничего не даст, сложения все съедят.
Комментарий от on 20.02.2010 - 07:54
venco, у меня есть знакомый программист, у него фирма купила лицензионную версию, я там и компилирую. Где взять — не знаю. Но мне кажется, что когда пишешь критические места на встроенном ассемблере, там не важно, какой компилятор, лишь бы он синтаксис встроенного ассемблера понимал.
Комментарий от on 21.02.2010 - 10:39
Итак, тов. venco вышел из 8 секунд!
Напоминаю, что 22 февраля в 12:00 конкурс завершается. То есть участники могут успеть выслать ещё по одной программе. По правилам, я тестирую только последнюю программу, посланную участником за сутки, значит последнее тестирование состоится завтра ровно в 12 часов, и если у меня в это время не будет лекции, то к 13 часам появится окончательный рейтинг, победитель должен будет на ту же почту отправить номер кошелька (яндекс.деньги или webmoney). Если будут какие-то задержки, то к вечеру точно справлюсь. Деньги обещаю выслать в течение суток.
Архив авторских решений и тестов будет готов чуть позже, где-то к 23-му числу. Я напишу отдельный пост.
Тем временем, я свою программу тоже улучшил. Сначала довёл кубическую версию до 14,5 с (оптимизация ввода/вывода), а после этого написал алгоритм Винограда — Штрассена (7 умножений + 15 сложений), что улучшило время на 2 секунды. Но реализация пока черновая, сложения написаны не слишком аккуратно, куча матриц сжирает почти гигабайт памяти, подозреваю, что секунд до 9 её довести можно. Работаем… Жалко, что многие участники потеряли активность, никогда не сдавайтесь!
Комментарий от on 22.02.2010 - 12:22
Ура, товарищи! Конкурс завершился. Всем огромное спасибо за участие и поддержку. Поздравляем победителя — venco.
Тов, venco, присылайте мне в ящик номер кошелька яндекс.денег или webmoney.
К вечеру будет готов пост в котором я выложу архив тестов и решений тех авторов, которые захотят поделиться исходниками. Поэтому прошу всех участников, у кого есть желание, прислать мне свои исходники до 19 часов.
Комментарий от on 22.02.2010 - 12:33
Участники конкурса могут прислать ссылки на свои странички или блоги, в следующем посте я сделаю на них прямые индексированные ссылки, при условии, что вы тоже делаете ссылку на ЭТУ страницу.
Комментарий от on 22.02.2010 - 18:18
> Наконец-то и мне удалось преодолеть 20-ти секундный барьер. До этого я использовал mm регистры (64 бита), теперь узнал, что на xmm регистрах операция pmaddwd выполняет 8 умножений и 4 сложения за один такт.
М-да, я тоже этого не знал, что и повлияло на мои оценки. Ну да ладно. Я вот чего Вас спросить хотел. Вы написали: «Хотите заработать 1000 р. за (максимум) час работы?». Положа руку на сердце, скажите, сколько примерно времени у Вас ушло на Ваши 8 версий?
Комментарий от on 22.02.2010 - 19:07
Лично я потратил на конкурс где-то 72 часа. Но учтите, что я на это и расчитывал (не сильно разбираюсь в SEE и как раз почти все время его и изучал). Конечно, я расчитывал, что в конкурсе примут участие те, кто хорошо знаком с предметной областью (с SIMD). Написание самого кода у меня заняло 3-4 часа, остальное время я думал. То есть человек, который программирование занимается профессионально, конечно, справился бы быстрее. Вы согласны?
Ну, для объективности мы можем спросить у других участников: товарищи, а сколько времени вы потратили на конкурс?
Комментарий от on 24.02.2010 - 14:52
> То есть человек, который программированием занимается профессионально, конечно, справился бы быстрее. Вы согласны?
Если он сам что-то похожее реализовывал (а не пользовался готовыми библиотеками), то да. Но я не уверен, что среди участников конкурса такие были.
Если человек только имел опыт работы с SIMD, то это тоже, конечно, ускорило бы работу. Но не на порядки.