Обновить
351
70

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

Отправить сообщение

Оптимизация ядра WebGPU для перемножения матриц и достижения производительности свыше 1ТФЛОПС

Время на прочтение12 мин
Охват и читатели1.5K

Пишем Surfgrad, высокопроизводительную библиотеку для автоматического дифференцирования выражений при помощи WebGPU.

Я работаю в компании Nomic, и многие из моих коллег заняты созданием больших TSNE-подобных визуализаций, работающих в браузере. При визуализации таких двумерных карт возникает две проблемы: проецировать эти конструкции (напр. TSNE и UMAP) в 2D-координатную систему протекает медленно и требует больших затрат оперативной памяти, особенно по мере того, как вы увеличиваете датасет и пытаетесь визуализировать в браузере миллионы точек данных, не расплавив при этом ноутбук невзначай.

Отобразить в браузере миллионы точек данных, не расплавив компьютер — та ещё задача. Мне доводилось слышать, что многие проблемы с масштабированием удаётся решать при помощи инструмента Deepscatter, разработанного Беном Шмидтом.

Но многие из таких разговоров, которые мне известны, вертятся вокруг Typescript и великолепия WebGPU как такового. Готовя эту статью, я не смог найти ни одной библиотеки для автоматического дифференцирования выражений, которая была бы написана с применением WebGPU. Но было бы упущением не назвать здесь два репозитория с функционально схожим наполнением: webGPT (библиотека на основе трансформеров, приспособлена только для логического вывода) и webgpu-blas (ядра для быстрого перемножения матриц под webGPU). Поэтому, в качестве самообразования и желая получше изучить WebGPU и Typescript, я решил написать Surfgrad, высокопроизводительную библиотеку для автоматического дифференцирования выражений под управлением WebGPU. Она обеспечивает тензорные операции в браузере. Как понятно по названию и по принципу работы, она во многом сделана по примеру tinygrad и micrograd.

Читать далее

Работа с куки-файлами хуже сапёрного дела

Время на прочтение15 мин
Охват и читатели3.3K

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

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

Читать далее

Почему ИИ рано поручать код-ревью

Время на прочтение8 мин
Охват и читатели1.8K

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

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

Читать далее

Запросто собираем базу данных при помощи команд Linux

Время на прочтение6 мин
Охват и читатели9K

База данных — это сердце многих приложений, от полнофункциональных корпоративных сайтов до сравнительно простых инструментов, например, для ведения списков покупок и финансовых трекеров. Популярны реляционные базы данных на основе SQL, но в Linux можно собрать более простую и прозрачную альтернативную базу данных.

Читать далее

Невероятно быстрый подсчёт байтов

Время на прочтение5 мин
Охват и читатели2.3K

Оказалось, что тема суммирования целых чисел в кодировке ASCII в Haswell со скоростью memcpy гораздо популярнее, чем я мог ожидать. Именно поэтому я решил поучаствовать и в другом челлендже в жанре HighLoad: подсчёт uint8. В настоящее время я занимаю всего лишь 13 место в списке лидеров, проигрываю первому месту около 7%, но уже узнал немало интересного. В этом посте я полностью опишу моё решение, в том числе, удивительный паттерн считывания из памяти. Используя его, можно примерно до 30% (по сравнению с обычным последовательным доступом) повысить скорость передачи в контексте одноядерных рабочих нагрузок, ограниченных размером кэша. По-видимому, этот метод малоизвестен.

Как и в других постах автора, программа настроена для следующих входных характеристик высоконагруженной системы: Intel Xeon E3-1271 v3 @ 3,60 ГГц, ОЗУ 512 МБ, Ubuntu 20.04. В ней используется только AVX2, а AVX512 не используется.

Читать далее

Уделите внимание токенизаторам — и вот почему

Время на прочтение12 мин
Охват и читатели4.5K

На прошлой неделе я помогал одному другу пустить одно его новое приложение в свободное плавание. Пока не могу особенно об этом распространяться, но упомяну, что это приложение, конечно же, сдобрено искусственным интеллектом — сегодня этим не удивишь. Может быть, даже изрядно сдобрено, в зависимости от того, к чему вы привыкли.

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

Меня довольно заинтриговало, что большинство успешных ИИ-приложений – это, в сущности, инструменты для умного семантического поиска. Поиск Google (в своём роде) раскрепостился, и это наталкивает меня на мысли, вдруг они только сейчас дали волю своим мощностям LLM, которые уже давно стояли за поисковым движком. Но я отвлёкся.

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

За последние пару лет я успел заметить одну выраженную черту разработчиков, привыкших действовать в области традиционного (детерминированного) программирования: им очень сложно перестроиться на осмысление задач в статистическом контексте, а именно так и следует подходить к программированию приложений с большими языковыми моделями, суть которых — это статистика. Статистика «хаотичнее» традиционной информатики и подчиняется иным правилам, нежели алгоритмы обычной computer science. К чему я клоню: статистика — это по-прежнему математика, но очень своеобразная математика.  

Читать далее

Пошаговое повышение производительности алгоритма

Время на прочтение11 мин
Охват и читатели1.4K

Недавно мне довелось работать над новым алгоритмом приближённого поиска ближайших соседей, который называется RaBitQ. Автор этого алгоритма уже предоставил достаточно скоростную реализацию на C++. Я попытался переписать этот алгоритм на Rust (ещё один случай «а почему бы не переписать на Rust»). Однако, я обнаружил, что моя реализация гораздо медленнее оригинальной. Далее я расскажу, как шаг за шагом доработал её производительность.

Читать далее

Быстрый поиск опечаток на Rust

Время на прочтение6 мин
Охват и читатели1K

Мы запустили наш поисковик по Hacker News и RAG-движок с полусырой системой исправления опечаток. В нашей первой версии тратилось более 30 мс на обработку орфографически правильных запросов. Это достаточно много, поэтому по умолчанию мы отключили данную фичу. Наша новейшая версия работает в 100 раз быстрее, справляется за 300 мкс с корректно записанными запросами и тратит ~5 мс/слово на исправление ошибок. В этом посте мы объясним, как нам удалось этого добиться!

Читать далее

Некоторые малоизвестные фичи, фокусы и причуды языка C

Время на прочтение19 мин
Охват и читатели22K

В этом посте разобраны некоторые фокусы, причуды и фичи языка C (некоторые из них – весьма фундаментальные!), которые, казалось бы, могут сбить с толку даже опытного разработчика. Поэтому я потрудился сделать за вас грязную работу и (в произвольном порядке) собрал некоторые из них в этом посте. Примеры сопровождаются ещё более вольными краткими пояснениями и/или листингами (некоторые из них цитируются).

Конечно же, здесь я не берусь перечислять абсолютно всё, так как факты из разряда «функция nan() не может устанавливать errno, поскольку в определённых ситуациях поведёт себя как strtod()» не слишком интересны.

ВНИМАНИЕ: сам факт попадания тех или иных вещей в эту подборку  не означает автоматически, что я рекомендую или, наоборот, не рекомендую ими пользоваться! Некоторые из приведённых примеров никогда не должны просачиваться за пределы списков наподобие этого, тогда как другие примеры невероятно полезны! Уверен, что могу положиться на ваш здравый смысл, дорогие читатели.

Читать далее

C++ с точки зрения Rust-разработчика: достоинства и недостатки

Время на прочтение8 мин
Охват и читатели10K

Я профессионально программирую на Rust и, признаться, немного этот язык продвигаю. Поэтому можете себе представить глубину моего расстройства, когда моя младшая сестрёнка, почти не умеющая программировать, обратилась ко мне и попросила научить её C++. Я попытался её отговорить, сказав, что однажды она будет сидеть за отладкой ошибок сегментирования, вооружившись Valgrind и вспоминать этот наш разговор, размышляя, а где же она свернула не туда. Но она оказалась ещё упрямее меня и настаивала: хочу выучить язык программирования, которым действительно пользуются люди.

Я не притрагивался к C++ с тех пор, как ещё в старших классах разрабатывал игры на Cocos2D-X, но решил, что сохранившихся у меня туманных воспоминаний о «правиле трёх» (или сколько там было? Пять? Ноль?) и прочих подобных материях будет более чем достаточно, чтобы решить такую задачу. Оказалось, что и мне требуется кое-что подучить, но я с удовольствием узнал, что существует большая аудитория, с которой можно поделиться этими знаниями. Почти любую концепцию из C++ легко понять, если объяснить её в ключе «о, эта как та штука из Rust».

Притом, что C++ местами несимпатичен, этот язык по-своему красив. Я и так это знал, но, когда взялся заново учиться C++, мне стало только яснее: если Rust в какой-то степени и превосходит C++ (допустим, вы верите, что это так), то лишь потому, что сам Rust стоял на плечах такого гиганта как C++.

Так что мы потратили пару недель, проштудировав серию руководств по OpenGL от ютубера под ником TheCherno (кстати, сама серия отличная). Две недели спустя нам удалось на экране единственный статичный голубой квадратик. Я уже стал опасаться, а не начнёт ли моя сестра сомневаться, стоило ли таким образом изучать разработку игр и пытаться изобразить что-нибудь на C++. Так что тогда я решил, что следует отбросить руководства господина Черно и взяться за разработку игры всерьёз.

Читать далее

Реверс-инжиниринг  GDB для работы с Pwndbg

Время на прочтение6 мин
Охват и читатели1.4K

Функционал GDB существенно сужается, когда приходится иметь дело с файлами, из которых убраны отладочные символы (получаются так называемые «урезанные бинарники»). Функции и имена переменных превращаются в бессмысленные адреса. Для установки контрольных точек приходится отслеживать адреса нужных нам функций из внешнего источника. Также нужно выводить в консоль структурированные значения и после этого корпеть над дампом памяти, пытаясь вычленить, где именно пролегают границы полей.

Вот почему этим летом, работая в Trail of Bits, я расширил Pwndbg — плагин для GDB. Поддерживает его мой наставник Доминик Чарнота. Я добавил в инструмент две фичи, благодаря которым практическая отладка урезанных бинарников сближается с аналогичной работой, знакомой нам из работы с отладчиком в IDE. Теперь в Pwndbg интегрирован инструмент Binary Ninja, позволяющий лучше выяснять специфику GDB+Pwndbg, а также выводить дамп структур Go, чтобы отлаживать бинарники Go стало удобнее.

Читать далее

Загруженность GPU — не самая репрезентативная метрика

Время на прочтение7 мин
Охват и читатели3.3K

В командах ML-инженеров часто пользуются метрикой «GPU Utilization» (Загруженность процессора), чтобы понять, насколько активно задействуется в работе процессор. Чтобы узнать эту информацию, обычно достаточно выполнить команду nvidia-smi в строке терминала. Во многих интегрированных наблюдательных инструментах загруженность процессора также отслеживается как основная характеристика производительности. Но иногда, как ни удивительно, эта метрика даёт не слишком точное представление о производительности GPU. На самом деле, GPU можно загрузить на 100%, выполняя лишь операции чтения и записи (в памяти), но при этом 0 вычислений. Эта статья – не о том, как мы это выяснили, а о том, что нам удалось узнать по ходу дела.

Читать далее

CORS — это тупо

Время на прочтение7 мин
Охват и читатели18K

Технология CORS и действующее в браузерах правило ограничения домена – те вещи, которые часто понимаются превратно. Ниже я объясню, что они собой представляют, и почему пора перестать волноваться по их поводу.

Замечание: я собираюсь рассказать о CORS и правиле ограничения домена как о единой сущности, поэтому далее часто буду употреблять эти термины как синонимы. Дело в том, что они, по сути – части одной системы, работают в сочетании друг с другом и помогают вам решать, что можно сделать с какими ресурсами смешанного происхождения. В принципе, если ваши запросы поступают из разных источников, то вам придётся иметь дело с правилами, политиками и механизмами CORS.

Прежде всего, отмечу, что CORS — это огромный костыль, помогающий снизить влияние ошибок, передающихся с унаследованным кодом. В этой системе защита предоставляется как по принципу отказа от участия (opt-out) в попытке частично купировать XSRF-атаки против незащищённых или немодифицированных сайтов, так и по принципу активного участия (opt-in), чтобы на сайте включалась активная самозащита. Но ни одной из этих мер не достаточно, чтобы решить целенаправленно созданную проблему. Если на вашем сайте используются куки, то вы обязаны деятельно позаботиться о его безопасности. (Ладно, это касается не любого сайта, но лучше перестрахуйтесь. Выделите время на тщательный аудит вашего сайта или выполните описанные ниже простые шаги. Даже придерживаясь самых разумных паттернов, вы всё равно можете подставиться под XSRF-уязвимости).

Читать далее

Как работает протокол HLS

Время на прочтение10 мин
Охват и читатели12K

Вот уже несколько недель я разрабатываю серверную поддержку коротких видео для компании Bluesky.

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

Чтобы укладываться в эти ограничения, мы попытались использовать сеть доставки видео-контента (CDN), которая могла бы нести основное бремя поддержки той полосы передачи данных, которая обеспечивала бы показ потокового видео по требованию.

Притом, что такая CDN – это полнофункциональный продукт, мы не хотели чрезмерно замыкаться на конкретном производителе и поэтому решили внести в нашу потоковую платформу некоторые улучшения, тем самым расширив спектр предлагаемых на ней услуг и творчески подойти к реализации протоколов потокового видео.

Читать далее

Почему новый процесс в Node порождается так медленно?

Время на прочтение10 мин
Охват и читатели1.4K

Мы в Val Town выполняем ваш код в процессах Deno. Недавно мы заметили, что под нагрузкой отдельно взятый Node-сервер Val Town не может породить более 40 процессов. На протяжении 30% процессорного времени главный поток остаётся заблокирован вызовами к spawn. Почему так медленно? Можно ли как-нибудь ускорить эту работу?

Читать далее

2-опережающий предсказатель ветвлений в процессоре Zen 5: тридцатилетняя идея, которая до сих пор развивается

Время на прочтение9 мин
Охват и читатели1.3K

Не так давно одному из авторов этого поста довелось интервьюировать Майка Кларка, который, в частности, сказал: “…вот увидите, какой принципиальный прогресс готовит нам будущее в виде процессора Zen 6, хотя, на самом деле, все условия для этого были заложены ещё на этапе Zen 5». На той же конференции по архитектуре, посвящённой Zen 5 выступил и Марк Пейпермастер, генеральный технологический директор AMD, высказавшийся так: «Zen 5 — это основательная переработка всей архитектуры Zen». Всё дело в многочисленных и принципиальных изменениях в устройстве ядра, которые обогатили процессор именно в этой версии.

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

Читать далее

У меня нет конструктора, но я должен инициализироваться

Время на прочтение13 мин
Охват и читатели8.7K

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

Главная ошибка была в том, что ты в это вообще ввязался — в этом никаких сомнений.

Ещё когда я впервые взялся проходить курс по C++ несколько лет назад, меня учили, что, если я не предоставлю собственного конструктора, то компилятор сам подберёт ему замену — своего рода конструкторы, действующие по умолчанию. Я решил подробнее в этом разобраться, особенно меня волновали случаи, которые выглядят примерно так:

Читать далее

UB или не UB – вот в чём вопрос: как gcc и clang обрабатывают статически известное неопределённое поведение

Время на прочтение7 мин
Охват и читатели2.9K

Недавно у нас в команде зашла дискуссия о неопределённом поведении (UB) в C. Напомню для тех, кто не знает: если мы пишем такой код, эффект от выполнения которого (и события в процессе его выполнения) строго не определён в спецификации языка, то возникает неопределённое поведение. Таким образом, встретив такой код, компилятор может действовать по собственному усмотрению, и нет никаких гарантий, что выполнение этого кода пойдёт по предсказуемому пути. Следовательно, нужно избегать неопределённого поведения любой ценой, поскольку мало того, что оно может приводить к глюкам программы, но и часто становится источником уязвимостей и угрозой безопасности. Примеры кода, в котором проявляется неопределённое поведение: выход за границы массива при его индексировании, целочисленное переполнение, деление на ноль, разыменование указателя на null [1].

Компиляторы нередко пользуются неопределённой семантикой языка, чтобы делать те или иные допущения о программе. Например, если написать что-то вроде int x = y/z, компилятор может предположить, что z не может быть равно нулю, так как деление на ноль приводит к неопределённому поведению, а программист явно не собирался писать такой код. На основе этой информации он может попытаться далее оптимизировать программу так:

Читать далее

Жизнь – боль: как одновременно поддерживать в Rust синхронный и асинхронный код

Время на прочтение13 мин
Охват и читатели3.7K

Присаживайтесь поудобнее и послушайте стариковскую байку: что случилось, когда я попросил у Rust слишком многого.

Допустим, вы хотите написать на Rust новую библиотеку. Всё, что для этого требуется — обернуть её в публичный API, через который будет предоставляться доступ к какому-то другому продукту, например, в Spotify API или, может быть, в API базы данных, скажем, ArangoDB. Не так это и тяжело: в конце концов, вы не изобретаете ничего нового, вам не приходится иметь дело со сложными алгоритмами. Поэтому вы полагаете, что задача решается относительно прямолинейно.  

Вы решаете реализовать библиотеку с применением async. Работа, которая будет выполняться с помощью вашей библиотеки, заключается в основном в выполнении HTTP-запросов, обслуживающих ввод/вывод, поэтому применять здесь async действительно целесообразно (кстати, это одна из тех фишек, благодаря которым сегодня так востребован Rust). Вы садитесь писать код — и вот, через несколько дней у вас готова версия v0.1.0. «Приятно», — думаете вы, как только cargo publish заканчивается успешно и загружает вашу работу на crates.io.

Проходит несколько дней, и вам прилетает новое уведомление с GitHub. Оказывается, кто-то открыл тему:

Читать далее

Что такое PID 0

Время на прочтение17 мин
Охват и читатели27K

Как говорится, «не будите во мне ботана». Иногда кто-нибудь беспечно задаст мне, казалось бы, невинный вопрос — и я убиваю следующие несколько часов (в описываемом случае — дней), чтобы полноценно сформулировать ответ. Обычно всё это заканчивается с моей стороны очередной филиппикой на mastodon или в каком-нибудь приватном чате. Но на сей раз не буду этим ограничиваться и напишу целый пост.

Вот с какого невинного вопроса всё началось:

А почему UID начинаются с 0, но PID начинаются с 1?

Если совсем коротко: в Unix PID (идентификаторы процессов) начинаются именно с 0! PID 0 просто не отображаются в пользовательском пространстве через традиционные API.  PID 0 запускает ядро, а затем практически уходит на покой, только немного участвует в работе планировщика процессов и в управлении питанием. Кроме того, на просторах Интернета доминирует заблуждение о PID 0, всё из-за одного ошибочного утверждения в Википедии, которому уже 16 лет.

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

Но, конечно же, любой желающий может просто загуглить, что такое PID 0, верно? Зачем мне вообще всё это писать?

Читать далее

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность