Рубрика «оптимизация программ» - 2

Многие программисты не понаслышке знают о том, что программа на языке C и C++ собирается очень долго. Кто-то решает эту проблему, сражаясь на мечах во время сборки, кто-то — походом на кухню «выпить кофе». Это статья для тех, кому это надоело, и он решил, что пора что-то предпринять. В этой статье разобраны различные способы ускорения сборки проекта, а также лечение болезни «поправил один заголовочный файл — пересобралась половина проекта».

Picture 1

Читать полностью »

Микрооптимизации в коде

Как правило, при обсуждении диагностических возможностей PVS-Studio за кадром остаются рекомендации, выдаваемые анализатором по поводу микрооптимизаций Си и Cи++ кода. Конечно, микрооптимизации не так важны, как диагностики выявляющие ошибки, но про них тоже интересно поговорить.
Читать полностью »

Всем известно, что преждевременная оптимизация — это плохо и надо себя одёргивать когда, возникает желание пооптимизировать не вовремя. Однако на практике чаще бывает ситуация когда естественное (и, возможно, интуитивно правильное) желание пооптимизировать подавляется по принципу «если вообще не оптимизировать — это не будет преждевременно». Либо так:

Своевременная оптимизация - 1

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

Хотя в принципе довольно странно оперировать какими-то эмпирическими понятиями по отношению к архитектуре программ, алгоритмам и их оптимизации — поскольку это вполне измеримые вещи. А значит — можно достаточно просто измерить своевременность оптимизации. Об этом и поговорим.
Читать полностью »

Прочтение публикации Упрощаем бинарный поиск в Excel сподвигло на дополнительное усовершенствование функции ВПР по сравнению с приведенным в статье.

Что не было учтено, и что хотелось бы добавить:

Читать полностью »

Добавлю в копилку статей Хабра о Бинарном поиске еще одну.
Речь пойдет о кастомной реализации, может быть полезно всем, кто часто использует в работе ВПР для сравнения больших списков или для поиска данных в больших массивах.

Предыстория

Все началось с того, что я открыл для себя т.н. Double-TRUE VLOOKUP trick (трюк с двойным использованием ВПР и ИСТИНА в 4-м параметре). Развернутое описание алгоритма можно найти в статье Charles Williams «Why 2 VLOOKUPS are better than 1 VLOOKUP» (в конце статьи).

Поняв принцип работы и открыв для себя, что этот подход может быть в тысячи раз быстрее обычного линейного поиска (ВПР с 4-м параметром ЛОЖЬ), я начал продумывать варианты раскрыть его возможности. В ходе реализации получилось несколько годных инструментов для контекстной рекламы, один из которых я еще продолжаю улучшать, и уже посвятил проекту пару статей на Хабре. Чтиво рекомендуется SEO-специалистам и специалистам по контекстной рекламе (сразу оговорюсь, по ссылкам в статьях уже устаревшие версии, последняя версия условно 6.0, ссылки на скачивание всех версий, включая самую свежую, будут в конце этой статьи):
Анализ больших семантических ядер, или «Робот-распознаватель»
Лемматизация в Excel, или «Робот-распознаватель 3.0

Так вот, несмотря на невероятную скорость работы этих файлов (невероятную для Excel), их создание потребовало использования таких же невероятно длинных мегаформул как одной из составляющих работы макросов (в последней из вышеуказанных статей приведен пример — формула на 3215 символов). И всему виной сложный синтаксис функции.
Если набить руку с его использованием, он перестает казаться сложным, но неискушенным пользователям, для которых предназначен такой подход, вряд ли захочется разбираться в нем.

Синтаксис выглядит так: Если(ВПР(искомое; массив;1; ИСТИНА)<искомое;""; ВПР(искомое; массив;n; ИСТИНА))
где n — порядковый номер столбца, из которого мы хотим вернуть значение напротив искомого ключа.
Вместо «ИСТИНА» в 4-м параметре можно использовать «1» для номинального сокращения длины формул, это не меняет их сути.
Если озвучить ход работы формулы, будет нижеследующее:
«Если бинарный поиск ключа по первому столбцу массива возвращает значение, меньшее, чем сам ключ, возвращаем пустую строку. Иначе — возвращаем результат бинарного поиска ключа со смещением n»
Подход используется для того, чтобы не возвращать никаких значений, если искомый ключ в массиве отсутствует, т.к. зачастую, если искомое не найдено — нам не нужно меньшее значение. Так сказать, все или ничего. Вкратце, в этом и есть суть «трюка».

Напомню, на карту поставлен прирост скорости, исчисляющийся трех-четырехзначными числами. Если подходить чисто математически — на массиве в 2^20 строк обычный бинарный поиск будет делать ~10 вычислений, формула выше — около 20, в то время, как линейный поиск — ~500.000, т.е. прирост формулы выше — в 25.000 раз. Если голые цифры не впечатляют, более красноречивое эквивалентное сравнение — 1 секунда против ~7 часов.
На практике прирост не столь существенный (в конце статьи ссылка на статью, где сравнивались разные способы). Это во многом связано с затратами процессорного времени на дополнительные процедуры, которые выполняет программа (например, запись значений в ячейки). НО прирост по-прежнему критически значимый (~4000 раз).

Но одновременно с этим мы имеем сложный, совершенно неюзабельный синтаксис. Не всем смертным дался ВПР, что говорить о комбинациях 2х ВПР с ЕСЛИ.

Вопрос со сложным синтаксисом я решил с помощью VBA — написал UDF (user-defined function, пользовательская функция), которая прячет под капот наши условные конструкции, оставляя нам привычный синтаксис всем известного ВПР.

Код UDF:
Читать полностью »

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

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

image

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

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

image

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

Введение

В предыдущем посте я постарался описать, как легко можно воспользоваться преимуществом GPU для обработки изображений. Судьба сложилась так, что мне подвернулась возможность попробовать улучшить медианную фильтрацию для GPU. В данном посте я постараюсь рассказать каким образом можно получить еще больше производительности от GPU в обработке изображений, в частности, на примере медианной фильтрации. Сравнивать будем GPU GTX 780 ti с оптимизированным кодом, запущенном на современном процессоре Intel Core i7 Skylake 4.0 GHz с набором векторных регистров AVX2. Достигнутая скорость фильтрации квадратом 3х3 в 51 GPixels/sec для GPU GTX 780Ti и удельная скорость фильтрации квадратом 3х3 в 10.2 GPixels/sec на 1 TFlops для одинарной точности на данное время являются самыми высокими из всех известных в мире.

Читать полностью »

Немного размышлений и советов по оптимизации кода на С++ - 1

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

Как правило, язык C++ используют там, где требуется высокая скорость работы. Но на C++ без особых усилий можно получить код, работающий медленнее какого-нибудь Python/Ruby. Именно подобным кодом оперируют многочисленные сравнения Any-Lang vs C++.

Вообще, оптимизация бывает трех типов:

  1. Оптимизация уже готового, проверенного и работающего кода.
  2. Изначально написание оптимального кода.
  3. Просто использование оптимальных конструкций.

Специально заниматься оптимизацией готового кода следует только после того, как проект закончен и используется. Как правило, оптимизация потребуется только в небольшой части проекта. Поэтому сначала нужно найти места в коде, которые съедают большую часть процессорного времени. Ведь какой смысл ускорять код, пусть даже на 500%, если он отнимает только 1% машинного времени? И следует помнить, что, как правило, гораздо больший выигрыш в скорости дает оптимизация самих алгоритмов, а не кода. Именно про данный ее вид говорят: «преждевременная оптимизация — зло» (с).

Второй тип оптимизации — это изначальное проектирование кода с учетом требований к производительности. Такое проектирование не является ранней оптимизацией.

Третий тип даже не совсем оптимизация. Скорее это избегание неоптимальных языковых конструкций. Язык C++ довольно сложный, при его использовании частенько нужно знать, как реализован используемый код. Он достаточно низкоуровневый, чтобы программисту пришлось учитывать особенности работы процессоров и операционных систем.
Читать полностью »

Введение

Ранее во вступительной статье я поднимал список проблем, с которыми придется столкнуться разработчику, если он захочет оптимизировать оптимизацию обработки изображения при помощи SIMD инструкций. Теперь пришло время на конкретном примере показать, как указанные выше проблемы можно решить. Я долго думал, какой алгоритм выбрать для первого примера, и решил остановиться на медианной фильтрации. Медианная фильтрация является эффективным способом подавления шумов, которые неизбежно появляются на цифровых камерах в условиях малого освещения сцены. Алгоритм этот достаточно ресурсоемок – так например, при обработке серого изображения медианным фильтром 3х3 требуется порядка 50 операций на одну точку изображения. Но в тоже время он оперирует только с 8-битными числами и ему для работы требуется сравнительно не много входных данных. Эти обстоятельства делают алгоритм достаточно простым для SIMD оптимизации и в тоже время позволяют получить из нее весьма существенное ускорение.

image
Читать полностью »


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js