Как стать автором
Обновить
0
0

Инженер-программист

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

Дорогая, я уменьшил {fmt}: уменьшил размер до 14kB и избавился от рантайма C++

Уровень сложностиСредний
Время на прочтение11 мин
Количество просмотров13K

Библиотека форматирования {fmt} известна своим небольшим влиянием на размер бинарников. Чаще всего её код в несколько раз меньше по сравнению с такими библиотеками, как IOStreams, Boost Format или, что иронично, tinyformat.

Давайте разберем, как можно уменьшить размер бинарников еще больше!

Читать далее
Всего голосов 40: ↑38 и ↓2+47
Комментарии26

Два потока, одно ядро: как устроена одновременная многопоточность

Уровень сложностиСредний
Время на прочтение13 мин
Количество просмотров25K

Одновременная многопоточность (Simultaneous multithreading, SMT) — это функция, позволяющая процессору одновременно обрабатывать команды из двух разных потоков. Но задавались ли вы когда-нибудь вопросом, как это работает? Как процессор отслеживает два потока и распределяет ресурсы между ними?

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

Примечание: основная часть изложенного в статье относится к реализации SMT компании Intel, также называемой гипертредингом (hyper-threading). Она основана на научной статье компании, опубликованной в 2002 году.
Читать дальше →
Всего голосов 50: ↑48 и ↓2+71
Комментарии48

Создание анимированных графиков с помощью Matlab

Уровень сложностиПростой
Время на прочтение6 мин
Количество просмотров6.1K

Анимированные графики помогают представить информацию более красиво и наглядно. Matlab позволяет их создавать с помощью всего пары функций. Как это сделать, читайте в данной статье.

Читать далее
Всего голосов 25: ↑25 и ↓0+25
Комментарии9

std::move vs. std::forward

Время на прочтение8 мин
Количество просмотров45K

Несмотря на то, что материалов на тему move-семантики и идеальной передачи в Интернете предостаточно, вопросов типа «что я должен здесь использовать: move или forward?» не становится меньше или мне просто «везет» на них. Поэтому и решено было написать эту статью. Предполагается, что читатель хотя бы немного знаком с rvalue-ссылками, move-семантикой и идеальной передачей.

Читать далее
Всего голосов 11: ↑10 и ↓1+16
Комментарии36

Декомпозиция классов: подход к разнообразию игровых систем на примере D&D и гонок

Время на прочтение10 мин
Количество просмотров8.4K

Богатая мета и разнообразие игровых классов — постоянная отличительная фишка RPG и еще ряда жанров, обеспечивающая поддержание интереса игрока и высокую реиграбельность. Но чтобы игрались все классы действительно хорошо, нужно уметь их правильно балансировать и комбинировать связки навыков, отличающие их друг от друга.

В своей работе я часто опираюсь на ресурсный подход к дизайну систем, описанный Эрнестом Адамсом (Ernest Adams) и Джорис Дорманс (Joris Dormans) в книге Game Mechanics: Advanced Game Design. Это дизайн в абстракциях, который представляет игру как экономическую систему. Подробнее с ним вы можете ознакомиться в книге или на Machinations.io

А под катом я расскажу про основы такого подхода и приведу практические примеры, как его применять в дизайне классов для игр любого жанра — на основе Dungeons & Dragons 3.5 и гонок, которые мне когда-то доводилось разрабатывать. 

Читать далее
Всего голосов 18: ↑18 и ↓0+18
Комментарии5

Сетевое программирование для разработчиков игр. Часть 2: прием и передача пакетов данных

Время на прочтение9 мин
Количество просмотров106K
От переводчика: Это перевод второй статьи из цикла «Networking for game programmers». Мне очень нравится весь цикл статей, плюс всегда хотелось попробовать себя в качестве переводчика. Возможно, опытным разработчикам статья покажется слишком очевидной, но, как мне кажется, польза от нее в любом случае будет.
Первая статья — http://habrahabr.ru/post/209144/



Прием и передача пакетов данных


Введение

Привет, меня зовут Гленн Фидлер и я приветствую вас в своей второй статье из цикла “Сетевое программирование для разработчиков игр”.


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

А сейчас я собираюсь рассказать вам, как на практике использовать UDP для отправки и приема пакетов.

BSD сокеты

В большинстве современных ОС имеется какая-нибудь реализация сокетов, основанная на BSD сокетах (сокетах Беркли).

Сокеты BSD оперируют простыми функциями, такими, как “socket”, “bind”, “sendto” и “recvfrom”. Конечно, вы можете обращаться к этим функциями напрямую, но в таком случае ваш код будет зависим от платформы, так как их реализации в разных ОС могут немного отличаться.

Поэтому, хоть я далее и приведу первый простой пример взаимодействия с BSD сокетами, в дальнейшем мы не будем использовать их напрямую. Вместо этого, после освоения базового функционала, мы напишем несколько классов, которые абстрагируют всю работу с сокетами, чтобы в дальнейшем наш код был платформонезависимым.
Читать дальше →
Всего голосов 42: ↑40 и ↓2+38
Комментарии20

Приёмы неблокирующего программирования: полные барьеры памяти

Время на прочтение9 мин
Количество просмотров9.2K

В первых двух статьях цикла мы рассмотрели четыре способа упорядочить доступ к памяти: load-acquire и store-release операции в первой части, барьеры чтения и записи в память — во второй. Теперь пришла очередь познакомиться с полными барьерами памяти, их влиянием на производительность, и примерами использования полных барьеров в ядре Linux.


Рассмотренные ранее примитивы ограничивают возможный порядок исполнения операций с памятью четырьмя различными способами:


  • Load-acquire операции выполняются перед последующими чтениями и записями.
  • Store-release операции выполняются после предыдущих чтений и записей.
  • Барьеры чтения разделяют предыдущие и последующие чтения из памяти.
  • Барьеры записи разделяют предыдущие и последующие записи в память.

Внимательный читатель заметил, что одна из возможных комбинаций в этом списке отсутствует:

Чтение выполняется... Запись выполняется...
… после чтения smp_load_acquire(), smp_rmb() smp_load_acquire(), smp_store_release()
… после записи ??? smp_store_release(), smp_wmb()
Оказывается, обеспечить глобальный порядок записей и последующих чтений из памяти гораздо сложнее. Процессоры вынуждены прилагать отдельные усилия для этого. Сохранение такого порядка стоит недёшево и требует явных инструкций. Чтобы понять причину этих особенностей, нам придётся спуститься на уровнь ниже и присмотреться к тому, как процессоры работают с памятью.
Читать дальше →
Всего голосов 10: ↑10 и ↓0+10
Комментарии4

Приёмы неблокирующего программирования: атомарные операции и частичные барьеры памяти

Время на прочтение8 мин
Количество просмотров12K

В первой статье цикла мы познакомились с простыми неблокирующими алгоритмами, а также рассмотрели отношение “happens before”, позволяющее их формализовать. Следующим шагом мы рассмотрим понятие «гонки данных» (data race), а также примитивы, которые позволяют избежать гонок данных. После этого познакомимся с атомарными примитивами, барьерами памяти, а также их использованием в механизме “seqcount”.


С барьерами памяти некоторые разработчики ядра Linux уже давно знакомы. Первый документ, содержащий что-то похожее на спецификацию гарантий, предоставляемых ядром при одновременном доступе к памяти — он так и называется: memory-barriers.txt. В этом файле описывается целый зоопарк барьеров вместе с ожидаемым поведением многопоточного кода в ядре. Также там описывается понятие «парных барьеров» (barrier pairing), что похоже на пары release-acquire операций и тоже помогает упорядочивать работу потоков.


В этой статье мы не будем закапываться так же глубоко, как memory-barriers.txt. Вместо этого мы сравним барьеры с моделью acquire и release-операций и рассмотрим, как они упрощают (или, можно сказать, делают возможной) реализацию примитива “seqcount”. К сожалению, даже если ограничиться лишь наиболее популярными применениями барьеров — это слишком обширная тема, поэтому о полных барьерах памяти мы поговорим в следующий раз.

Читать дальше →
Всего голосов 11: ↑11 и ↓0+11
Комментарии3

Введение в неблокирующие алгоритмы

Время на прочтение8 мин
Количество просмотров24K

Неблокирующие алгоритмы широко применяются в ядре Linux когда традиционные примитивы блокировки либо не могут быть использованы, либо недостаточно быстры. Эта тема многим интересна и время от времени всплывает на LWN. Из недавнего — вот эта июльская статья, которая собственно и сподвигла меня написать свою серию. Ещё чаще разговор заходит про механизм read-copy-update (RCU — руководство 2007 года всё ещё актуально), подсчёт ссылок, и способы сделать более понятные, высокоуровные API ко всему этому разнообразию. Ну а сейчас вас ждёт погружение в идеи, стоящие за неблокирующими алгоритмами, а также их использованием в ядре.


Знание низкоуровневой модели памяти в целом считается продвинутым уровнем понимания, которого страшатся даже опытные программисты-ядерщики. Словами нашего редактора (из его июльской статьи): «Понять модель памяти можно лишь правильно повёрнутым мозгом». Говорят, что моделью памяти Linux (и файлом memory-barriers.txt в частности) можно пугать детей. Порой для достижения эффекта достаточно всего лишь рявкнуть “acquire” или “release”.


И в то же время, механизмы вроде RCU и seqlocks так широко применяются в ядре, что практически каждый разработчик рано или поздно сталкивается с фундаментально неблокирующими интерфейсами. Поэтому многим будет полезно иметь хотя бы базовое представление о неблокирующей синхронизации. В этой серии статей я расскажу, что же на самом деле означает acquire и release-семантика, а также приведу пять сравнительно простых паттернов, которые покрывают большинство вариантов использования неблокирующих примитивов.

Читать дальше →
Всего голосов 27: ↑24 и ↓3+33
Комментарии60

Не изобретая велосипед. Кэширование: рассказываем главные секреты оптимизации доступа к данным

Время на прочтение4 мин
Количество просмотров9.7K

Точно скажу, что костыли и велосипеды не лучшее решение, особенно если мы говорим о кэшировании, а конкретнее, если нам надо оптимизировать метод доступа к данным, чтобы он имел производительность выше, чем на источнике. Я докажу это на нескольких примерах, приведённых в статье, всего за 5 минут.


Читать дальше →
Всего голосов 9: ↑7 и ↓2+5
Комментарии6

C++20: Пулы потоков в cppcoro

Время на прочтение5 мин
Количество просмотров5.4K

Этот пост является заключительным в моей мини-серии из трех постов о cppcoro. cppcoro — это библиотека абстракций корутин от Льюиса Бейкера (Lewis Baker). Сегодня я покажу вам пулы потоков (thread pools).

 

Читать далее
Всего голосов 10: ↑9 и ↓1+8
Комментарии1

Анатомия асинхронных фреймворков в С++ и других языках

Время на прочтение20 мин
Количество просмотров43K
Привет! В этой статье я расскажу об устройстве асинхронных движков с корутинами и без них. Для начала сосредоточимся не на конкретном движке, а на том, почему во всех популярных языках программирования появились корутины и чем они так хороши. Это может быть интересно не только C++-разработчикам, но и всем, кто занимается разработкой сетевых приложений или интересуется архитектурой современных фреймворков.

Пройдёмся по разным архитектурам построения серверов — от самой простой синхронной к более интересным, посмотрим на типичную архитектуру корутинового движка, а после окунёмся в дебри C++ и взглянем на самое страшное на примере нашего фреймворка userver.

Пишем синхронный сервер


Представьте, что у вашего сервиса очень маленькая нагрузка — 100 rps, и вам дали задачу написать простой сервер, понятный каждому второму школьнику. У вас получится что-то наподобие следующего:

void naive_accept() {
  for (;;) {
    auto new_socket = accept(listener);

    std::thread thrd([socket = std::move(new_socket)] {
      auto data = socket.receive();
      process(data);
      socket.send(data);
    });

    thrd.detach();
  }
}
Читать дальше →
Всего голосов 56: ↑53 и ↓3+63
Комментарии32

О шаблонах в С++, чуть сложнее

Время на прочтение40 мин
Количество просмотров34K

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

Потрогать здесь
Всего голосов 50: ↑50 и ↓0+50
Комментарии31

Просто о шаблонах C++

Время на прочтение50 мин
Количество просмотров188K

Статья для тех, кто боится слова template в C++. Вводная информация с примерами и их подробным разбором.

Читать далее
Всего голосов 62: ↑61 и ↓1+70
Комментарии35

Самые интересные блоги и сайты для C++ программистов

Время на прочтение4 мин
Количество просмотров17K

С++ Top
Наверняка у читателя есть свои любимые сайты и блоги, посвящённые программированию на языке С++. Сегодня ваша коллекция пополнится.

Читать дальше →
Всего голосов 20: ↑17 и ↓3+20
Комментарии2

[ В закладки ] Алгоритмы и структуры данных в ядре Linux, Chromium и не только

Время на прочтение9 мин
Количество просмотров86K
Многие студенты, впервые сталкиваясь с описанием какой-нибудь хитроумной штуки, вроде алгоритма Кнута – Морриса – Пратта или красно-чёрных деревьев, тут же задаются вопросами: «К чему такие сложности? И это, кроме авторов учебников, кому-нибудь нужно?». Лучший способ доказать пользу алгоритмов – это примеры из жизни. Причём, в идеале – конкретные примеры применения широко известных алгоритмов в современных, повсеместно используемых, программных продуктах.



Посмотрим, что можно обнаружить в коде ядра Linux, браузера Chromium и ещё в некоторых проектах.
Читать дальше →
Всего голосов 158: ↑149 и ↓9+140
Комментарии15

Как простой баг повреждения памяти ядра Linux может привести к полной компрометации системы

Время на прочтение47 мин
Количество просмотров5.8K

Введение


В этом посте описывается простой в реализации баг блокировки ядра Linux и то, как я использовал его против ядра Debian Buster 4.19.0-13-amd64. В посте рассматриваются варианты устранения бага, препятствующие или усложняющие использование подобных проблем злоумышленниками.

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

Многие описанные здесь отдельные техники эксплойтов и варианты их устранения не новы. Однако я считаю, что стоит объединить их в одну статью, чтобы показать, как различные способы устранения взаимодействуют друг с другом на примере достаточно стандартного эксплойта с использованием освобождённой памяти.
Читать дальше →
Всего голосов 14: ↑14 и ↓0+14
Комментарии1

Обучение умных игровых соперников в Unity методом «игра с самим собой» средствами ML-Agents

Время на прочтение9 мин
Количество просмотров3.7K
Привет, Хабр!

Как знают наши постоянные читатели, мы давно и успешно издаем книги по Unity. В рамках проработки темы нас заинтересовал, в частности, инструментарий ML-Agents Toolkit. Сегодня мы предлагаем вашему вниманию перевод статьи из блога Unity о том, как эффективно обучать игровых агентов методом игры «с самим собой»; в частности, статья помогает понять, чем этот метод эффективнее традиционного обучения с подкреплением.



Приятного чтения!
Читать дальше →
Всего голосов 2: ↑2 и ↓0+2
Комментарии5

Конвертируй это — с Yandex Message Queue

Время на прочтение10 мин
Количество просмотров5K

Довольно прозаичный и понятный в быту термин порой все еще вызывает вопросы в IT. Зачем при разработке приложений использовать очереди или сервисы очередей, чтобы автоматизировать этот процесс? Ответим на этот вопрос практическими примером — напишем в serverless-стеке Yandex.Cloud сервис для конвертации видео в GIF, используя Yandex Message Queue — ту самую очередь.

Читать далее
Всего голосов 13: ↑12 и ↓1+13
Комментарии1

Как и чем живёт современный Токио

Время на прочтение16 мин
Количество просмотров31K
В предыдущем материале я рассмотрел причины, привёдшие к образованию Токайдo, а также основы японского городского планирования. Сегодня расскажу о том, как и чем живёт современный Токио, ядро этого громадного мегалополиса: жилищный вопрос, постепенный отход от эгалитаризма в эпоху post bubble economy, несколько социальных феноменов.

Читать дальше →
Всего голосов 84: ↑82 и ↓2+116
Комментарии20

Информация

В рейтинге
4 292-й
Откуда
Санкт-Петербург, Санкт-Петербург и область, Россия
Зарегистрирован
Активность