2017-09-28 7 views
2

ntdllのNtQuerySystemInformationを使用して、各プロセッサの性能に関する情報を得たいと考えています。今私はそれがちょうど5つすべての試行を実行し、その後返すという問題があります。c# - 構造体の配列のポインタの問題

NtQuerySystemInformationは常にInfoLengthMismatchであるNtStatusを返します。通常、これは通常、自分のバッファを大きくする必要があることを意味します。 1つのプロセッサ(配列なし)と0x10000のバッファサイズで試してみると、ちょっとうまく動作しますが、最初のtryではInfoLengthMismatchが得られますが、2回目は常に動作します。

私はバッファを100倍も増加させようとしましたが、何も効果がありませんでした。

private _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[] GetPerformanceInfo() 
    { 
     try 
     { 
      //Getting count of processors 
      SYSTEM_INFO sysInfo = new SYSTEM_INFO(); 
      GetSystemInfo(out sysInfo); 
      int processors = (int)sysInfo.numberOfProcessors; 

      int tries = 0; 

      while (true) 
      { 

       //buffer size 
       uint infoLength = (uint)(Marshal.SizeOf(typeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)) * processors); 

       //buffer 
       IntPtr infoPtr = Marshal.AllocHGlobal((int)infoLength); 

       //Problem: result is always InfoLengthMismatch 
       NtStatus result = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemProcessorPerformanceInformation, infoPtr, infoLength, out infoLength); 

       //if success, get the array and return it 
       if (result == NtStatus.Success) 
       { 
        int szStruct = Marshal.SizeOf(typeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); 
        _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[] localStructs = new _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[processors]; 

        for (uint i = 0; i < processors; i++) 
         localStructs[i] = (_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)Marshal.PtrToStructure(new IntPtr(infoPtr.ToInt64() + (szStruct * processors)), typeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); 

        return localStructs; 
       } 

       //free ptr when fail 
       Marshal.FreeHGlobal(infoPtr); 

       if (++tries > 5) 
        return null; 

       //set ptr again, new try 
       infoPtr = Marshal.AllocHGlobal((int)infoLength); 

      } 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Source + ": " + e.Message.ToString()); 
      return null; 
     } 
    } 

} 

//struct of a large int 
[StructLayout(LayoutKind.Explicit, Size = 8)] 
public struct LARGE_INTEGER 
{ 
    [FieldOffset(0)] public Int64 QuadPart; 
    [FieldOffset(0)] public UInt32 LowPart; 
    [FieldOffset(4)] public Int32 HighPart; 
} 

//struct 
public struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION 
{ 
    public LARGE_INTEGER IdleTime; 
    public LARGE_INTEGER KernelTime; 
    public LARGE_INTEGER UserTime; 
    public LARGE_INTEGER Reserved1; 
    public ulong Reserved2; 
} 

EDIT:サイズが間違っている

uint infoLength = (uint)(Marshal.SizeOf(typeof(_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)) * processors); 

通常ならば、それは、この場合には、私はinfoLengthのVARに適切なサイズに設定していてます:間違った事は、このラインでしたそれはループの始めに毎回です。

+0

メモリを2回割り当てて1回解放することは承知していますか? – Enfyve

答えて

2

私が気づいたことがいくつかあります。まず第一に、あなたは二回のメモリを割り当てていて、一度だけ、それを解放:NtQuerySystemInformationがエラーを返した場合

//buffer 
IntPtr infoPtr = Marshal.AllocHGlobal((int)infoLength); 

//... 

//free ptr when fail 
Marshal.FreeHGlobal(infoPtr); 

//... 

//set ptr again, new try 
infoPtr = Marshal.AllocHGlobal((int)infoLength); 

は第二に、それは必要なサイズにアウトオプションのパラメータを設定します。私が見ているものの、バッファサイズは8 * 5 * processorsです。または40 * processors

コールの前後にinfoLengthを出力することで、適切なサイズと必要なサイズを確認できます。

// Should be 40 * processors 
Console.WriteLine((int)infoLength); 

//Problem: result is always InfoLengthMismatch 
NtStatus result = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemProcessorPerformanceInformation, 
         infoPtr, infoLength, out infoLength); 

// Will be bigger than 40 * processors 
Console.WriteLine((int)infoLength); 
+0

私は4つのプロセッサを持っていますが、infoLengthは40 * 40ではなく40に設定されます。 – Tom

+0

@Tom私はコードを複製して問題はありませんでした。私が追加したのは 'NtStatus'と' SYSTEM_INFORMATION_CLASS'の列挙型だけでした。 'NtQuerySystemInformation'のdllimportと' Environment.ProcessorCount'を使いました。 – Enfyve

関連する問題