Войти
ПрограммированиеФорумОбщее

Вопросы по Delphi (7 стр)

Страницы: 16 7 8 958 Следующая »
#90
8:55, 23 мая 2022

  Ага, позже уже сделаю полноценный тест и напишу о полученных результатах ;).

#91
8:57, 23 мая 2022

  Mirrel, это будет достаточно сложно реализовать, но как-нибудь попробую. Спасибо!

#92
8:59, 23 мая 2022

skalogryz
> раза в 4, а то и больше.
в зависимости как будет реализована эта побайтовая проверка. Можно проверить 8, 16, 32 байта в развёрнутом цикле. Там тоже скорость будет "высокая", за счёт того, что мы не будем выполнять цикл.
Ну да, при соответствующих длинах массива.

Простой пример: делим длину массива на 32 (обычно берут 8), прогоняем по развернутому массиву получившееся количество раз. Остаток прогоняем по обычному циклу.

Решение давнее и не моё. ))) Просто вспомнил.

#93
(Правка: 12:23) 11:34, 23 мая 2022

  Вот такой небольшой тест получился:

+ Показать

  И таки да, удалось достичь той же скорости что и IndexOfByte по сути).
P.S. Что-то рано обрадовался, так как CheckNonZeroItem как-то не корректно работает(всегда возвращает True)), но зато функция skalogryz-а с некоторыми минимальными правками дает такой же по скорости результат.
P.S.2. Тупо забыл инициализировать результат ^_^. В примере выше исправил.

#94
11:53, 23 мая 2022

ArtProg
> GetTickCount64
мммм... этим не пользуются для измерений скорости.
Вот этим измеряй скорость QueryPerformanceCounter. Можешь здесь посмотреть как это работает. Демка на скорость. Используй только делфи.
Или гугл в помощь. )))

#95
12:02, 23 мая 2022

Mirrel, благодарю за ссылку. Помню еще на каком-то дельфийском форуме содрал модуль по работе с измерением времени. И там тоже GetTickCount64 присутствовал.

#96
(Правка: 16:00) 13:47, 23 мая 2022

  Вобщем получился такой доработанный код:

// находит первый ненулевой элемент массива, начиная с data_start, 
// length - количество элементов, которые нужно проверить.
function NotIndexByte(data_start:PByte; length:integer): integer;
var
  n,m: integer;
begin
  Result:=-1;
  for n:=0 to length>>3-1 do
    if (PQWord(data_start+n<<3)^<>0) then
      begin
        Result:=n<<3;
        Break;
      end;
  data_start+=Result;
  for m:=0 to Min(7,length-Result) do
    if (PByte (data_start+m<<0)^<>0) then
      begin
        Result+=m<<0;
        Break;
      end;
end;
#97
15:34, 23 мая 2022

ArtProg
> PQWord(data_start+n<<3)^<>val
Работает верно только для val равного 0 (байт $00 превращается в $0000000000000000)
Для к примеру val равного $77 будет неправильно, будет сравнение с $0000000000000077 вместо $7777777777777777

#98
(Правка: 16:06) 15:53, 23 мая 2022

Недавно была подобная задача на сишечке, переделал под поиск неравного байта:
https://gcc.godbolt.org/z/ffE9xhrcW
Плюс в использовании SSE при сохранении читабельности, в Дельфи SSE - это неизбежный ассемблер. Можно и AVX, но там от AVX небольшой эффект, процентов 20.

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

#99
(Правка: 16:00) 15:58, 23 мая 2022

  CD, по ходу дела так и есть). Дельное замечание. На самом деле мне пока что и неравенста нулю хватает(в большинстве циклов у меня в коде как раз такие проверки). Но дабы не вводить в забдуждение допишу еще комментарий вверху. Без понятия на данный момент как на общий случай распространить(умножение на ту константу $0101010101010101 результата увы не дало).

#100
16:10, 23 мая 2022

invis, может быть как внешнюю процедуру получится вызвать. Не уверен правда, что компилятор Лазаруса это хоть как-то распараллелит(сильно не вникал, но вроде бы есть поддержка SSE по крайней мере), скорее всего никак. Придется курить ассемблерный код тогда. У меня тут еще одна идея нарисовалась, надо бы проверить, но опять таки для ненулевых значений).

#101
16:46, 23 мая 2022

В FPC есть некие зачатки высокоуровневого SSE, вроде векторных типов byte16 из моего примера.
https://forum.lazarus.freepascal.org/index.php?topic=32741.0
Но работало (когда я пробовал) хреновенько, только на элементарных примерах.

#102
17:22, 23 мая 2022

Как внешнюю - можно линковать сишный .obj, в 64 битах у Дельфи тот же формат и линкует без проблем. Хотя я предпочитаю dll, их всё-таки отлаживать можно. А .obj отлаживаются только как ассемблер.

Если есть готовность ковыряться в ассемблере, то у меня была ещё похожая функция поиска подстроки:

+ Показать

Поиск первого неравного символа проще, можно выкинуть сравнение с "хвостом" и выходить на первом найденном неравенстве.

#103
21:38, 23 мая 2022

  Спасибо за ссылки и примеры кода! Есть некоторые вопросы касательно последней функции на асме, но это уже наверное завтра буду разбираться, а то сегодня у меня почти целый день был посвящен данной тематике).

#104
(Правка: 24 мая 2022, 1:20) 22:34, 23 мая 2022

ArtProg
> умножение на ту константу $0101010101010101 результата увы не дало
вообще это было взято из работы с массивом символов. Но там должна быть известна длина строки.

Вот код, можешь потестировать. Правда писал я его на коленке и не проверял.

function FindArrZero(arr: pbyte; len_arr: LongWord): LongWord;
var
  i, j, _ost: Integer;
  _arr: PQWord;
begin
    // делаем выборку из 8 элементов. Длину массива делим на 8.
  j := len_arr div 8;  // допустим будем брать 8 элементов сразу. Хотя бы потому что это удобно.
  _ost := len_arr - j * 8;  // 
  Result := 0;
  while j > 0 do
  begin
    _arr := arr[0];
    inc(arr, 8);
    if (_arr^ and $FF) <> 0 then
      inc(Result)
    else
      exit;
    if (_arr^ and $FF00) <> 0 then
      inc(Result)
    else
      exit;
    if (_arr^ and $FF0000) <> 0 then
      inc(Result)
    else
      exit;
    if (_arr^ and $FF000000) <> 0 then
      inc(Result)
    else
      exit;
    if (_arr^ and $FF00000000) <> 0 then
      inc(Result)
    else
      exit;
    if (_arr^ and $FF0000000000) <> 0 then
      inc(Result)
    else
      exit;
    if (_arr^ and $FF000000000000) <> 0 then
      inc(Result)
    else
      exit;
    if (_arr^ and $FF00000000000000) <> 0 then
      inc(Result)
    else
      exit;
    dec(j);
  end;
  for i := 0 to _ost do
  begin
    if arr[i] <> 0 then
      inc(Result)
    else
      exit;
  end;
end.

Функция вернёт номер элемента где встретился первый нуль. Если вернётся полная длина массива, значит нуля не было.
Не пытайся свернуть цикл, этим ты только усугубишь ситуацию по скорости работы. Ты можешь её ещё больше развернуть, взяв два/четыре значения QWord. Можно и больше взять, просто цикл будет огромным. Это нужно только в том случае, если у тебя огромные проверяемые массивы, в противном случае это бостолковое занятие.

Будет ли использование SIMD лучше данного результата? Не уверен. SIMD предназначен (в основном) для других целей.

Будет ли скорость быстрее если использовать многопоточку? Да, особенно если массив имеет достаточно большую длину.

Страницы: 16 7 8 958 Следующая »
ПрограммированиеФорумОбщее