Эффективное преобразование массива синглов в массив двойников в Delphi 2010 - PullRequest
0 голосов
/ 31 января 2011

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

Приложение создает массив из отдельных векторов:

unit unApplication
type

TVector = record
  x, y, z : single;
end;

TvectorArray = array of Tvector;

procedure someFunc(): tvectorArray;
[...]

в то время как подсистема ожидает массив двойных векторов.Я также реализовал приведение типов из tvector в Tvectord:

unit unSubSystem
type

TVectorD = record
  x, y, z : double;
  class operator Implicit(value : t3dVector):t3dvectorD;inline;
end;

TvectorDArray = array of TvectorD;

procedure otherFunc(points: tvectorDArray);

implementation 
    class operator T3dVecTorD.Implicit(value : t3dVector):t3dvectorD;
begin
  result.x := value.x;
  result.y := value.y;
  result.z := value.z;
end;

То, что я сейчас делаю, выглядит следующим образом:

uses unApplication, unsubsystem,...
procedure ConvertValues
var
  singleVecArr : TvectorArray;
  doubleveArr :  TvectorDArray; 
begin
  singleVecArr := somefunc;
  setlength(doubleVecArray, lenght(singlevecArr));
  for i := 0 to length(singlevecArr) -1 do
    doubleVecArray[i] := singleVecArr[i];
end;

Есть ли более эффективный способ выполнить такие преобразования?

Ответы [ 3 ]

1 голос
/ 01 февраля 2011

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

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

Наконец, если случайно этот код являетсяузкое место, вы должны подумать о том, чтобы вообще не конвертировать его.Я предполагаю, что вы используете стандартные операции с плавающей запятой Delphi, которые отображаются на 8087 FPU.Все такие операции с плавающей запятой происходят внутри стека с плавающей запятой 8087.Значения преобразуются при вводе с точностью до 64 или более обычно 80 бит.Я не думаю, что было бы медленнее загружать сингл, чем загружать двойной - на самом деле это может быть даже быстрее из-за производительности чтения из памяти.

1 голос
/ 01 февраля 2011

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

Например, следующее преобразовало бы один единственный вектор в один двойной вектор:

procedure SingleToDoubleVector (var S: TVector; var D: TVectorD);
// @S in EAX
// @D in EDX
asm
  movups    xmm0, [eax]     ;// Load S in xmm0
  movhlps   xmm1,  xmm0     ;// Copy High 2 singles of xmm0 into xmm1
  cvtps2pd  xmm2,  xmm0     ;// Convert Low two singles of xmm0 into doubles in xmm2
  cvtss2sd  xmm3,  xmm1     ;// Convert Lowes single in xmm1 into double in xmm1
  movupd   [edx],  xmm2     ;// Move two doubles in xmm2 into D (.X and .Y)
  movsd    [edx+16],xmm3    ;// Move one double from xmm3 into D.Z
end;

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

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

0 голосов
/ 01 февраля 2011

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

Кроме того, рассчитывается ли длина в каждом цикле? Возможно, поместите это в переменную, чтобы избежать вычисления.

...