![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Работа с памятью. ( Выравнивание )
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.
Встроеный ассемблер здесь, по-моему, не подойдет. Требуются эксперименты.
Возникнут осложнения, если существенно требуется передача параметров.