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

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

Порядок объявления переменных.


Страницы:   1 2

learner ©   (2006-07-27 15:21:00) 

Параметром в процедуру передовала указатель на следующую структуру:
SYSTEM_PROCESSES_ADD = packed record
   NextEntryDelta : ULONG;
   ThreadCount : ULONG;
   CreateTime : LARGE_INTEGER;
   UserTime : LARGE_INTEGER;
   KernelTime : LARGE_INTEGER;
   ProcessName : string;
   FullPath : string;
   UserName : string;
   BasePriority : KPRIORITY;
   ProcessId : ULONG;
   InheritedFromProcessId : ULONG;
   HandleCount : ULONG;
   VmCounters : VM_COUNTERS;
   PrivatePageCount : ULONG;
   IoCounters: IO_COUNTERS;
   Threads: array [0..0] of SYSTEM_THREADS;  
 end;

После изменения порядка объявления переменных:
SYSTEM_PROCESSES_ADD = packed record
   NextEntryDelta : ULONG;
   ThreadCount : ULONG;
   CreateTime : LARGE_INTEGER;
   UserTime : LARGE_INTEGER;
   KernelTime : LARGE_INTEGER;
   BasePriority : KPRIORITY;
   ProcessId : ULONG;
   InheritedFromProcessId : ULONG;
   HandleCount : ULONG;
   VmCounters : VM_COUNTERS;
   PrivatePageCount : ULONG;
   IoCounters: IO_COUNTERS;
   Threads: array [0..0] of SYSTEM_THREADS;
   ProcessName : string;<--Перемещено
   FullPath : string;<--Перемещено
   UserName : string;<--Перемещено  
 end;

скорость выполнения процедуры упала в пять раз !
Перепроверила раз сто. Вывод один:
От порядка объявления переменных зависит скорость.
Возникают два вопроса:
Почему это происходит и как в данной конкретной
стуктуре оптимальнее всего разместить переменные ?
Не перебирать же все возможные перестановки :))


learner   (2006-07-27 18:37:00) [1]

Сорри надо читать : "предыдущего"


learner   (2006-07-27 18:34:00) [2]

>А где же начальные "пять раз"?
Тестировала - тестировала и , вдруг, скорость упала в пять раз.
Вообще - то я прогоняла, чтобы посмотреть на утечку памяти, но так получилось. Стала выяснять в чем дело, вернулась по "хистору"
к предидущим вариантам. Поняла, что дело в расположении переменных.
А 8% прироста, это от исходной скорости.
>А что за смысл задачи, что такие требования к скорости предъявляются, если >не секрет ?
Не секрет.
На заре мною была написана программа. Она при запуске мне выводила списки
прцессов, сервисов, драйверов и DLL - ек появившихся в системе с момента ее предидущего запуска или не знакомых ей. А также новые вхождения
в реестре ( которые я знаю ) в плане автозапуска и подгружаемых библиотек.
Очень часто она мне помогала и я к ней привыкла. Но она совсем по-дилетански написана, и на сканирование всего у нее уходило 45-50 сек.
Вот и решила переписать.  
А ZwQuerySystemInformation дает очень много полезной информации.
Вот и стала изучать труды Игоря Шевченко :))


Игорь Шевченко   (2006-07-27 18:01:00) [3]


> Разместила преременные как все мне посоветовали и получила
> прирост
> скорости на 8%. Мелочь, а так приятно


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


Германн   (2006-07-27 17:33:00) [4]


> Разместила преременные как все мне посоветовали и получила
> прирост
> скорости на 8%. Мелочь, а так приятно :))

А где же начальные "пять раз"?
:-)


learner   (2006-07-27 17:28:00) [5]

>[23] Игорь Шевченко ©   (27.07.06 17:03)
:))
Разместила преременные как все мне посоветовали и получила прирост
скорости на 8%. Мелочь, а так приятно :))


Игорь Шевченко   (2006-07-27 17:03:00) [6]

learner ©   (27.07.06 16:54) [21]


> Мне непонятно только одно. Почему Вы так определяете размер
> буфера ?


Так список процессов от вызова к вызову может меняться :) Поэтому ReturnLength может не сработать при следующем вызове.


Ketmar   (2006-07-27 17:02:00) [7]

ReallocMem в стандартном MM страдает неэффективностью (если верить статьям на rsdn %-).


learner   (2006-07-27 16:54:00) [8]

>[19] Игорь Шевченко ©   (27.07.06 16:41)
Игорь, спасибо большое.
Именно этот модуль я, сейчас, и изучаю :))
Мне непонятно только одно. Почему Вы так определяете размер буфера ?

rc := NtQuerySystemInformation(InfoClass, @SystemSessionInformation,
  SizeOf(SystemSessionInformation), @ReturnLength);
while rc = STATUS_INFO_LENGTH_MISMATCH do begin
  FreeMem(SystemSessionInformation.Buffer);
  ListSize := ListSize * 2;
  SystemSessionInformation.BufferSize := ListSize;
  GetMem(SystemSessionInformation.Buffer, ListSize);
  rc := NtQuerySystemInformation(InfoClass, @SystemSessionInformation,
    SizeOf(SystemSessionInformation), @ReturnLength);
end;

У меня, почему-то работает следующее :
cbSize:=0;
rc := NtQuerySystemInformation(InfoClass, nil, cbSize, @ReturnLength);
if rc = STATUS_INFO_LENGTH_MISMATCH then
begin
 cbSize:=ReturnLength;
 ReallocMem(pSysInfo, ReturnLength);
 rc:=NtQuerySystemInformation(InfoClass, pSysInfo, cbSize,ReturnLength);
end;


tesseract   (2006-07-27 16:48:00) [9]


> learner ©   (27.07.06 16:37) [18]


вся запись должна быть кратна 32.
это повышает производительность. В приниципе убери packed и должно всё работать.

сначала объявляються 4 - байтные поля - потом остальные.
string лучше заменить на pchar -тоже 4 байта будет.


Игорь Шевченко   (2006-07-27 16:41:00) [10]

learner ©   (27.07.06 16:37) [18]

Можно и так. А можно воспользоваться моими же классами...

{
  Модуль: NtProcessInfo

  Описание: Класс для удобного представления информации о списке процессов
            и потоков, возвращаемом функцией NtQuerySystemInformation
            с информационным классом SystemProcessesAndThreadsInformation

  Автор: Игорь Шевченко

  Дата создания: 20.12.2002

  История изменений:
}
unit NtProcessInfo;

interface
uses
 NtDll, HSObjectList, Windows, HsNtDef;

type
 THSNtThreadInfo = class
 public
   Info: SYSTEM_THREADS;
   constructor Create (AInfo: SYSTEM_THREADS);
 end;

 THSNtThreadInfoList = class(THSObjectList)
 private
   function GetItems (I: Integer): THSNtThreadInfo;
 public
   property Items[I: Integer]: THSNtThreadInfo read GetItems; default;
 end;

 {
   Информация о процессе, приведенная к единому виду для операционных систем
   Windows NT4 и Windows 2000 (и выше).
 }
 THSNtProcessInfo = class
 private
   function GetProcessName: string;
   function GetUserName: string;
 public
   Info: SYSTEM_PROCESSES_NT2000;
   Threads: THSNtThreadInfoList;

   constructor Create (const AInfo: SYSTEM_PROCESSES_NT2000);
   constructor CreateNt4 (const AInfo: SYSTEM_PROCESSES_NT4);
   destructor Destroy; override;
   property ProcessName: string read GetProcessName;
   property UserName: string read GetUserName;
 end;

 THSNtProcessInfoList = class(THSObjectList)
 private
   function GetItems (I: Integer): THSNtProcessInfo;
 public
   constructor Create (AData: Pointer);
   constructor CreateEmpty;
   procedure Rebuild (const AData: Pointer);
   property Items[I: Integer]: THSNtProcessInfo read GetItems; default;
 end;
 TQueryListInformation = function (InfoClass: Integer; var rc: NTSTATUS;
 var ReturnLength: DWORD): Pointer;

function QueryListInformation (InfoClass: Integer; var rc: NTSTATUS;
 var ReturnLength: DWORD): Pointer;
function QuerySessionListInformation (const SessionId: ULONG;
 InfoClass: Integer; var rc: NTSTATUS; var ReturnLength: DWORD): Pointer;

implementation
uses
 SysUtils, NtStatusDefs, NtUtils;

function QueryListInformation (InfoClass: Integer; var rc: NTSTATUS;
 var ReturnLength: DWORD): Pointer;
var
 ListSize: Integer;
begin
 ListSize := $400;
 GetMem(Result, ListSize);
 rc := NtQuerySystemInformation(InfoClass, Result, ListSize, @ReturnLength);
 while rc = STATUS_INFO_LENGTH_MISMATCH do begin
   FreeMem(Result);
   ListSize := ListSize * 2;
   GetMem(Result, ListSize);
   rc := NtQuerySystemInformation(InfoClass, Result, ListSize, @ReturnLength);
 end;
 if rc <> STATUS_SUCCESS then begin
   FreeMem(Result);
   Result := nil;
 end;
end;

function QuerySessionListInformation (const SessionId: ULONG;
 InfoClass: Integer; var rc: NTSTATUS; var ReturnLength: DWORD): Pointer;
var
 ListSize: Integer;
 SystemSessionInformation: SYSTEM_SESSION_INFORMATION;
begin
 ListSize := $1000;
 SystemSessionInformation.SessionId := SessionId;
 SystemSessionInformation.BufferSize := ListSize;
 GetMem(SystemSessionInformation.Buffer, ListSize);
 rc := NtQuerySystemInformation(InfoClass, @SystemSessionInformation,
   SizeOf(SystemSessionInformation), @ReturnLength);
 while rc = STATUS_INFO_LENGTH_MISMATCH do begin
   FreeMem(SystemSessionInformation.Buffer);
   ListSize := ListSize * 2;
   SystemSessionInformation.BufferSize := ListSize;
   GetMem(SystemSessionInformation.Buffer, ListSize);
   rc := NtQuerySystemInformation(InfoClass, @SystemSessionInformation,
     SizeOf(SystemSessionInformation), @ReturnLength);
 end;
 if rc <> STATUS_SUCCESS then begin
   FreeMem(SystemSessionInformation.Buffer);
   Result := nil;
 end else
   Result := SystemSessionInformation.Buffer;
end;

{ THSNtThreadInfo }

constructor THSNtThreadInfo.Create (AInfo: SYSTEM_THREADS);
begin
 inherited Create;
 Info := AInfo;
end;

{ THSNtThreadInfoList }

function THSNtThreadInfoList.GetItems (I: Integer): THSNtThreadInfo;
begin
 Result := THSNtThreadInfo(inherited Items[I]);
end;

{ THSNtProcessInfo }

constructor THSNtProcessInfo.Create (const AInfo: SYSTEM_PROCESSES_NT2000);
begin
 inherited Create;
 Info := AInfo;
 Threads := THSNtThreadInfoList.Create;
end;

constructor THSNtProcessInfo.CreateNt4 (const AInfo: SYSTEM_PROCESSES_NT4);
begin
 inherited Create;
 Move (AInfo, Info, SizeOf(AInfo));
 FillChar(Info.IoCounters, SizeOf(IO_COUNTERS), 0);
 Threads := THSNtThreadInfoList.Create;
end;

destructor THSNtProcessInfo.Destroy;
begin
 Threads.Free;
 inherited;
end;

{ THSNtProcessInfoList }

constructor THSNtProcessInfoList.Create (AData: Pointer);
begin
 inherited Create;
 Rebuild (AData);
end;

constructor THSNtProcessInfoList.CreateEmpty;
begin
 inherited Create;
end;

function THSNtProcessInfoList.GetItems (I: Integer): THSNtProcessInfo;
begin
 Result := THSNtProcessInfo(inherited Items[I]);
end;

function THSNtProcessInfo.GetProcessName: string;
begin
 Result := HSUnicodeStringToAnsiString(Info.ProcessName);
end;

procedure THSNtProcessInfoList.Rebuild(const AData: Pointer);
var
 NextOffset: ULONG;
 PProcess: PSYSTEM_PROCESSES_NT2000;
 ProcessItem: THSNtProcessInfo;
 PThreads: PSYSTEM_THREADS_ARRAY;
 I: Integer;
begin
 Clear;
 PProcess := PSYSTEM_PROCESSES_NT2000(AData);
 repeat
   if Win32MajorVersion <= 4 then begin
     ProcessItem := THSNtProcessInfo.CreateNt4 (
       PSYSTEM_PROCESSES_NT4(PProcess)^);
     PThreads := PSYSTEM_THREADS_ARRAY(DWORD(PProcess) +
       SizeOf(SYSTEM_PROCESSES_NT4));
   end else begin
     ProcessItem := THSNtProcessInfo.Create(PProcess^);
     PThreads := PSYSTEM_THREADS_ARRAY(DWORD(PProcess) +
       SizeOf(SYSTEM_PROCESSES_NT2000));
   end;
   for I:=0 to Pred(ProcessItem.Info.ThreadCount) do
     ProcessItem.Threads.Add(THSNtThreadInfo.Create(PThreads^[I]));
   Add(ProcessItem);
   NextOffset := PProcess^.NextEntryDelta;
   PProcess := PSYSTEM_PROCESSES_NT2000(DWORD(PProcess) + NextOffset);
 until NextOffset = 0;
end;

function SIDToName (const SID: PSID): string;
var
 Use: SID_NAME_USE;
 DomainName: ZString;
 DomainNameLength: DWORD;
 Name: ZString;
 NameLength: DWORD;
begin
 DomainNameLength := SizeOf(DomainName);
 NameLength := SizeOf(Name);
 if not LookupAccountSid (nil, SID, Name, NameLength, DomainName,
    DomainNameLength, Use) then
   Result := '***'
 else
   Result := Name;
end;

function THSNtProcessInfo.GetUserName: string;
var
 AccessToken: THandle;
 SidInfo: PSIDANDATTRIBUTES;
 ReturnLength: DWORD;
 ProcessHandle: THandle;
begin
 Result := '';
 ProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION, false,
   Info.ProcessId);
 if ProcessHandle = 0 then
   Exit;
 try
   if not OpenProcessToken(ProcessHandle, TOKEN_QUERY, AccessToken) then
     Exit;
   GetMem (SidInfo, 4096);
   try
     Win32Check(GetTokenInformation(AccessToken, TokenUser, SidInfo, 4096,
       ReturnLength));
     Result := SidToName(SidInfo^.Sid);
   finally
     FreeMem(SidInfo);
     CloseHandle(AccessToken);
   end;
 finally
   CloseHandle(ProcessHandle);
 end;
end;

end.


learner   (2006-07-27 16:37:00) [11]

SYSTEM_PROCESSES_ADD = packed record
  IoCounters: IO_COUNTERS; ( 48 )
  VmCounters : VM_COUNTERS; ( 44 )
  CreateTime : LARGE_INTEGER;
  UserTime : LARGE_INTEGER;
  KernelTime : LARGE_INTEGER;
  NextEntryDelta : ULONG;
  ThreadCount : ULONG;
  ProcessId : ULONG;
  InheritedFromProcessId : ULONG;
  HandleCount : ULONG;
  PrivatePageCount : ULONG;
  BasePriority : KPRIORITY;
  ProcessName : string;
  FullPath : string;
  UserName : string;  
  Threads: array [0..0] of SYSTEM_THREADS;
end;
Т.е. так ?


tesseract   (2006-07-27 16:30:00) [12]


> Мефисто   (27.07.06 16:28) [15]


Да я не против. Так на пальцах раскрыл проблему как мог.
Сам уже слабо помню механиз всяких prefetch.

но AMD такой код воспримет лучше, чем p4.


learner   (2006-07-27 16:29:00) [13]

>ЗЫ: но в пять раз - я так понимаю pentium4?
Да. pentium4, 3.0 GHz
Вызывала в цикле 10 000 раз.


Мефисто   (2006-07-27 16:28:00) [14]


> tesseract ©   (27.07.06 16:17) [14]


Так скажем, оба этих фактора влияют в комплексе на проблему выше.


tesseract   (2006-07-27 16:17:00) [15]


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


не на выравнивание, а на  поиск нужных данных в структуре, процесс долгий, учитываю 32 битность процессора.

Плюс ещё сбиваешь с толку кэш процессора.  

ЗЫ: но в пять раз - я так понимаю pentium4?


Мефисто   (2006-07-27 16:11:00) [16]

Воспользоваться рекомендациями:


> tesseract ©   (27.07.06 15:28) [2]


Причем в рекордах желательно первыми полями указывать поля по 4 байта,
потом 2 байта, и затем по 1 байтовые поля. Т.е. от большего к меньшему.
Причина в выравнивании данныйх по 4 байтам (tesseract ©   (27.07.06 15:28) [2]). А если беспорядочно поля выставить, то время зря тратиться на выравниваниек данных.


learner   (2006-07-27 16:05:00) [17]

[2] tesseract ©   (27.07.06 15:28)
> В packed record да, зависит. Необходимо выровнять переменные по 4 байтам.
Это означает изменить тип или порядок ?
Можно подробнее ?


learner   (2006-07-27 16:02:00) [18]

>[10] Сергей М. ©   (27.07.06 15:57)
Это не точная копия.
>И что, это дает уверенность, что порядок следования полей можно менять от >балды ?
Так я же ее сама вручную заполняю. И в др. функциях (не моих) не использую.


Сергей М.   (2006-07-27 15:57:00) [19]


> learner ©   (27.07.06 15:52) [8]


> а вот Вам необходимо


Ой какие мы нежные !)


> [9]


И что, это дает уверенность, что порядок следования полей можно менять от балды ? Даже несмотря на то что это творчество уважаемого ИШ, а не мелкомягких ?


learner   (2006-07-27 15:53:00) [20]

>[6] Игорь Шевченко ©   (27.07.06 15:50)
>Это не MSDN. Это вольная переделка моего творчества, похоже.
Совершенно верно.


Страницы:   1 2

Наверх

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