Pull to refresh
  • by relevance
  • by date
  • by rating

Производительность shared_ptr и C++11: почему я не верю библиотекам

C++ *
Здравствуйте!

Оптимизировал я однажды критический участок кода, и был там boost::shared_ptr… И понял я: не верю я библиотекам, хоть и пишут их дядьки умные.

Детали под катом.
Читать дальше →
Total votes 84: ↑72 and ↓12 +60
Views 24K
Comments 49

Одним махом 100 миллионов убивахом. Или lock-free распределитель памяти

Programming *C++ *Concurrent computing *

Постановка задачи


Один из алгоритмов, который я реализовывал, имел интересные особенности при работе с памятью:
  • Могло выделяться огромное количество, до десятков и сотен миллионов небольших объектов одного типа.
  • Объекты представляли собой POD- типы.
    POD
    A Plain Old Data Structure in C++ is an aggregate class that contains only PODS as members, has no user-defined destructor, no user-defined copy assignment operator, and no nonstatic members of pointer-to-member type.
  • Заранее было неизвестно какое количество объектов понадобится, могло так случится, что потребуется сотня, а может и сто миллионов.
  • Объекты никогда не удаляются по одному, в какой-то момент они становятся не нужны все сразу.
  • Алгоритм хорошо распараллеливается, по этому выделением объектов занимается одновременно несколько потоков, по количеству ядер процессора(ов).

Использование в таких условиях стандартного new – delete приводит к очень большим потерям времени на удаление объектов. Если без отладчика удаление происходило хотя бы за несколько секунд, то в присутствии отладчика освобождение памяти замедляется примерно в 100(!) раз, и отладка проекта становится просто невозможной. Кроме того из-за большого количества выделенных объектов достаточно ощутимым становился перерасход памяти на внутренние данные распределителя памяти.
Для решения задачи выделения огромного количества объектов одного типа, и их пакетного удаления, был сделан lock-free контейнер MassAllocator. Код компилируется Visual Studio 2012. Полный код проекта выложен на github.
Читать дальше →
Total votes 34: ↑32 and ↓2 +30
Views 14K
Comments 42

Lock-free структуры данных. Основы: Атомарность и атомарные примитивы

Programming *C++ *

Построение lock-free структур данных зиждется на двух китах – атомарных операциях и способах упорядочения доступа к памяти. В этой статье речь пойдет об атомарности и атомарных примитивах.

Анонс. Спасибо за теплый прием Начал! Вижу, что тема lock-free интересна хабрасообществу, это меня радует. Я планировал построить цикл по академическому принципу, плавно переходя от основ к алгоритмам, попутно иллюстрируя текст кодом из libcds. Но часть читателей требует зрелищ не мешкая показать, как пользоваться библиотекой, особо не рассусоливая. Я согласен, в этом есть свой резон. В конечном счете, и мне не так интересно, что там внутри boost, — опишите, как его применять! Поэтому свой эпический цикл я разделю на три части: Основы, Внутри и Извне. Каждая статья эпопеи будет относится к одной из частей. В Основах будет рассказываться о низкоуровневых вещах, вплоть до строения современных процессоров; это часть для почемучек вроде меня. Внутри будет освещать интересные алгоритмы и подходы в мире lock-free, — это скорее теория о том, как реализовать lock-free структуру данных, libcds будет неисчерпаемым источником C++ кода. В Извне будут статьи о практике применения libcds, — программные решения, советы и FAQ. Извне будет питаться вашими вопросами/замечаниями/предложениями, дорогие хабражители.

А пока я судорожно готовлю начало Извне, — первая часть Основ. Статья во многом не о C++ (хотя и о нем тоже) и даже не о lock-free (хотя без atomic lock-free алгоритмы неработоспособны), а о реализации атомарных примитивов в современных процессорах и о базовых проблемах, возникающих при использовании таких примитивов.
Атомарность — это первый круг ада низкий уровень из двух.
Читать дальше →
Total votes 119: ↑116 and ↓3 +113
Views 95K
Comments 34

OpenCL 2.0 и драйверы от AMD и Intel

High performance *GPGPU *
Незамеченной на хабре прошла новость о появлении OpenCL 2.0 драйверов от AMD и Intel.

Многим кажется, что подобный API просто очередной маркетинговый buzzword. Отчасти это так, потому что почти все современные аппаратные продукты выходят с пунктом «OpenCL» в списке поддерживаемых технологий и рекламе: последние CPU, GPU, APU (CPU+GPU), FPGA, CPU+FPGA. И многим из области разработки enterprise ПО хочется откреститься от этих «модных» названий, но и это скоро станет невозможно стараниями Oracle и AMD.

Массовый параллелизм аппаратного обеспечения уже давно присутствует в серверах, пресональных компьютерах, телефонах и планшетах, специализированных аппаратных ускорителях. OpenCL в области FPGA рассматривается как способ упростить, удешевить и популяризовать разработку. При этом использование преимуществ, предоставляемых аппаратурой, пока требует от программиста использовать таких API как OpenCL, CUDA, OpenMP. Но появляются попытки скрыть эту сложность от прикладных программистов, например Project Sumatra и ScalaCL.
Читать дальше →
Total votes 17: ↑15 and ↓2 +13
Views 35K
Comments 5

Использование handle и intrusive reference counter-ов в многопоточных средах в языке C

System Analysis and Design *C *Concurrent computing *
Sandbox
Доступ к одим и тем же данным в нескольких потоках считается плохой практикой, но во многих случаях это неизбежно, и это не тот вопрос, который обсуждается здесь. Вопрос который здесь обсуждается, это как организовать такой доступ наиболее безопасным способом. Также тут не обсуждаются атомарные операции, которые тут упоминаются: разные компиляторы предлагают различные средства для таких операций.

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

Это может быть сделано несколькими способами, но мы будем говорить только о двух из них: хэндлы (handles) и встроенные счётчики ссылок (intrusive reference counters).
Читать дальше →
Total votes 13: ↑12 and ↓1 +11
Views 8.5K
Comments 24

Обзор примитивов синхронизации — спинлоки и тайны ядра процессора

Assembler *System Programming *Programming microcontrollers *
Последняя статья про классические примитивы синхронизации.

(Наверное, потом напишу ещё одну про совсем уже нетипичную задачу, но это потом.)

Сегодня мы немножко заглянем в процессор. Чуть-чуть.

По сути, мы будем говорить про единственный примитив, который принципиально отличается от остальных: спинлок. Spinlock.

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

На уровне процесса всё так и есть — различия между спинлоком и мьютексом — чисто технические, вопрос реализации и производительности.

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

Дело в том, что внутри ядра мьютекс реализован с помощью спинлоков, а вот спинлоки реализованы сами по себе, автономно. Они — действительно базовый примитив. Ниже — только сам процессор.

Есть и ещё одно, семантическое различие. Мьютекс допускает и предполагает снятие нити с процессора, долгую остановку вызывающей нити. Мьютексом можно запереть объект на час или сутки, это приемлемо и нормально. Спинлок принципиально рассчитан только на кратчайшие приостановки, это всегда работа с неатомарным стейтом объекта. Присваивание группы переменных, небольшой цикл — это максимум того, что можно сделать под спинлоком.

Итак, иерархия реализации такова: mutex/cond/sema сделаны на базе спинлоков, спинлоки — на базе атомарных операций, предоставляемых процессором. Мы в них немного заглянем сегодня.

Как устроен спинлок?
Читать дальше →
Total votes 43: ↑41 and ↓2 +39
Views 45K
Comments 45

Ускоряем std::shared_mutex в 10 раз

High performance *Programming *C++ *Concurrent computing *
В этой статье мы детально разберем атомарные операции и барьеры памяти C++11 и генерируемые ими ассемблерные инструкции на процессорах x86_64.

Далее мы покажем как ускорить работу contfree_safe_ptr<std::map> до уровня сложных и оптимизированных lock-free структур данных аналогичных по функциональности std::map<>, например: SkipListMap и BronsonAVLTreeMap из библиотеки libCDS (Concurrent Data Structures library): github.com/khizmax/libcds

И такую многопоточную производительность мы сможем получить для любого вашего изначально потоко-небезопасного класса T используемого как contfree_safe_ptr<T>. Нас интересуют оптимизации повышающие производительность на ~1000%, поэтому мы не будем уделять внимание слабым и сомнительным оптимизациям.
Читать дальше →
Total votes 54: ↑54 and ↓0 +54
Views 40K
Comments 22

Ещё один шажок к C++20. Встреча в Альбукерке

Яндекс corporate blog Programming *C++ *Compilers *IT Standards *
Из центральной части Канады — на юго-запад США! Альбукерке расположен в штате Нью-Мексико:



На встрече международного комитета по стандартизации C++, которая прошла в этом городе, приняли одно очень большое нововведение в С++20 и несколько маленьких.
Читать дальше →
Total votes 63: ↑62 and ↓1 +61
Views 19K
Comments 260

C++ велосипедостроение для профессионалов

Конференции Олега Бунина (Онтико) corporate blog Programming *C++ *Compilers *IT Standards *
Классы, которые люди самостоятельно пишут, а потом копируют из одного проекта в другой, хотя они уже есть в стандартных библиотеках, в простонародье называются велосипедами. Первый вопрос, который возникает при встрече с таким «велосипедом» — зачем люди переписывают что-то заново? Вариантов может быть несколько.

  • Некоторые делают это для самообучения: берут класс стандартной библиотеки, пишут его сами с нуля, сравнивают то, что получилось, с тем, что есть в стандартной библиотеке — в процессе узнают для себя что-то новое.
  • Некоторые проекты имеют особое требования к коду. В embedded-разработке принято работать без RTTI и без exception, поэтому части стандартной библиотеки, которые используют RTTI и exception, необходимо переписать без них.
  • Редко, но бывает, когда велосипед пишут, потому что могут написать лучше, чем в стандартной библиотеке. Как правило, такие нововведения рано или поздно попадают в стандартную библиотеку.
  • Другим только кажется, что они могут написать лучше, и таких людей больше. Но в процессе они обучаются, выясняют для себя что-то новое и что-то интересное открывают.
  • Могут быть другие причины.

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

  • бездумно переносить устаревшие технологии 20-30-летней давности в современные проекты;
  • пользоваться «вредными» бенчмарками и оптимизациями.

А также затронем «вредные» советы, обсудим новейшие практики программирования (C++ 11 и позднее), подумаем, что делать с «идеальным» велосипедом.

Total votes 76: ↑76 and ↓0 +76
Views 36K
Comments 102

Мифы о кэше процессора, в которые верят программисты

Concurrent computing *
Translation
Как компьютерный инженер, который пять лет занимался проблемами кэша в Intel и Sun, я немного разбираюсь в когерентности кэша. Это одна из самых трудных концепций, которые пришлось изучить ещё в колледже. Но как только вы действительно её освоили, то приходит гораздо лучшее понимание принципов проектирования систем.

Вы можете удивиться: зачем же разработчику ПО думать о механизме кэширования в CPU? Отвечу. С одной стороны, многие понятия из концепции когерентности кэша непосредственно применимы в распределённых системах и на уровнях изоляции СУБД. Например, представление реализации когерентности в аппаратных кэшах помогает лучше понять разницу в моделях согласованности (консистентности) — отличие строгой согласованности (strong consistency) от согласованности в конечном счёте (eventual consistency). У вас могут появиться новые идеи, как лучше обеспечить согласованность в распределённых системах, используя исследования и принципы из аппаратного обеспечения.

С другой стороны, неправильные представления о кэшах часто приводят к ложным утверждениям, особенно когда речь идёт о параллелизме и состоянии гонки. Например, часто говорят о трудности параллельного программирования, потому что «у разных ядер в кэшах могут быть разные/устаревшие значения». Или что квалификатор volatile в языках вроде Java нужен, чтобы «предотвратить локальное кэширование общих данных» и принудительно «читать/записывать только в основную память».
Читать дальше →
Total votes 75: ↑70 and ↓5 +65
Views 70K
Comments 72

С++20 на подходе! Встреча в Рапперсвил-Йона

Яндекс corporate blog Programming *C++ *Algorithms *Compilers *
В начале июня в городе Рапперсвил-Йона завершилась встреча международной рабочей группы WG21 по стандартизации C++.

Вот что вас ждёт под катом:
  • Контракты и друзья
  • Концепты (без друзей)
  • __has_cpp_attribute(unlikely)
  • bit_cast<my_stuff>(some_array)
  • contains, shift_left, shift_right, ispow2, ceil2… и старые алгоритмы под новым соусом
  • atomic_ref
  • Что нового можно писать в шаблонах и чем это полезно
  • constexpr virtual foo()
  • Parallelism 2, Reflection и Executors TS

Также будет бонус: минисекция для экспертов:

  • user-declared virtual destructor не влияет на тривиальность типа
  • Куда можно будет засунуть восклицательный знак и чем это может быть полезно
  • constexpr std::regex mail_regex(R"((?:(?:[^<>()\[\].,;:\s@\"]+(?:\.[^<>()\[\].,;:\s@\"]+)*)|\".+\")@(?:(?:[^<>()\[\].,;:\s@\"]+\.)+[^<>()\[\].,;:\s@\"]{2,}))")

Добро пожаловать под кат
Total votes 51: ↑50 and ↓1 +49
Views 18K
Comments 427