diff --git a/trunk/ProcessHacker.Native/Api/NativeFunctions.cs b/trunk/ProcessHacker.Native/Api/NativeFunctions.cs index db9b18757..6628c07ce 100644 --- a/trunk/ProcessHacker.Native/Api/NativeFunctions.cs +++ b/trunk/ProcessHacker.Native/Api/NativeFunctions.cs @@ -295,10 +295,32 @@ namespace ProcessHacker.Native.Api [In] [Optional] IntPtr ExceptionPort ); + /// + /// Creates a profile object. + /// + /// A handle to the profile object. + /// + /// A handle to the process to profile. If NULL, all address spaces are profiled. + /// + /// + /// The first address at which to collect profiling information. + /// + /// + /// The size of the range to profile. ProfileBase <= address < + /// ProfileBase + ProfileSize will generate a hit. + /// + /// + /// A log2 value of each address bucket. Acceptable values are from 2 to 30. + /// + /// An array of int hit counters. + /// The size of the buffer, in bytes. + /// The profiling source. + /// The processors to profile. + /// A NTSTATUS value. [DllImport("ntdll.dll")] public static extern NtStatus NtCreateProfile( [Out] out IntPtr ProfileHandle, - [In] IntPtr ProcessHandle, + [In] [Optional] IntPtr ProcessHandle, [In] IntPtr ProfileBase, [In] IntPtr ProfileSize, [In] int BucketSize, diff --git a/trunk/ProcessHacker.Native/Objects/ProfileHandle.cs b/trunk/ProcessHacker.Native/Objects/ProfileHandle.cs index c77b9dc19..bca661b6d 100644 --- a/trunk/ProcessHacker.Native/Objects/ProfileHandle.cs +++ b/trunk/ProcessHacker.Native/Objects/ProfileHandle.cs @@ -21,8 +21,7 @@ */ using System; -using System.Collections.Generic; -using System.Text; +using System.Runtime.InteropServices; using ProcessHacker.Native.Api; using ProcessHacker.Native.Security; @@ -30,6 +29,90 @@ namespace ProcessHacker.Native.Objects { public class ProfileHandle : NativeHandle { - // TODO: Implement basics + public static ProfileHandle Create( + ProcessHandle processHandle, + IntPtr rangeBase, + int rangeSize, + int bucketSize, + KProfileSource profileSource, + IntPtr affinity + ) + { + NtStatus status; + IntPtr handle; + + if (bucketSize < 2 || bucketSize > 30) + throw new ArgumentException("Bucket size must be between 2 and 30, inclusive."); + + int realBucketSize = 2 << bucketSize; + MemoryAlloc buffer = new MemoryAlloc(((rangeSize - 1) / realBucketSize + 1) * sizeof(int)); // divide, round up + + if ((status = Win32.NtCreateProfile( + out handle, + processHandle, + rangeBase, + new IntPtr(rangeSize), + bucketSize, + buffer, + buffer.Size, + profileSource, + affinity + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return new ProfileHandle(handle, true, rangeBase, rangeSize, realBucketSize, buffer); + } + + private IntPtr _rangeBase; + private int _rangeSize; + private int _bucketSize; // not logarithmic + private MemoryAlloc _buffer; + + private ProfileHandle( + IntPtr handle, + bool owned, + IntPtr rangeBase, + int rangeSize, + int bucketSize, + MemoryAlloc buffer + ) + { + _rangeBase = rangeBase; + _rangeSize = rangeSize; + _bucketSize = bucketSize; + _buffer = buffer; + } + + protected override void Close() + { + _buffer.Dispose(); + + base.Close(); + } + + public int[] Collect() + { + int[] counters = new int[_buffer.Size / sizeof(int)]; + + Marshal.Copy(_buffer, counters, 0, counters.Length); + + return counters; + } + + public void Start() + { + NtStatus status; + + if ((status = Win32.NtStartProfile(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void Stop() + { + NtStatus status; + + if ((status = Win32.NtStopProfile(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } } }