![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Warning, которого быть не должно.
Riply © (2008-06-10 21:48:00)Здравствуйте !
Вот скелет некой функции:
function Test: WideString;
var
Tmp : UNICODE_STRING;
begin
Result := '';
RtlInitUnicodeString(@Tmp, nil);
if NT_SUCCESS(............) then
try
............
if NT_SUCCESS(............) then
begin
// ............ Много кода, но Result в нем нигде не используется
SetLength(Result, Tmp.Length shr SHR_WCHAR);
if Tmp.Length > 0 then Move(Tmp.Buffer^, Pointer(Result)^, Tmp.Length);
end;
finally
RtlFreeUnicodeString(@Tmp);
end;
end;
Почему Delphi настырно выдает следующее предупреждение:
"[Pascal Warning] Alx_Unicode.pas(746): W1035 Return value of function 'Test' might be undefined" ?
Что такое может быть "не так" в коде, где точки ?
(Если его закоментировать (но только весь сразу, а не кусочками), то варнинг исчезает)
Riply (2008-06-13 10:29:00) [1]> [53] Игорь Шевченко © (13.06.08 01:35)
Спасибо.
Игорь Шевченко (2008-06-13 01:35:00) [2]Riply © (13.06.08 01:11) [52]
> Чем я рискую, подменивая способ выделения памяти для UNICODE_STRING
> в Nt-функциях ?
> Может это у них страховка для случая многопоточности ?
Ничем. Память для буфера в Unicode_string - это самая обыкновенная память пользовательского режима и как ее выделять - это дело сугубо личное. лучше чем выделение через Heap-функции еще ничего не придумали, кроме lookaside-списков, но они для строк категорически не подходят.
> Я помню как меня удивил тот факт, что Nt-функции с UNICODE_STRING
> работают через Heap.
Собственно, практически все выделение памяти работает через Heap-функции, а они, в свою очередь работают через VirtualAlloc/VirtualFree, кроме отображения файлов на память, так что удивляться нечему.
Кстати, совет, если уж о скорости заговорили - если у тебя есть константы, которые надо передавать через UNICODE_STRING, не вызывай RtlInitUnicodeString и тем более, не выделяй под константы память и не копируй туда значения. Лучше использовать для этих целей константные строки типа
const
MyUnicodeString: UNICODE_STRING = (Length:длина; MaximumLength:длина; Biffer:'строка');
Riply (2008-06-13 01:11:00) [3]> [51] Игорь Шевченко © (13.06.08 00:40)
> И работает быстро, зараза!
:)
Я помню как меня удивил тот факт, что Nt-функции с UNICODE_STRING работают через Heap.
А мы же их (пусть и косвенно) но вызываем "мульены" раз :)
Попробовала найти ответ на вопрос "а зачем", но кроме как у Рихтера ничего не нашла.
А он тоже выражает удивление по этому поводу.
Кстати, этот вопрос меня интересует до сих пор.
Чем я рискую, подменивая способ выделения памяти для UNICODE_STRING в Nt-функциях ?
Может это у них страховка для случая многопоточности ?
Игорь Шевченко (2008-06-13 00:40:00) [4]Riply © (13.06.08 00:03) [50]
> Скомпилированный под Delphi 7 и BDS 2006 он дает наглядное
>
> представление о, изменениях в работе BMM.
собственно, начиная с D2005, если я не ошибаюсь, в delphi используется FastMM вместо старого кода. Поэтому отличия они, в принципе, очевидны.
Мне больше другое интересно, а как же система работает ? Она ж тоже память выделяет под свои нужды, однако без всяких дополнительных Memory Manager'ов живет, пользуя HeapAlloc, HeapFree (они же RtlAllocateHeap, RtlFreeHeap).
И работает быстро, зараза!
Riply (2008-06-13 00:03:00) [5]Раз уж заговорили об этом, хочу поделиться.
Есть у меня код (автора, к сожалению, не помню, но не я :).
Скомпилированный под Delphi 7 и BDS 2006 он дает наглядное
представление о, изменениях в работе BMM.
Если с этим кодом чуть поиграть, то можно его использовать для
получения и других "сравнительных" данных.
Не знаю, может кому интересно будет. Ну а на "нет" и суда нет :)
unit BMM_SpeedMultiTread;
interface
uses
Windows,
SysUtils,
Classes;
procedure DiffGetMemSpeedInMultiThread(List: TStrings);
implementation
const
BorlandMM = 'borlndmm.dll';
function BMM_GetMem(Size: Integer): Pointer; external BorlandMM name '@Borlndmm@SysGetMem$qqri';
function BMM_FreeMem(P: Pointer): Integer; external BorlandMM name '@Borlndmm@SysFreeMem$qqrpv';
function _IsDebuggerPresent:boolean;external 'kernel32.dll' name 'IsDebuggerPresent';
//Хак - получение указателя на borlandmm.IsMultiThread
function GetBMMIsMultiThreadPtr:pBoolean;
var
pbase,p,pp:pChar;
pData,v:integer;
begin
Result:=Nil;
integer(pbase):=GetModuleHandle('borlndmm.dll');
if pbase = Nil then Exit;
p:=pbase+pInteger(pbase+$3C)^; //указатель на PE-signature
inc(p,24); //указатель на PE.OptionalHeader
//начало секции данных - чтобы не возиться c анализом секций берем BaseOfData
//(поле не обязательное для заполнения, но в borlndmm оно установлено)
if pWord(p)^ and $100 = $100 then //если PE32
pData:=integer(pbase)+pInteger(p+24)^ //BaseOfData
else
begin //BaseOfCode SizeOfCode
pData:=integer(pbase)+pInteger(p+20)^+pInteger(p+4)^;
pData:=(pData+4093) and -4096;
end;
p:=pbase+pInteger(p+16)^; //AddressOfEntryPoint
pp:=p+48;
repeat
//ищем MOV byte ptr [XXXX],1 = $05C6,$XXXX,$01
if (pWord(p)^ = $05C6) and (pByte(p+6)^ = 1) then
begin
v:=pInteger(p+2)^;
if (v >= pData) and (v < pData+$100) then
begin
Result:=pointer(v);
Exit;
end;
end;
inc(p);
until p >= pp;
end;
procedure DiffGetMemSpeedInMultiThread(List: TStrings);
const
memsz = 8;
repcnt = 1;//32;
itemcnt = 4*2;
fmt:array[1..itemcnt] of string = (
'GetMem+FreeMem = %4d <- IsMultiThread:=false',
'GetMem+FreeMem = %4d <- IsMultiThread:=true',
'borlandmm.dll = %4d <- as is (dll.IsMultiThread:=true)',
'borlandmm.dll = %4d <- set on fly dll.IsMultiThread:=false',
'HeapAlloc\Free = %4d <- dwFlags = 0',
'HeapAlloc\Free = %4d <- dwFlags = NO_SERIALIZE',
'GlobalAlloc\Free = %4d <- GMEM_FIXED',
'GlobalAlloc\Free = %4d <- GMEM_MOVEABLE');
var
t:array[0..itemcnt] of integer;
p:array[1..3] of pointer;
i,j,k,ph,over,heapflags:integer;
BMMIsMultiThread:pBoolean;
function StartRDTSC:integer;
asm
push ebx
push edi
xor eax,eax
cpuid //db $0F,$A2
rdtsc //db $0F,$31
mov edi,eax
xor eax,eax
cpuid //db $0F,$A2
mov eax,edi
pop edi
pop ebx
end;///
function StopRDTSC:integer;
asm
rdtsc //db $0F,$31
end;///
begin
over:=0; //замеряем оверхед на cpuid
for j:=1 to 5 do
begin
t[0]:=StartRDTSC;
t[0]:=StopRDTSC-t[0]-over;
end;
over:=t[0];
IsMultiThread:=false;
for i:=1 to 3 do GetMem(p[i],memsz);
k:=1;
repeat
for j:=1 to 5 do
begin
t[0]:=StartRDTSC;
for i:=1 to repcnt do
begin
FreeMem(p[2]);
GetMem(p[2],memsz);
end;
t[k]:=(StopRDTSC-t[0]-over) div repcnt;
end;
IsMultiThread:=true;
inc(k)
until k > 2;
IsMultiThread:=false;
for i:=1 to 3 do FreeMem(p[i]);
for i:=1 to 3 do p[i]:=BMM_GetMem(memsz);
BMMIsMultiThread:=GetBMMIsMultiThreadPtr;
repeat
for j:=1 to 5 do
begin
t[0]:=StartRDTSC;
for i:=1 to repcnt do
begin
BMM_FreeMem(p[2]);
p[2]:=BMM_GetMem(memsz);
end;
t[k]:=(StopRDTSC-t[0]-over) div repcnt;
end;
if BMMIsMultiThread <> Nil then BMMIsMultiThread^:=false;
inc(k);
until k > 4;
for i:=1 to 3 do BMM_FreeMem(p[i]);
if BMMIsMultiThread <> Nil then BMMIsMultiThread^:=true;
ph:=GetProcessHeap;
for i:=1 to 3 do p[i]:=HeapAlloc(ph,0,memsz);
heapflags:=0;
repeat
for j:=1 to 5 do
begin
t[0]:=StartRDTSC;
for i:=1 to repcnt do
begin
HeapFree(ph,heapflags,p[2]);
p[2]:=HeapAlloc(ph,heapflags,memsz);
end;
t[k]:=(StopRDTSC-t[0]-over) div repcnt;
end;
heapflags:=1; //=HEAP_NO_SERIALIZE;
inc(k);
until k > 6;
for i:=1 to 3 do HeapFree(ph,0,p[i]);
for i:=1 to 3 do p[i]:=pointer(GlobalAlloc(GMEM_FIXED,memsz));
for j:=1 to 5 do
begin
t[0]:=StartRDTSC;
for i:=1 to repcnt do
begin
GlobalFree(integer(p[2]));
p[2]:=pointer(GlobalAlloc(GMEM_FIXED,memsz));
end;
t[k]:=(StopRDTSC-t[0]-over) div repcnt;
end;
inc(k);
for i:=1 to 3 do GlobalFree(integer(p[i]));
for i:=1 to 3 do p[i]:=pointer(GlobalAlloc(GMEM_MOVEABLE,memsz));
for j:=1 to 5 do
begin
t[0]:=StartRDTSC;
for i:=1 to repcnt do
begin
GlobalFree(integer(p[2]));
p[2]:=pointer(GlobalAlloc(GMEM_MOVEABLE,memsz));
end;
t[k]:=(StopRDTSC-t[0]-over) div repcnt;
end;
inc(k);
for i:=1 to 3 do GlobalFree(integer(p[i]));
List.Add('');
for i:=1 to k-1 do
List.Add(Format(fmt[i],[t[i]]));
if _IsDebuggerPresent then
List.Add('ВНИМАНИЕ: результаты HeapAlloc\Free сильно завышены'#13#10+
'из-за запуска программы под отладчиком');
end;
end.
Riply (2008-06-12 23:19:00) [6]> [48] Игорь Шевченко © (12.06.08 23:04)
> а эта...вопрос такой автору - а зачем такое количество вложенных друг в друга inline-функций ?
> Тест компилятора или иные соображения ?
Здесь все вместе.
Модуль в стадии разработки и тестирования.
На этом этапе множественность вложений позволяла почти безболезненно
менять алгоритм работы на любом "уровне" и наблюдать
за его поведением при различных условиях (в т. ч. и быстродействием).
Позже, когда было выяснено влияние inline и выбран окончательный алгоритм,
планировалось "слияние" функций и приведение модуля в рабочий, пригодный для использования вид.
Игорь Шевченко (2008-06-12 23:04:00) [7]а эта...вопрос такой автору - а зачем такое количество вложенных друг в друга inline-функций ? Тест компилятора или иные соображения ?
Игорь Шевченко (2008-06-12 22:26:00) [8]Riply © (12.06.08 21:10) [44]
Это я несколько ввел в заблуждение, виноват - я переместил тело функции, убрав ее прототип из интерфейсной части Sh_Unicode.
В интерфейсной части она объявлена как inline, а в implementation без него, что вполне допустимо. Так что перенеся функцию я убрал inline.
Riply (2008-06-12 21:33:00) [9]> [45] Тын-Дын © (12.06.08 21:29)
> У меня в оригинале:
У вас и Игорем "оригиналы" могут различаться. (Хоть убейте - не помню)
Я ведь, отправив Игорю код, не сидела сложа руки в ожидании результата :)
Могла и напартачить с исходниками :)
Тын-Дын (2008-06-12 21:29:00) [10]
> в проекте она не inline
У меня в оригинале:
function Us_HoldInteger_(const pUs: PUNICODE_STRING; const Value, Base, DisplChars, SourceHoldBytes: LongWord): NTSTATUS;
implementation
function Us_HoldInteger_(const pUs: PUNICODE_STRING; const Value, Base, DisplChars, SourceHoldBytes: LongWord): NTSTATUS; {$IFNDEF SH_MEM_US_DEBUG}inline;{$ENDIF}
var
MemBlock: MEM_BLOCK;
begin
{$IFDEF SH_MEM_US_HEAP}
Result := MemBlock.__GetMemory(MAX_INT_LENGTH);
if Result = STATUS_SUCCESS then
try
Result := BlockMem_AppendInteger(@MemBlock, Value, Base, DisplChars);
if NT_SUCCESS(Result) then Result := Us_HoldLen_(pUs, MemBlock.pBuffer, MemBlock.Length, SourceHoldBytes);
finally
MemBlock.__FreeMem;
end;
{$ELSE}
MemBlock.InitMemBlock(SourceHoldBytes, MaximumLength, Buffer);
Result := BlockMem_AppendInteger(@MemBlock, Value, Base, DisplChars);
Us_InitFromMemBlock_(pUs, @MemBlock);
{$ENDIF}
end;
Riply (2008-06-12 21:10:00) [11]> [43] Игорь Шевченко © (12.06.08 21:04)
> в проекте она не inline
Все. Я уже совсем запуталась. Не могу вспомнить в каком виде высылала проект :(
Ну да ладно. Так как решаем поступить: плюнуть (до лучших времен :) или еще помучаться ?
Игорь Шевченко (2008-06-12 21:04:00) [12]
> Уходит, если функция не inline
в проекте она не inline
Тын-Дын (2008-06-12 20:13:00) [13]Я бы всё-таки убрал inline в Us_HoldInteger_, избавившись от предупреждения-)
Riply (2008-06-12 19:36:00) [14]> [40] Игорь Шевченко © (12.06.08 18:45)
> а ты попробуй функцию перенести. define все те же самые, inc-файл тот же включается,
> функция сама не inline, посмотришь, уйдет warning или нет.
Уходит, если функция не inline
> Тын-Дын ©
> {$DEFINE SH_MEM_MNG}
> {.$DEFINE SH_MEM_DEBUG}
> {.$DEFINE SH_MEM_US_DEBUG}
> {$DEFINE SH_MEM_US_HEAP}
> program Warning;
> {$APPTYPE CONSOLE}
А разве такое "использование" директив не опасно ?
Я имею ввиду то, не получится ли что у разных юнитов разные define`ы ?
Вопрос к участникам:
Т.е. решаем пока плюнуть на этот Warning и Us_HoldInteger_ делаем не inline ?
А варнинг пусть живет как хочет :)
Игорь Шевченко (2008-06-12 18:45:00) [15]
> Вдруг и здесь что-то подобное ?
а ты попробуй функцию перенести. define все те же самые, inc-файл тот же включается, функция сама не inline, посмотришь, уйдет warning или нет.
Тын-Дын (2008-06-12 18:30:00) [16]
> Надо компилировать с такими дериктивами:
С такими и компилировал - нет предупреждения после исправления..
Riply (2008-06-12 18:26:00) [17]> [34] Тын-Дын © (12.06.08 18:16)
> То же самое - у меня при компиляции нет предупреждения.
Надо компилировать с такими дериктивами:
{$DEFINE SH_MEM_MNG}
{.$DEFINE SH_MEM_DEBUG}
{.$DEFINE SH_MEM_US_DEBUG}
{$DEFINE SH_MEM_US_HEAP}
тогда будет.
> [36] Игорь Шевченко © (12.06.08 18:19)
> Мой хороший совет - не париться.
Наверное Вы правы, но я хорошо запомнила историю, когда inline функция
"меняла" входной параметр - константу.
Вдруг и здесь что-то подобное ?
Тын-Дын (2008-06-12 18:26:00) [18]
> Кстати, Warning исчезает, если функцию Us_HoldInteger_ перенести
> без всяких изменений из модуля Sh_Unicode в тело проекта
> сразу перед TestExtract.
Не потому ли, что Rеsult присваивается непосредственно в этой функции безусловно?
Тын-Дын (2008-06-12 18:19:00) [19]Сейчас удалю всё, кроме исходных текстов, ещё раз перекомпилирую...
Игорь Шевченко (2008-06-12 18:19:00) [20]Кстати, Warning исчезает, если функцию Us_HoldInteger_ перенести без всяких изменений из модуля Sh_Unicode в тело проекта сразу перед TestExtract.
Мой хороший совет - не париться.