Adrift, да он и есть (ну тоесть что-то внутреннее из него) -- но моя то функция успешно встроилась, с присущими последовательному коду оптимизациями. Твои свопы так же много раз прыгают в разные куски кода) При этом они сортируют все значения, а std::nth_element() нет... -- он только подставляет значение в указанном элементе, таким, как если бы массив стал отсортирован полностью.
int median5_adrift(const int* arr) { int a = arr[0], b = arr[1], c = arr[2], d = arr[3], e = arr[4];
if (a > b) std::swap(a, b); if (b > c) std::swap(b, c); if (c > d) std::swap(c, d); if (a > b) std::swap(a, b); if (b > c) std::swap(b, c); if (c > e) std::swap(c, e); if (a > b) std::swap(a, b); return (b > c) ? b : c; }
int median5_adrift2(int* arr) { if (arr[0] > arr[1]) std::swap(arr[0], arr[1]); if (arr[1] > arr[2]) std::swap(arr[1], arr[2]); if (arr[2] > arr[3]) std::swap(arr[2], arr[3]); if (arr[0] > arr[1]) std::swap(arr[0], arr[1]); if (arr[1] > arr[2]) std::swap(arr[1], arr[2]); if (arr[2] > arr[4]) std::swap(arr[2], arr[4]); if (arr[0] > arr[1]) std::swap(arr[0], arr[1]); return (arr[1] > arr[2]) ? arr[1] : arr[2]; }
for (int i = 0; i < 100'000'000; i++) { volatile auto v = median5_adrift(arr.data()); // 0.24s //volatile auto v = median5_adrift2(arr.data()); // 0.19s //volatile auto v = median5_safocl(arr); // 0.38s //volatile auto v = median5_safocl2(arr); // 0.25s }
auto elapsedTime = duration_cast<duration<double>>(steady_clock::now() - time).count(); std::println("{}", elapsedTime); }
Ничего не поменялось, мой вариант не изменяющий массив работает быстрее твоего, даже второго варианта, который массив изменяет и после первой итерации сортирует уже отсортированные данные )
а ты прими извне данные -- а не из известных наперед (в компайл тайме) значений памяти...
Пожалуйста, добавляем в загрузку volatile:
Код:
int a = (volatile int&)arr[0], b = (volatile int&)arr[1], c = (volatile int&)arr[2], d = (volatile int&)arr[3], e = (volatile int&)arr[4];
Было 0.24s, стало 0.26s, по-прежнему быстрее, чем 0.38s ) На самом деле для STM32H5 и gcc я так и делал, иначе компилятор мою функцию сворачивал до константы.
safocl писал(а):
Adrift, ты даже заблуждаешься что ты ничего не меняешь -- при этом свапая все значения)))
Я своплю значения регистров. Второй вариант действительно свопит в памяти, но он там для сравнения, ведь тебе я тоже добавил функцию передающую array по ссылке, что можно считать заменой передачей со span, которую ты назвал достойным вариантом )
Заголовок сообщения: Re: Хитрые, необычные алгоритмы и код
Добавлено: Чт дек 05, 2024 20:03:37
Собутыльник Кота
Карма: 38
Рейтинг сообщений: 268
Зарегистрирован: Пт сен 07, 2018 20:20:02 Сообщений: 2723 Откуда: деревня в Тульской губернии
Рейтинг сообщения:0 Медали: 1
Массив передается в функцию по указателю, поэтому просто обязан быть в памяти. А локальным переменным функции ничто не мешает быть регистровыми, что и использует компилятор. Вполне здравая и эффективная идея Adrift заключается в том, что компилятор видит, что из переставляемых значений используется в итоге лишь одно, да и то возвращается в регистре, как результат функции. Поэтому реальную перестановку ему даже не обязательно производить. Другой вопрос, что при наличии SIMD инструкций, перестановки ими не оптимизируются. Но в связи с тем, Adrift отказывается мыслить шире, чем в рамках используемой им сейчас архитектуры, обсуждение этого ранее зашло в тупик.
ПростоНуб, тут как раз в CubeMX добавили STM32N6, который выйдет в следующем году и будет иметь нормальный SIMD, так вот самый мелкий корпус там vfbga142 - это к вопросу об их массовом использовании в эмбедде )
ПростоНуб, тут как раз в CubeMX добавили STM32N6, который выйдет в следующем году и будет иметь нормальный SIMD, так вот самый мелкий корпус там vfbga142 - это к вопросу об их массовом использовании в эмбедде )
Для Вас embedded system заканчивается на STM32, а у моего клиента на заводе есть embedded system даже на Epyc. У многих дома - на одноплатниках под Linux и HA. Впрочем даже у Вас наверняка есть embeded ARM с SIMD в смартфоне. Почитайте внимательней, что не для Вас, а для большинства, считается embedded system: https://en.wikipedia.org/wiki/Embedded_system
Если при компиляции целиком это и может быть заинлайнено или как-то оптимизировано, то в случае библиотечной функции, С++ ABI не позволяет передать массив, иначе, чем по указателю. Впрочем меня опять тут начнут укорять, что я методологии профессиональной разработки пытаюсь применять к пет-проектам, где никто изоляцией кода между модулями проекта не заморачивается, так как разработчик всегда один и только один.
Для Вас embedded system заканчивается на STM32, а у моего клиента на заводе есть embedded system даже на Epyc. У многих дома - на одноплатниках под Linux и HA. Впрочем даже у Вас наверняка есть embeded ARM с SIMD в смартфоне.
Здорово, только это раздел микроконтроллеров и ПЛИС, не одноплатников, соответственно понятие embedded тут уточненное ) Вы же прекрасно понимаете, что шла бы речь про Epic и одноплатники на Linux никто бы к вашему SIMD не цеплялся, но речь про микроконтроллеры где этот SIMD присутствует в виде очень редкого исключения. С другой стороны важно ведь не само наличие SIMD, а его влияние на производительность, правильно? Например, STM32H7 на 550MHz, выполняющие 2 инструкции за такт, даже без нормального SIMD должны быть существенно быстрее вашего Xtensa с SIMD. И что прикажете делать? Какой из этих двух мк устарел? )
да в общем то нет -- не ответил -- с чего взято, что std::array это какая то нестековая память и что он не является POD типом и агрегатом?
Какая разница, стековая или не стековая? В данном случае, раз T POD и никаких собственных конструктора, операторов или деструктора добавлено не было, это как раз POD тип. С точки зрения С++ ABI, POD массив передается всегда, как указатель. Если очень интересно, можете погрузиться в спецификацию Itanium C++ ABI.
С точки зрения С++ ABI, POD массив передается всегда, как указатель.
непонятно откуда такая инфа -- возможно ты путаешь аргумент в виде (int arr[]) -- но std::array в аргументе не превращается в такое -- но в первом случае просто правило языка C++ действует, которое делает decoy int[] к int* в аргументе функций -- тут ничего общего с моим случаем.
Здорово, только это раздел микроконтроллеров и ПЛИС, не одноплатников, соответственно понятие embedded тут уточненное
Я же уже писал, хотите себя ограничивать и для каждой архитектуры, для которой ведете разработку, переписывать библиотечные функции заново - Ваши проблемы. Я имею все основания утверждать, что в профессиональной разработке предпочитительно иметь, по возможности, один и тот же код для всех платформ. Но доказывать Вам выгоды такого решения уже утомился. Так что делайте как хотите. Мне от этого хуже не будет )
Например, STM32H7 на 550MHz, выполняющие 2 инструкции за такт, даже без нормального SIMD должны быть существенно быстрее вашего Xtensa с SIMD. И что прикажете делать?
Могу посмеяться над голословным утверждением. Без данных тестирования, которое можно повторить и проверить, говорить об этом смысла не имеет. Возможны любые результаты. Например, в том же ffmpeg переход на SSSE3 дал прирост производительности некоторых функций в 40 раз, а на AVX-512 - в 94 раза. Так что имея почти двукратный выигрыш в CoreMark, STM32H7 вполне может проиграть.
Заголовок сообщения: Re: Хитрые, необычные алгоритмы и код
Добавлено: Чт дек 05, 2024 22:03:14
Первый раз сказал Мяу!
Зарегистрирован: Пн мар 18, 2024 22:04:17 Сообщений: 37
Рейтинг сообщения:0
причина более худшего в тестировании с std::array моем варианте скорости сокрыта не в нем, а как оказалось в почему то грустно работающем std::sort и nth_element -- они обязаны за O(n) и O(n*log(n)) работать соответственно применяя компаратор, но почему то получается в этих реализациях бибилиотек c++ дополнительные накладные расходы предоставляют...
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 9
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения