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);
+ }
}
}