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

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

Работа с памятью. ( Выравнивание )


Страницы:   1 2

Riply ©   (2008-03-20 21:50:00) 

Здравствуйте !
Допустим у нас есть очень привиредливая процедура:

procedure Fastidious(pAligned: Pointer);

Вот подавай ей на входе pAligned выровненный по границе SizeOf(Int64)
иначе она и работать откажется.
И пытаемся мы ее вызвать тремя способами:

procedure TestCallFastidious(pNotAligned: Pointer);
var
//......
MyRecord: TMySuperPuperRecord;
pTmp: Pointer;
begin
//.......  1-й вызов
Fastidious(@MyRecord);
//.......  2-й вызов
pTmp := GetMemory(MemSize);
Fastidious(pTmp);
//.......  3-й вызов
Fastidious(pNotAligned);
end;


Как лучше выкрутиться ?
Для 1-ого и 3-го приходит в голову только
Заводить доп. переменную Pointer и мучаться с перевыделением и копированием.
Со вторым вызовом тоже не понятно.
Мне не удалось получить pTmp не выровненный по 8-байтной границе
и не удалось нигде найти утверждения, что он будет выровнен.
Как с ним обстоят дела ?

P.S.
Пользоваться чем-то вроде VirtualAlloc не хотелось бы.


Leonid Troyanovsky   (2008-03-22 15:06:00) [1]


> Riply ©   (21.03.08 23:45) [39]

> но меня уже "зацепило"  :)

Все же не очень понятно, чем не угодила VirtualAlloc.

А по поводу дельфийского ММ хелп моей TD обещал лишь

Memory manager blocks are always rounded upward to a 4-byte boundary, and
always include a 4-byte header in which the size of the block and other status
bits are stored. This means that memory manager blocks are always double-
word-aligned, which guarantees optimal CPU performance when addressing

Т.е., если уж так хочется 8 байт, то проси Size+8 байт, и в случае если полученный адрес не кратен 8 - сдвинь указатель на 4.
Ну, и {$A8}, IMHO, здесь не повредит.

Хотя, это проблемы не Fastidious, которой, как уже говорилось,
достаточно отлупить инвалидный адрес, а того, кто ее вызывает.

--
Regards, LVT.


Riply   (2008-03-21 23:45:00) [2]

> [38] palva ©   (21.03.08 22:59)
> Язык си я зря предложил. Решить проблему он не поможет.

Меня тут мучает другое.
Учитывая [36] Sapersky и [37] Sha © , подумала:
А может под BDS 2006 будет работать [1] Игорь Шевченко © ?
Опять таки, четких утверждений мне найти не удалось,
но не удалось, также, и получить "невыровненную" YouParameterData: TFoo;
если ее размер превышает SizeOf(Int64).
Конечно, можно плюнуть на это дело, и использовать вариант типа [31] han_malign,
но меня уже "зацепило"  :)


palva   (2008-03-21 22:59:00) [3]

Язык си я зря предложил. Решить проблему он не поможет.


Sha   (2008-03-21 14:31:00) [4]

> Riply ©   (21.03.08 13:28) [35]

Sapersky   (21.03.08 13:57) [36]  уже  ответил :)

для стандартного менеджера памяти ранних версий Delphi
см. также использование константы cAlign в в Source\RTL\Sys\getmem.inc

нечто похожее есть и в FastMM, который, как и любой менеджер памяти,
обязан быть совместимым со стандартным.
Т.е. ранее написанные программы должны сохранять работособность с любымм MM,
и, значит, любая выделяемая память обязана быть выровнена по крайней мере на 4.


Sapersky   (2008-03-21 13:57:00) [5]

Мне не удалось получить pTmp не выровненный по 8-байтной границе

Зависит от версии Delphi, точнее, менеджера памяти. FastMM в BDS2006 по умолчанию выравнивает на 8:
http://dn.codegear.com/article/33416
Стандартный менеджер более ранних Delphi - на 4.

По поводу выравнивания переменных была информация здесь:
http://dennishomepage.gugs-cats.dk/CodingForSpeedInDelphi.doc


Riply   (2008-03-21 13:28:00) [6]

> [33] Sha ©   (21.03.08 10:46)
> pMyRecord:=pointer((integer(pTmp)+4) and -8);

Проглядела: например при integer(pTmp) = 1, получаем указатель не на нашу память :)
Вроде так получается:
pMyRecord:= pointer((DWord(pTmp) + 7) and -8);


Riply   (2008-03-21 13:01:00) [7]

> [31] han_malign ©   (21.03.08 10:29)
> - с небуферизированным чтением файла у меня такое прокатывало...

Ну вот и со "статическим" объявлением разобрались. :)

> [33] Sha ©   (21.03.08 10:46)
> pointer((integer(pTmp)+4) and -8);

Элегантно, ничего не скажешь.
А я то..., всякие условия "если это по модулю, то..." проверяю :)

Спасибо всем большое !


Sha   (2008-03-21 10:46:00) [8]

pTmp := GetMemory(PMyRecordSize+4);
pMyRecord:=pointer((integer(pTmp)+4) and -8);
Fastidious(pMyRecord);


по идее, должно работать для любого Delphi MM


han_malign   (2008-03-21 10:37:00) [9]

PMyRec( @_buf)- собаку забыл.

лишний байт в _buf, но мы люди не жадные :)...

для 64-бит(если когда появится) - если выравнивание на степень 2-ки - LongWord всегда прокатит, а mod сAlignможно заменить на and (cAlign - 1)(cAlign - есесьно не 0)...


han_malign   (2008-03-21 10:29:00) [10]


> > [24] palva ©   (21.03.08 00:07)
>
> Ага, и после этого "не дышать" на код memalign дабы не изменить
> количество и порядок  данных в стеке.

угу, а также на $D+/- и $W+/-...

var
    _buf: array[0..sizeof(TMyRec)+cMyAlign];
    pbuf: PMyRec;
    offs: LongWord;
begin
    pbuf:= PMyRec(_buf) ;
    offs:= LongWord(pbuf) mod cMyAlign;//для 32-бит, если появится 64-битный Delphi - int64 и воможно IFDEF
    if( offs > 0)then inc(PChar(pbuf), cMyAlign - offs);

- с небуферизированным чтением файла у меня такое прокатывало...


Германн   (2008-03-21 01:46:00) [11]


> Riply ©   (21.03.08 01:29) [29]
>
> > [28] palva ©   (21.03.08 01:01)
> > Переходите на си (Borland 5.5)
>
> Так. Все сговорились :) В один голос предлагают переходить
> на С.
> Знаю, что надо его осваивать. Да вот все духу не хватает
> :(
>

Не, ну освоить СИ в основах не так сложно, как кажется. Скажу больше. Это гораздо проще, чем то, что ты изучаешь своим методом ННТ. Токмо вот возникает другой вопрос после прочтения:

> Допустим у нас есть очень привиредливая процедура:
>
> procedure Fastidious(pAligned: Pointer);
>
> Вот подавай ей на входе pAligned выровненный по границе
> SizeOf(Int64)
> иначе она и работать откажется.

А вдруг после освоения СИ ты приведешь пример другой "привиредливой" функции, но уже на СИ? Что тогда?


Riply   (2008-03-21 01:29:00) [12]

> [28] palva ©   (21.03.08 01:01)
> Переходите на си (Borland 5.5)

Так. Все сговорились :) В один голос предлагают переходить на С.
Знаю, что надо его осваивать. Да вот все духу не хватает :(


palva   (2008-03-21 01:01:00) [13]

Переходите на си (Borland 5.5)

#pragma pack(4)
#include
void main() {
 struct {
   int a;
   __int64 d;
   int n;
 } s;
 printf("%d %d\n", &s.d, &s.n);  // 1245056 1245064
}


Riply   (2008-03-21 00:46:00) [14]

>  [25] guav ©   (21.03.08 00:12)
> Не знаю как Riply, но мне этот цирк не нравится

Riply тоже не любит цирк :)

>  [26] palva ©   (21.03.08 00:21)
> То есть вернемся к [2]

Уже пишется маленькая структура, которая будет этим заниматься :)


palva   (2008-03-21 00:21:00) [15]


> Не знаю как Riply, но мне этот цирк не нравится,

Мне тоже

> если нет средства выравнивания на стеке, значит надо выделять
> динамически.

То есть вернемся к [2]


guav   (2008-03-21 00:12:00) [16]

> [24] palva ©   (21.03.08 00:07)

Ага, и после этого "не дышать" на код memalign дабы не изменить количество и порядок  данных в стеке.
Не знаю как Riply, но мне этот цирк не нравится, имхо, если нет средства выравнивания на стеке, значит надо выделять динамически.


palva   (2008-03-21 00:07:00) [17]

Вот такой набросок

{$APPTYPE CONSOLE}

procedure memalign; // Это процедура, в которой выделяются данные
var
YouParameterData: Int64;
begin
 WriteLn(Integer(@YouParameterData));
 // Fastidious(@YouParameterData)
end;

procedure mediator;
begin
 memalign;
end;

procedure caller;
var itest: Integer;
begin
 if Integer(@itest) and 7 = 0 then
   mediator   // Эти две строки возможно
 else
   memalign;  // надо будет поменять местами при настройке
end;

begin
 caller;
end.


guav   (2008-03-20 23:54:00) [18]

> [20] tesseract ©   (20.03.08 23:31)
> навряд-ли в регистры - он их 32-х считает (Delphi) а int64,
> как факт, ещё с первых пней идёт.

Может EDX:EAX, как используется для результата функции, я же написал про пару регистров. В любом случае, лучше делать меньше подобных предположений о коде сгенерированом компилятором.


palva   (2008-03-20 23:42:00) [19]

Вообще-то без ассемблера можно обойтись. Только нужны подробности задачи.


palva   (2008-03-20 23:35:00) [20]

Процедура на ассемблере (без параметров) должна проверить текущий адрес стека и в том случае, если он делится/не делится на 8, увеличить стек на 4 после чего сразу же вызвать ту процедуру в которой выделяется память. После возврата из процедуры стек нужно вернуть назад на 4.
Встроеный ассемблер здесь, по-моему, не подойдет. Требуются эксперименты.
Возникнут осложнения, если существенно требуется передача параметров.


Страницы:   1 2

Наверх

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