Pull to refresh
194
0.1
Андрей Дмитриев @AndreyDmitriev

Пользователь

Send message

Считать или нет "жизнь в деревне" минусом - в общем сильно зависит от индивиуума, мы вот живём в немецкой деревне, а ездим отдыхать в шведские или норвежские но опять же деревни. Вот чтоб на берегу озера, отдельный дом, сауна, камин и всё такое. Это на любителя, но в большом городе жить не хочется (это притом, что я почти тридцать лет в Питере прожил), а если точнее, то идеально, когда большой город неподалёку (Гамбург в нашем случае), но не в нём.

Мы в прошлом году два раза в Швеции были, ездили на машине из Германии через Данию. Осенью паспорта проверяли на съезде с Эресуннского моста, там будки стоят, причём попросили документы всех сидящих в машине. А вот под Рождество никто не проверял, пограничники, видимо ушли отмечать.

По моему мнению (но я интроверт), у каждого программиста должен быть отдельный кабинет, с закрывающейся дверью, окном и стенами для липких листочков. "Оупен спейсы" — зло страшное, когда нашу компанию купили американцы, они первым делом снесли несколько стен и засадили всех в один зал. Меня вот ровно на три месяца хватило, самых бесполезных месяцев моей жизни. Потом я снова перебрался в кабинет. В домашнем офисе — тоже самое, должна быть хоть маленькая, но отдельная комнатушка. Это притом, что я работаю в промышленном программировании, и иногда приходится работать на заводе, в шумозащитных наушниках, но это другое.

В прошлом году как раз наблюдал моих детей — гимназистов, с рулеткой, изображающих из себя Галилея — один ронял конфету, второй снимал... Я спросил — оказалось, что им задали измерить g в домашних условиях. Я (как закончивший физтех со степенью магистра) заметил им, что это в общем похвально, но сильно точно с метровой высоты не получится, да и конфету лучше заменить на стальной шарик... В голове у меня сразу родилось два плана — либо взять цифрозеркалку на штативе с хорошим объективом, выставить там 60 FPS, затем раздербанить видео на картинки через ffmpeg, там и посмотреть, на каком кадре начинается и заканчивается падение, либо я могу притащить с работы пару ультразвуковых датчиков, прилепить их на стену, подкинуть их на входы ардуинки, или ещё лучше, сRio, там FPGA на 40 MHz, я просто посчитаю такты между фронтами... Я предложил им помочь — Не, пап, спасибо, мы сами... Нам тут в гимназии приложуху выдали... Дальше я с изумлением наблюдал, как прямо на смартофоне отрок загрузил видео, там оно покадрово, затем, вот прямо на экране тыркнул в падающую конфетку, потом ещё раз, и через пару минут выдал — вот, примерно 9,6, да ещё и с графиками зависимости координат и скорости от времени, этой точности нам достаточно, нам важен принцип. Я был впечатлён. Эх, мне бы такие возможности, когда я грыз гранит науки тридцать лет назад.

простите но на С++ есть нюансы,

Ну при чём тут плюсплюсы-то? Я Вас уверяю, интринсики будут одинаковы что там что на Си. Вот, смотрите, код из пятой главы - это ровно тоже что и у Вас, только с FMA до кучи. Тут как раз нет вообще никаких нюансов.

на Расте будет либо так же по скорости либо быстрее ... так же есть разница в платформах,...

Вы мешаете вообще всё в одну кучу.

как начать через перемножения матриц пользоваться ускоряющимися регистрами

Вы термин "ускоряющихся регистров" сами придумали? Вот я бы порекомендовал раздобыть книжку Даниэля Куссвюрма "Профессиональное программирование на ассемблере x64 с расширениями AVX, AVX2 и AVX-512" и прочесть, хотя бы ради терминологии. Второе издание переведено на руский, третье пока нет, вроде. Лучше возьмите обе, на английском тоже "Kusswurm Daniel — Modern X86 Assembly Language Programming" (там в русском таки есть косяки перевода). Хотя эти книжки и не идеальны, но в них есть ровно всё то, что Вы выше изложили, причём весь код из книги издательством выложен на Гитхабе, включая использование FMA и произвольные размеры матриц. Если на интрисиках, то "Modern Parallel Programming with C++ and Assembly Language" того же автора, а код к ней вот здесь.

Вам имело смысл соревноваться не с Си кодом, а с библиотеками, вот в Intel MKL вроде это есть, ну и там gemm() из LAPACK, по-моему и то и другое под никсами живёт (хотя я тут не спец). Вам имело смысл попробовать реализовать это дело для матриц произвольного размера, как одинарной так и двойной точности и если бы Вы обогнали по скорости существующие библиотеки, то получилась бы хорошая статья. Кроме того, у Вас своеобразный стиль изложения (Вы дайте кому-нибубдь прочитать перед публикацией), ну и по коду можно придраться, ну вот зачем столько файлов включать для интрисиков, там же один immintrin.h всего нужен, смысл верчения циклов "с ускорением" от меня тоже ускользает, и т.д.

Вы точно этот код запускали и он точно вам один и тот же ответ выдает с наивным методом?

Я не поленился проверить, да, он выдаёт тот же результат, что и референсный dgemm(). Правда я перебросил его на double:

Скрытый текст
MATMULDLL_API void mulm4VVVd(double* result, double* a, double* b)
{
    __m256d row0 = _mm256_loadu_pd(&b[0]);
    __m256d row1 = _mm256_loadu_pd(&b[4]);
    __m256d row2 = _mm256_loadu_pd(&b[8]);
    __m256d row3 = _mm256_loadu_pd(&b[12]);

    __m256d newRow0 = _mm256_mul_pd(row0, _mm256_set1_pd(a[0]));
    newRow0 = _mm256_add_pd(newRow0, _mm256_mul_pd(row1, _mm256_set1_pd(a[1])));
    newRow0 = _mm256_add_pd(newRow0, _mm256_mul_pd(row2, _mm256_set1_pd(a[2])));
    newRow0 = _mm256_add_pd(newRow0, _mm256_mul_pd(row3, _mm256_set1_pd(a[3])));

    __m256d newRow1 = _mm256_mul_pd(row0, _mm256_set1_pd(a[4]));
    newRow1 = _mm256_add_pd(newRow1, _mm256_mul_pd(row1, _mm256_set1_pd(a[5])));
    newRow1 = _mm256_add_pd(newRow1, _mm256_mul_pd(row2, _mm256_set1_pd(a[6])));
    newRow1 = _mm256_add_pd(newRow1, _mm256_mul_pd(row3, _mm256_set1_pd(a[7])));

    __m256d newRow2 = _mm256_mul_pd(row0, _mm256_set1_pd(a[8]));
    newRow2 = _mm256_add_pd(newRow2, _mm256_mul_pd(row1, _mm256_set1_pd(a[9])));
    newRow2 = _mm256_add_pd(newRow2, _mm256_mul_pd(row2, _mm256_set1_pd(a[10])));
    newRow2 = _mm256_add_pd(newRow2, _mm256_mul_pd(row3, _mm256_set1_pd(a[11])));

    __m256d newRow3 = _mm256_mul_pd(row0, _mm256_set1_pd(a[12]));
    newRow3 = _mm256_add_pd(newRow3, _mm256_mul_pd(row1, _mm256_set1_pd(a[13])));
    newRow3 = _mm256_add_pd(newRow3, _mm256_mul_pd(row2, _mm256_set1_pd(a[14])));
    newRow3 = _mm256_add_pd(newRow3, _mm256_mul_pd(row3, _mm256_set1_pd(a[15])));

    _mm256_storeu_pd(&result[0], newRow0);
    _mm256_storeu_pd(&result[4], newRow1);
    _mm256_storeu_pd(&result[8], newRow2);
    _mm256_storeu_pd(&result[12], newRow3);
}

И он, кстати, в данном частном случае 4х4 обгоняет по производительности реализацию LabVIEW. Ну, может и пригодится когда-нибудь. Хотя сейчас такой код практически сразу ИИ сходу набрасывает.

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

В прошлом году видел репортаж, как раз про это. Короче, дело происходит в Германии, в маленьком городке Gräfenhainichen есть такой молодой человек, которого зовут Никлас Маттей, ему 18 лет, весьма целеустремлённый юноша:

В свободное время он садится на свой велик, обвешанный камерами и табличками POLIZFI (за POLIZEI ему самому прилетит по шапке) и одевшись в рабочую одежду, похожую на полицейскую униформу, старательно фоткает любые нарушения, после чего пишет заявления (по немецки Anzeige). Сам себя он называет Anzeigenhauptmeister (главный мастер по заявлениям). Накропал он их уже больше четырёх тысяч, и вот это я понимаю — размах. Иногда он устраивает рейды и в соседние городки, в Гамбурге он тоже был замечен. При этом даже если сами полицейские остановятся где не надо, он и им выпишет, я видел видео. Мэр этого городка плачет горючими слезами, мол достал он всех в органах правопорядка этими заявлениями неимоверно, из девятисот заявлений только двенадцать получили ход, принеся в казну аж 357 евро штрафов (пруф).

Я, кстати, сам в такой роли однажды был — меня соседка достала своей машиной на тротуаре, которую мне с собакеным каждый раз обходить, ну я не поленился сходить в полицию и показал фотку. Там мне вежливо объяснили, что это и не тротуар вовсе, а проезжая часть, она имеет право там стоять, и единственное, за что ей может прилететь — так это за то, что она против движения паркуется, но поскольку это маленький тихий деревенский район, то они на это закрывают глаза, короче пусть паркуется как хочет и вы тоже паркуйтесь, штрафов вы там не получите. Он ещё заметил, что городок у нас маленький, а память у него хорошая, и он меня знает и видел пару раз, как я мотороллер парковал на тротуаре, когда за хлебушком с утра ездил, я ж не получил штрафа, хотя и мог бы, но они это негласно позволяют, покуда я никому не мешаю. В общем, порядок, конечно, должен быть, но всё хорошо в меру, без фанатизма и ненужного перфекционизма.

Вообще говоря это далеко не самый быстрый способ, есть и другие подходы, без хэширования. Мне как-то давно потребовалось генерить видеопоток, заполненный случайным шумом, но так чтобы укладываться в тайминг фреймов (160 МБ в секунду, кажется или около того), я в интернетах быстро нашёл подходящий несложный алгоритм. В данном случае я б Вихрь Мерсенна попробовал прирастить, там надо посмотреть какой период повторения псевдослучайной последовательности, но должно быть ещё быстрее чем данный метод, там просто банально меньше мат операций нужно для получения каждого следующего символа. Просто идея.

Нет, не манипуляции, просто я хотел ограничиться тривиальным случаем, когда запускается четыре потока, с явным назначением аффинити, и некоторые "заходят не туда", просто для иллюстрации.

Если же я буду запускать потоки без явного указания процессора (как обычно и делают), то будет так (скорость в МБ/с): 4 потока - 436; 5 потоков - 457; 6 потоков - 490; 7 потоков - 503. Также видно, как он чуть чуть частоту роняет под нагрузкой.

Восемь потоков я не тестировал, потому что уже семь дают мне 99% процентов загрузки и при запуске восьмого цикл, отображающий индикатор встаёт колом. Но не думаю, что там будет большая разница с семью. По хорошему конечно код надо показывать, там секретов нет, просто это на LabVIEW.

Скриншоты
4
4
5
5
6
6
7
7

Это в общем не входило в задачу, интерес был чисто "академический". Тестировать же лучше "полноценную" версию, которая chat.deepseek.com. Чуть выше в комментах я сравнил выдачу на довольно специфическом вопросе по сравнению с DeepSeek-R1-Distill-Qwen-7B-Q4_K_M, но там в общем результат ожидаем. Вы что-то специфическое хотели спросить? Я могу передать ей вопрос.

Разница есть, в пользу AVX512, но она невелика. Я только что прогнал вот эти две сборки

avx2 выдала 0.9 токенов в секунду, а avx512 — 1.1. Цифры я списал с веб интерфейса:

О, спасибо, хорошее замечание. Я, кстати, попробовал DeepSeek-R1-Distill-Qwen-7B-Q4_K_M.gguf запустить там и тут, так вот на компе из обзора она даёт 10 токенов, а на том, что в комменте выше - семь (даже если Quad не включён), и если включить, то, возможно даже они сравняются. Так что скорость в общем не совсем пропорциональна пропускной способности памяти, скорость процессора тоже важна. Результат интересный, ядро W-2245 где-то раза в полтора быстрее старого 6132, но тут их всего 8, а там 28. Я б ожидал токенов этак 4-5, но нет, оно быстрее.

Вот сухой бенчмарк, тачка слева даёт десять токенов, а справа - семь:

А, кстати, это легко продемонстрировать за утренним кофе.

Смотрите, я буду вычислять SHA256 в четыре потока, запуская это дело на четырёхядерном i7, и если я отдам распределение потоков на откуп операционке (точнее, LabVIEW и операционке), то загрузка восьми логических ядер будет выглядеть вот так (извините за немецкий скриншот):

"Рыхленько" так. А теперь следите за руками - я могу посадить мои потоки на первые четыре ядра:

И получу 280 MB/s, но тут фактически работают два физических ядра.

А теперь я раскидаю потоки вот так:

И получу уже 470 MB/s, потому что теперь я занял четыре физических ядра.

Во всех трёх случаях средняя загрузка процессора - чуть больше половины, а вот производительность приложения сильно разная.

Выключая гипертрединг, я не даю возможности приложению сесть на ядра неоптимальным образом, но в последнем случае видно, что сама операционка (и остальные процессы) перебралась на незанятые "гипертредированые" ядра, и если их не будет, то она будет использовать те, где крутятся мои потоки, так что с выключенным HT производительность в теории может просесть, хотя и не намного. Рецептов по оптимальному использованию гипертрединга тут в общем нет, надо просто пробовать и так и сяк.

Нет. нет, там судя по всему просто выделение памяти так реализовано. После того как всё загрузилось, память забита на 90% и обращений к диску не производится, это я проверил. А при изначальной загрузке модели она SSD грузит на 100%, да, это видно. Там в принципе исходники есть, можно посмотреть, как она модель грузит (хотя я пока туда не лазил).

Да, правильно. Я просто проверил, что без него загрузка стала 100%. Если бы она и при выключенном гипертрединге осталась в районе 50, то надо было бы внимательно смотреть откуда там ноги растут и почему идёт недогруз. Теперь его по идее надо включить обратно и провести тщательные замеры (так то я проверил производительность "на глаз".). И да, вполне возможно, что с его включением станет чуть лучше (я, кажется и видел 1.2 токена с ним и 1.1 без него, но "кажется" - не считается). А может ведь и так получиться, что программа допустим видит 28 физических ядер, но при создании потоков они все "сядут" на один 14-ядерный процессор (операционка, скорее всего такую глупость не сделает, а вот программа по ошибке вполне может), у которого 28 логических потоков, он будет из кожи вон лезть на своём гипертрединге, а второй будет просто простаивать, я и в этом случае увижу 50% (мой индикатор показывает среднее по всем логическим ядрам) но в этом случае выключение гипертрединга даст и стопроцентную загрузку и безусловный и заметный прирост. Там был, кажется ключ управления потоками в опциях, я завтра гляну, если время будет. Полная, "на всю катушку" загрузка на 56 потоков - тоже бывает по итогу медленнее, чем 28 потоков по чистым ядрам, я читал на реддите, что многие игры работают заметно быстрее именно при выключенном HT.

Их есть у меня, причём в запечатанном, нетронутом виде:

1
23 ...

Information

Rating
3,738-th
Location
Ahrensburg, Schleswig-Holstein, Германия
Date of birth
Registered
Activity