Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Снова выравнивание памяти :)


Страницы:   1 2

Riply ©   (2008-05-08 21:14:00) 

Здравствуйте !
Учитывая горький опыт предыдущей программистской жизни,
решила, что начинать новую надо с модуля, выравнивающего память :)
Вроде ничего сложного, но при ReallocMem у меня получается
двойное копирование: первый раз копирует память сама ReallocMem, а потом
уже я, если это необходимо.
Как можно избавиться от этого, или уменьшить "частоту" случаев, необходимо копирование ?
Только не советуйте переписать SysReallocMem из getmem.inc :)

Вот что у меня пока получается:
type
PMEM_STUFF = ^_MEM_STUFF;
 _MEM_STUFF = packed record
 {$IFDEF SH_MEM_128}
  _Stuff: array[0..7] of Byte;
  {$ENDIF}
  Stuff: Int64;
 end;

type
PMEM_HEADER = ^_MEM_HEADER;
 _MEM_HEADER = packed record
  _Shift: Word;
  _HeaderSize: Word;
  _RealPtr: Pointer;
 end;

type
PMEM_BLOCK = ^_MEM_BLOCK;
 _MEM_BLOCK = packed record
  Length: LongWord;
  MaxLength: LongWord;
  _Shift: Word;
  _HeaderSize: Word;
  _RealPtr: Pointer;
 end;

const
{$IFDEF SH_MEM_128}
__PRED                       = SizeOf(Int64) shl 1 - 1;
__SHIFT                      = - (SizeOf(Int64) shl 1);
{$ELSE}
__PRED                       = SizeOf(Int64) - 1;
__SHIFT                      = - SizeOf(Int64);
{$ENDIF}

__MEM_SIZE_INC               = SizeOf(_MEM_STUFF) + SizeOf(_MEM_BLOCK);

{$IFDEF SH_MEM_MNG}
var
__MemMgrEx: TMemoryManagerEx;
{$ENDIF}

function ROUND_UP_DEFINE(const Value: LongWord): LongWord; inline;
begin
Result := (Value + __PRED) and __SHIFT;
end;

function OFFSET_TO_DEFINE(const P: Pointer): LongWord; inline;
begin    
{$IFDEF SH_MEM_128}
Result := OFFSET_TO128(LongWord(P));
{$ELSE}
Result := OFFSET_TO64(LongWord(P));
{$ENDIF}
end;

function _LMem_GetRealPtr(const pBlock: PMEM_BLOCK; var P: Pointer): NTSTATUS; inline;
begin
P := pBlock._RealPtr;
if P = Pointer(LongWord(pBlock) - pBlock._Shift)
 then Result := STATUS_SUCCESS
 else Result := STATUS_INVALID_ADDRESS;
end;

procedure _LMem_SetMaxLength(const pBlock: PMEM_BLOCK; const MaximumLength: LongWord); inline;
begin
with pBlock^ do
 begin
  MaxLength := MaximumLength;
  if Length > MaxLength then Length := MaxLength;
 end;
end;

function _LMem_InitMemBlock(const pTmp: Pointer; const aMaxLength: LongWord; const HeaderSize: LongWord = 0): PMEM_BLOCK;
var
NewShift: LongWord;
begin
NewShift := OFFSET_TO_DEFINE(pTmp);
Result := PMEM_BLOCK(LongWord(pTmp) + NewShift);
with Result^ do
 begin
  Length := 0;
  MaxLength := aMaxLength;
  _Shift := NewShift;
  _HeaderSize := HeaderSize;
  _RealPtr := pTmp;
 end;
end;

function __Call_ReallocMem(const P: Pointer; const AlignedSize: LongWord): Pointer;
begin
{$IFDEF SH_MEM_MNG}
Result := __MemMgrEx.ReallocMem(P, AlignedSize);
{$ELSE}
Result := P;
ReallocMem(Result, AlignedSize);
{$ENDIF}
end;

function _Sh_ReallocMem(var P; const AlignedSize: LongWord): NTSTATUS;
var
pTmp: Pointer;
begin
pTmp := __Call_ReallocMem(Pointer(P), AlignedSize);
if pTmp <> nil then
 if pTmp <> Pointer(P) then
  begin
   Result := STATUS_SUCCESS;
   Pointer(P) := pTmp;
  end
 else Result := STATUS_SH_SUCCESS
else Result := STATUS_INSUFFICIENT_RESOURCES;
end;

function __LMem_ReallocMem(var P: Pointer; const AlignedSize: LongWord): NTSTATUS;
begin
Result := _Sh_ReallocMem(P, __MEM_SIZE_INC + AlignedSize);
end;

function _LMem_ReallocMemCopy(var pBlock: PMEM_BLOCK; const AlignedSize: LongWord): NTSTATUS;
var
pTmp: Pointer;
NewShift, OldShift: LongWord;
pOldBlock: PMEM_BLOCK;
begin
Result := _LMem_GetRealPtr(pBlock, pTmp);
if Result = STATUS_SUCCESS then
 begin
  OldShift := pBlock._Shift;
  Result := __LMem_ReallocMem(pTmp, AlignedSize + pBlock._HeaderSize);
  if Result = STATUS_SUCCESS then
   begin
    NewShift := OFFSET_TO_DEFINE(pTmp);
    pBlock := PMEM_BLOCK(LongWord(pTmp) + NewShift);
    if OldShift <> NewShift then // <-- Вот тут и копируем. Т.е. при изменении самого указателя и смещения
     begin
      pOldBlock := Pointer(LongWord(pTmp) + OldShift);
      with pOldBlock^ do
       if MaxLength < AlignedSize                        
        then Move(pOldBlock^, pBlock^, MaxLength + SizeOf(_MEM_BLOCK) + _HeaderSize)
        else Move(pOldBlock^, pBlock^, AlignedSize + SizeOf(_MEM_BLOCK) + _HeaderSize);
      pBlock._Shift := NewShift;
     end;
    pBlock._RealPtr := pTmp;
    _LMem_SetMaxLength(pBlock, AlignedSize);
   end
  else
   if Result = STATUS_SH_SUCCESS then _LMem_SetMaxLength(pBlock, AlignedSize);
 end;
end;

function _LMem_ReallocMemOnly(var pBlock: PMEM_BLOCK; const AlignedSize: LongWord): NTSTATUS;
var
pTmp: Pointer;
begin
Result := _LMem_GetRealPtr(pBlock, pTmp);
if Result = STATUS_SUCCESS then
 begin
  Result := __LMem_ReallocMem(pTmp, AlignedSize);
  if Result = STATUS_SUCCESS then pBlock := _LMem_InitMemBlock(pTmp, AlignedSize) else
   if Result = STATUS_SH_SUCCESS then _LMem_SetMaxLength(pBlock, AlignedSize);
 end;
end;

function LMem_ReallocMem_(var pBlock: PMEM_BLOCK; const AlignedSize: LongWord): NTSTATUS;
begin // May be copy Length only ?
if ((pBlock.MaxLength > 0) and (AlignedSize > 0)) or (pBlock._HeaderSize > 0)
 then Result := _LMem_ReallocMemCopy(pBlock, AlignedSize)
 else Result := _LMem_ReallocMemOnly(pBlock, AlignedSize);
end;


Riply   (2008-05-09 00:51:00) [21]

> [3] Германн ©   (09.05.08 00:36)
> Похоже на замену грибов, травкой :)

Это почему это ? :)
IMHO, лучше заранее подготовиться, чем потом перелопачивать кучу кода,
когда выясниться, что кто-то не желает работать с твоей структурой из-за ее "невыровненности" :)


Riply   (2008-05-09 00:48:00) [22]

> [2] guav © (09.05.08 00:19)
>> начинать новую надо
> А мож ну его ?

Эта... "Как прикажешь тебя понимать, Саид ?"  :)

> Как можно избавиться от этого,

> Думаю, ты можешь копировать один раз, заменив вызов ReallocMem на AllocMem + FreeMem,
> но тогда копирование будет в любом случае.

Рассматривала этот вариант: IMHO, для большинства случаев он "непродуктивен".
Опыты показали, что ReallocMem не так уж и часто перемещает память.
(Это сильно зависит от исходного и нового размеров и еще от фазы луны :)
А мне после нее заново перемещать потребуется, только если у поинтеров
оказались разные оффсеты до границы выравнивания.


> PS: "В стандарте С функция realloc пользуется дурной славой плохо спроектированной функции.
> Она делает одновременно слишком много дел: выделяет память, если ей передано значение NULL,
> освобождает её если передан нулевой размер, перераспределяет её на том же месте,
> если это возможно или перемещает её, если таковое перераспределение невозможно.

Это одна из причин почему я рассматриваю в __Call_ReallocMem
вариант использования MemoryManagerEx.ReallocMem
Если он конечно не череват всякими "непредсказуемостями" :)

> PPS:

Да Вы, оказывается, еще и искуситель :)


Германн   (2008-05-09 00:36:00) [23]


> Riply ©   (08.05.08 21:14)
>
> Здравствуйте !
> Учитывая горький опыт предыдущей программистской жизни,
> решила, что начинать новую надо с модуля, выравнивающего
> память :)

Похоже на замену грибов, травкой :)


guav   (2008-05-09 00:19:00) [24]

> [0] Riply ©   (08.05.08 21:14)


> начинать новую надо

А мож ну его ?


> Как можно избавиться от этого,

Думаю, ты можешь копировать один раз, заменив вызов ReallocMem на AllocMem + FreeMem, но тогда копирование будет в любом случае.

PS: "В стандарте С функция realloc пользуется дурной славой плохо спроектированной функции. Она делает одновременно слишком много дел: выделяет память, если ей передано значение NULL, освобождает её если передан нулевой размер, перераспределяет её на том же месте, если это возможно или перемещает её, если таковое перераспределение невозможно. Данная функция обычно рассматривается всеми как пример недальновидного, ошибочного проектирования"

PPS:

__declspec( align(1024) ) struct Whatever
{
 char a;
} w1;

int _tmain(int argc, _TCHAR* argv[])
{
 struct Whatever w2;
 void *p = _aligned_malloc(100, 1024);
 printf("Aligned global %p\n", &w1);
 printf("Aligned local %p\n", &w2);
 printf("Aligned heap %p\n", p);
 p = _aligned_realloc(p, 10000, 16384);
printf("Realigned heap %p\n", p);
 _aligned_free(p);
 return 0;
}
/* output is
Aligned global 00417400
Aligned local 0012F400
Aligned heap 00358400
Realigned heap 0035C000
*/


Loginov Dmitry   (2008-05-08 21:31:00) [25]

Бог моЙ! Надеюсь, это менее опасно, чем с NTFS :))


> начинать новую надо с модуля, выравнивающего память


а еще память можно освежать и укреплять :)


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо