Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2008.06.01;
Скачать: [xml.tar.bz2];

Вниз

Снова выравнивание памяти :)   Найти похожие ветки 

 
Riply ©   (2008-05-08 21:14) [0]

Здравствуйте !
Учитывая горький опыт предыдущей программистской жизни,
решила, что начинать новую надо с модуля, выравнивающего память :)
Вроде ничего сложного, но при 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;


 
Loginov Dmitry ©   (2008-05-08 21:31) [1]

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


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


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


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

> [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
*/


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


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

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


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

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

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

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

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

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


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

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

> PPS:

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


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

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

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


 
Германн ©   (2008-05-09 00:56) [6]


> Riply ©   (09.05.08 00:51) [5]

Поживём - увидим. :)


 
guav ©   (2008-05-09 01:14) [7]

> [4] Riply ©   (09.05.08 00:48)


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

Ну зачем писать ещё один мфт скан ?


 
antonn ©   (2008-05-09 01:29) [8]


> Riply ©   (08.05.08 21:14)

С возвращением! :)


 
Германн ©   (2008-05-09 02:09) [9]


> antonn ©   (09.05.08 01:29) [8]
>
>
> > Riply ©   (08.05.08 21:14)
>
> С возвращением! :)
>

Тут более подходит - С реинкарнацией! :)


 
sniknik ©   (2008-05-09 10:34) [10]

чем только люди не занимаются, лиш бы не работать...


 
Ins ©   (2008-05-09 11:35) [11]

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


 
Ins ©   (2008-05-09 11:45) [12]

Про работу менеджера памяти (того, что в более старых версиях, а не FastMM) можно почитать тута:
http://www.rsdn.ru/article/Delphi/memmanager.xml


 
Virgo_Style ©   (2008-05-09 20:49) [13]

antonn ©   (09.05.08 1:29) [8]
С возвращением! :)

Германн ©   (09.05.08 2:09) [9]
Тут более подходит - С реинкарнацией! :)


С клонированием, насколько я помню конец Чужих 3 - начало Чужих 4. Становится ясно, как именно погибли исходники.

:0)


 
Германн ©   (2008-05-10 00:54) [14]


> Virgo_Style ©   (09.05.08 20:49) [13]

Ещё раз напоминаю, что фамилия сержанта из Чужих пишется, да и произносится, иначе, чем сей ник :)


 
AlexDan ©   (2008-05-10 01:52) [15]

> Riply ©   (08.05.08 21:14)
Конференция "начинающим". Шок в студию..)!. Мне просто интересно Вы) кому программы пишете НАСА или (дальше просто не хватает фантазии..)
Ну ладно NTFS это для души,а что за монстра вы сейчас лепите и, самое интересное для кого?


 
Германн ©   (2008-05-10 02:00) [16]


> AlexDan ©   (10.05.08 01:52) [15]

Слишком много скобок. Riply © всё пишет для души, и никак иначе.


 
AlexDan ©   (2008-05-10 02:57) [17]

Да я тут просто написал маленькую прожку для выключения компа, так мне захотелось чтобы он потом вилку из разетки выдёргивал)), я думаю, что если Riply мне поможет, то у нас всё получиться..


 
AlexDan ©   (2008-05-10 03:08) [18]

> Германн © (10.05.08 02:00) [16]
> Riply © всё пишет для души, и никак иначе.
По моему, если писать только для души, то жить только ею, в смысле, душею, и прийдётся.. Хотя, ваш покорный слуга, наверное, так и делает..
А пока живёт он исключительно частным предпринимательством в строительном бизнесе.


 
logic   (2008-05-10 11:25) [19]


> AlexDan ©   (10.05.08 03:08) [18]

это реклама


 
Leonid Troyanovsky ©   (2008-05-10 11:47) [20]


> Riply ©   (08.05.08 21:14)  

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

Не очень понятно, зачем, собс-но.
Было ж уже похожее обсуждение.

Для того, чтобы получить выровненный нужным образом блок
достаточно VirtualAlloc.
Если требуется использовать дельфийский ММ, то проще распределить
блок с запасом (он выравнивает лишь по 4 байтам), а затем передвинуть
указатель на нужную границу.

--
Regards, LVT.


 
Anatoly Podgoretsky ©   (2008-05-10 12:38) [21]

> AlexDan  (10.05.2008 02:57:17)  [17]

Ты сватаешься или подкатываешься?


 
AlexDan ©   (2008-05-10 14:00) [22]

Восновном я только хотел узнать
> Ну ладно NTFS это для души,а что за монстра вы сейчас лепите
> и, самое интересное для кого?


 
AlexDan ©   (2008-05-10 14:01) [23]

В основном (опечатка)


 
Riply ©   (2008-05-10 15:23) [24]

> [20] Leonid Troyanovsky © (10.05.08 11:47)
> Не очень понятно, зачем, собс-но.
> Для того, чтобы получить выровненный нужным образом блок
> достаточно VirtualAlloc.

Попробую объяснить, почему мне это приспичило :)
VirtualAlloc - довольно медленная функция:
Во всяком случае, у меня получается так:
цикл с миллионом итераций для VirtualAlloc, VirtualFree длится 11266 тиков.
Его аналог для GetMem, FreeMem - 16 тиков.
Использование собственнолапного выравнивания (со всеми вкусными прибамбасами) - 47 тиков.

Для сравнения затрат, приведу такую цифру (из того с чем мне пишлось столкнуться):
на NT-сканирование индексированного диска с почти миллионом объектов уходит 8903 тика.
Если учесть, что для каждого объекта надо как минимум один раз выделить/освободить память,
(как реализовать работу с одним буфером для пока не придумала :)
то становиться ясно, что использование VirtualAlloc - непозволительная роскошь.
Затраты на нее превысят затраты на пробежку по всему диску :)

Сейчас, я собираюсь посмотреть в сторону рееста (еще точно не решила).
Думаю, что вполне логично предположить, что при работе с ним нам встретяться
и "привередливые" функции (требующие 64-ого выравнивания) и что расходы
на "рабочие" операции будут гораздо заметнее, чем при работе с FS.
Исходя из всего вышесказанного и было принято решение "подстелить соломки" :)


 
Leonid Troyanovsky ©   (2008-05-10 17:30) [25]


> Riply ©   (10.05.08 15:23) [24]

> цикл с миллионом итераций для VirtualAlloc, VirtualFree
> длится 11266 тиков.
> Его аналог для GetMem, FreeMem - 16 тиков.

Тут нет никакой мистики, видимо, пара Get/FreeMem
топчется в одном и том же аллоцированном блоке.

А миллион VirtualAlloc/Free - перебор, лучше одноразово.

> (как реализовать работу с одним буфером для пока не придумала
> :)

Может на этом и сосредоточиться.
Ну, не один, так хотя бы пул буферов.

А что не устраивает в выделении блока с запасом?

--
Regards, LVT.



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2008.06.01;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.53 MB
Время: 0.046 c
2-1210226756
operator
2008-05-08 10:05
2008.06.01
Экспорт delphi кода с сохранением форматирования в word/html


2-1210237817
Efimov
2008-05-08 13:10
2008.06.01
Как построить диаграмму по данным из БД?


2-1210344790
michail
2008-05-09 18:53
2008.06.01
Сохранение изображения в двоичном файле


2-1210153969
Alex7
2008-05-07 13:52
2008.06.01
Флаговый параметр для CommandText ADODataSet к MS SQL


6-1187942038
leonidus
2007-08-24 11:53
2008.06.01
Indy и обработка ошибок при работе с HTTP-прокси





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский