From 029c35262ee60c1fc06f40abae772ad96f259411 Mon Sep 17 00:00:00 2001 From: David Hall Date: Wed, 10 Jul 2019 15:32:02 -0600 Subject: [PATCH] Fixed and updated functions in realtimeapiset.h Added unit tests --- PInvoke/Kernel32/RealtimeApiSet.cs | 364 ++++++++++++++++------ UnitTests/PInvoke/Kernel32/RealtimeApiSetTests.cs | 84 +++++ 2 files changed, 361 insertions(+), 87 deletions(-) create mode 100644 UnitTests/PInvoke/Kernel32/RealtimeApiSetTests.cs diff --git a/PInvoke/Kernel32/RealtimeApiSet.cs b/PInvoke/Kernel32/RealtimeApiSet.cs index 28dff426..e1f11b64 100644 --- a/PInvoke/Kernel32/RealtimeApiSet.cs +++ b/PInvoke/Kernel32/RealtimeApiSet.cs @@ -6,15 +6,18 @@ namespace Vanara.PInvoke public static partial class Kernel32 { /// - /// Converts the specified auxiliary counter value to the corresponding performance counter value; optionally provides the estimated conversion error in - /// nanoseconds due to latencies and maximum possible drift. + /// Converts the specified auxiliary counter value to the corresponding performance counter value; optionally provides the estimated + /// conversion error in nanoseconds due to latencies and maximum possible drift. /// /// The auxiliary counter value to convert. - /// On success, contains the converted performance counter value. Will be undefined if the function fails. - /// On success, contains the estimated conversion error, in nanoseconds. Will be undefined if the function fails. + /// + /// On success, contains the converted performance counter value. Will be undefined if the function fails. + /// + /// + /// On success, contains the estimated conversion error, in nanoseconds. Will be undefined if the function fails. + /// /// /// Returns S_OK if the conversion succeeds; otherwise, returns another HRESULT specifying the error. - /// /// /// /// Return value @@ -33,24 +36,27 @@ namespace Vanara.PInvoke /// The value to convert is outside the permitted range (+/- 10 seconds from when the called occurred). /// /// - /// /// - // HRESULT WINAPI ConvertAuxiliaryCounterToPerformanceCounter( _In_ ULONGLONG ullAuxiliaryCounterValue, _Out_ PULONGLONG lpPerformanceCounterValue, - // _Out_opt_ PULONGLONG lpConversionError); https://msdn.microsoft.com/en-us/library/windows/desktop/mt781214(v=vs.85).aspx - [DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)] - [PInvokeData("Realtimeapiset.h", MSDNShortId = "mt781214")] + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-convertauxiliarycountertoperformancecounter + // HRESULT ConvertAuxiliaryCounterToPerformanceCounter( ULONGLONG ullAuxiliaryCounterValue, PULONGLONG lpPerformanceCounterValue, + // PULONGLONG lpConversionError ); + [DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true)] + [PInvokeData("realtimeapiset.h", MSDNShortId = "94664D63-D1B0-443B-BB88-C8A8771577A6")] public static extern HRESULT ConvertAuxiliaryCounterToPerformanceCounter(ulong ullAuxiliaryCounterValue, out ulong lpPerformanceCounterValue, out ulong lpConversionError); /// - /// Converts the specified performance counter value to the corresponding auxiliary counter value; optionally provides the estimated conversion error in - /// nanoseconds due to latencies and maximum possible drift. + /// Converts the specified performance counter value to the corresponding auxiliary counter value; optionally provides the estimated + /// conversion error in nanoseconds due to latencies and maximum possible drift. /// /// The performance counter value to convert. - /// On success, contains the converted auxiliary counter value. Will be undefined if the function fails. - /// On success, contains the estimated conversion error, in nanoseconds. Will be undefined if the function fails. + /// + /// On success, contains the converted auxiliary counter value. Will be undefined if the function fails. + /// + /// + /// On success, contains the estimated conversion error, in nanoseconds. Will be undefined if the function fails. + /// /// /// Returns S_OK if the conversion succeeds; otherwise, returns another HRESULT specifying the error. - /// /// /// /// Return value @@ -73,40 +79,47 @@ namespace Vanara.PInvoke /// The value to convert is prior to the last system boot or S3/S4 transition. /// /// - /// /// - // HRESULT WINAPI ConvertPerformanceCounterToAuxiliaryCounter( _In_ ULONGLONG ullPerformanceCounterValue, _Out_ PULONGLONG lpAuxiliaryCounterValue, - // _Out_opt_ PULONGLONG lpConversionError); https://msdn.microsoft.com/en-us/library/windows/desktop/mt781215(v=vs.85).aspx - [DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)] - [PInvokeData("Realtimeapiset.h", MSDNShortId = "mt781215")] + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-convertperformancecountertoauxiliarycounter + // HRESULT ConvertPerformanceCounterToAuxiliaryCounter( ULONGLONG ullPerformanceCounterValue, PULONGLONG lpAuxiliaryCounterValue, + // PULONGLONG lpConversionError ); + [DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true)] + [PInvokeData("realtimeapiset.h", MSDNShortId = "2499981B-6C13-4A3D-836A-D4CCD11C8D50")] public static extern HRESULT ConvertPerformanceCounterToAuxiliaryCounter(ulong ullPerformanceCounterValue, out ulong lpAuxiliaryCounterValue, out ulong lpConversionError); /// Queries the auxiliary counter frequency. /// - /// Long pointer to an output buffer that contains the specified auxiliary counter frequency. If the auxiliary counter is not supported, the value in the - /// output buffer will be undefined. + /// Long pointer to an output buffer that contains the specified auxiliary counter frequency. If the auxiliary counter is not + /// supported, the value in the output buffer will be undefined. /// /// Returns S_OK if the auxiliary counter is supported and E_NOTIMPL if the auxiliary counter is not supported. - // HRESULT WINAPI QueryAuxiliaryCounterFrequency( _Out_ PULONGLONG lpAuxiliaryCounterFrequency); https://msdn.microsoft.com/en-us/library/windows/desktop/mt781218(v=vs.85).aspx - [DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)] - [PInvokeData("Realtimeapiset.h", MSDNShortId = "mt781218")] + /// + /// You can determine the availability of the auxiliary counter by comparing the returned value against E_NOTIMPL. + /// Examples + /// The following sample describes how to call QueryAuxiliaryCounterFrequency to retrieve the counter frequency. + /// + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryauxiliarycounterfrequency HRESULT + // QueryAuxiliaryCounterFrequency( PULONGLONG lpAuxiliaryCounterFrequency ); + [DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true)] + [PInvokeData("realtimeapiset.h", MSDNShortId = "71E00DF2-7F67-43D2-9D6D-BFE9FEA4B30A")] public static extern HRESULT QueryAuxiliaryCounterFrequency(out ulong lpAuxiliaryCounterFrequency); /// /// Retrieves the cycle time for the idle thread of each processor in the system. /// - /// On a system with more than 64 processors, this function retrieves the cycle time for the idle thread of each processor in the processor group to - /// which the calling thread is assigned. Use the QueryIdleProcessorCycleTimeEx function to retrieve the cycle time for the idle thread on each - /// logical processor for a specific processor group. + /// On a system with more than 64 processors, this function retrieves the cycle time for the idle thread of each processor in the + /// processor group to which the calling thread is assigned. Use the QueryIdleProcessorCycleTimeEx function to retrieve the cycle + /// time for the idle thread on each logical processor for a specific processor group. /// /// /// /// - /// On input, specifies the size of the ProcessorIdleCycleTime buffer, in bytes. This buffer is expected to be 8 times the number of processors in the group. + /// On input, specifies the size of the ProcessorIdleCycleTime buffer, in bytes. This buffer is expected to be 8 times the number of + /// processors in the group. /// /// - /// On output, specifies the number of elements written to the buffer. If the buffer size is not sufficient, the function fails and this parameter - /// receives the required length of the buffer. + /// On output, specifies the number of elements written to the buffer. If the buffer size is not sufficient, the function fails and + /// this parameter receives the required length of the buffer. /// /// /// @@ -114,123 +127,300 @@ namespace Vanara.PInvoke /// /// /// If the function succeeds, the return value is nonzero. - /// If the function fails, the return value is zero. To get extended error information, call GetLastError. + /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// - // BOOL WINAPI QueryIdleProcessorCycleTime( _Inout_ PULONG BufferLength, _Out_ PULONG64 ProcessorIdleCycleTime); https://msdn.microsoft.com/en-us/library/windows/desktop/ms684922(v=vs.85).aspx - [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] - [PInvokeData("WinBase.h", MSDNShortId = "ms684922")] + /// To compile an application that uses this function, define _WIN32_WINNT as 0x0600 or later. + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryidleprocessorcycletime BOOL + // QueryIdleProcessorCycleTime( PULONG BufferLength, PULONG64 ProcessorIdleCycleTime ); + [DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)] + [PInvokeData("realtimeapiset.h", MSDNShortId = "75a5c4cf-ccc7-47ab-a2a9-88051e0a7d06")] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool QueryIdleProcessorCycleTime(ref uint BufferLength, IntPtr ProcessorIdleCycleTime); + public static extern bool QueryIdleProcessorCycleTime(ref uint BufferLength, ulong[] ProcessorIdleCycleTime); + + /// + /// Retrieves the cycle time for the idle thread of each processor in the system. + /// + /// On a system with more than 64 processors, this function retrieves the cycle time for the idle thread of each processor in the + /// processor group to which the calling thread is assigned. Use the QueryIdleProcessorCycleTimeEx function to retrieve the cycle + /// time for the idle thread on each logical processor for a specific processor group. + /// + /// + /// The number of CPU clock cycles used by each idle thread. + [PInvokeData("realtimeapiset.h", MSDNShortId = "75a5c4cf-ccc7-47ab-a2a9-88051e0a7d06")] + public static ulong[] QueryIdleProcessorCycleTime() + { + var ct = new ulong[Environment.ProcessorCount]; + var sz = (uint)ct.Length * sizeof(ulong); + if (!QueryIdleProcessorCycleTime(ref sz, ct)) + Win32Error.ThrowLastError(); + return ct; + } /// Retrieves the accumulated cycle time for the idle thread on each logical processor in the specified processor group. /// The number of the processor group for which to retrieve the cycle time. /// /// - /// On input, specifies the size of the ProcessorIdleCycleTime buffer, in bytes. This buffer is expected to be 8 times the number of processors in the group. + /// On input, specifies the size of the ProcessorIdleCycleTime buffer, in bytes. This buffer is expected to be 8 times the number of + /// processors in the group. /// /// - /// On output, specifies the number of elements written to the buffer. If the buffer size is not sufficient, the function fails and this parameter - /// receives the required length of the buffer. + /// On output, specifies the number of elements written to the buffer. If the buffer size is not sufficient, the function fails and + /// this parameter receives the required length of the buffer. /// /// /// - /// The number of CPU clock cycles used by each idle thread. If this parameter is NULL, the function updates the BufferLength parameter with the required length. + /// The number of CPU clock cycles used by each idle thread. If this parameter is NULL, the function updates the BufferLength + /// parameter with the required length. /// /// /// If the function succeeds, the return value is nonzero. - /// If the function fails, the return value is zero. To get extended error information, use GetLastError. + /// If the function fails, the return value is zero. To get extended error information, use GetLastError. /// - // BOOL QueryIdleProcessorCycleTimeEx( _In_ USHORT Group, _Inout_ PULONG BufferLength, _Out_ PULONG64 ProcessorIdleCycleTime); https://msdn.microsoft.com/en-us/library/windows/desktop/dd405507(v=vs.85).aspx - [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] - [PInvokeData("WinBase.h", MSDNShortId = "dd405507")] + /// + /// To compile an application that uses this function, set _WIN32_WINNT >= 0x0601. For more information, see Using the Windows Headers. + /// + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryidleprocessorcycletimeex BOOL + // QueryIdleProcessorCycleTimeEx( USHORT Group, PULONG BufferLength, PULONG64 ProcessorIdleCycleTime ); + [DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)] + [PInvokeData("realtimeapiset.h", MSDNShortId = "4bf05e40-96d1-4c01-b3a8-8a45934b38c6")] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool QueryIdleProcessorCycleTimeEx(ushort Group, ref uint BufferLength, IntPtr ProcessorIdleCycleTime); + public static extern bool QueryIdleProcessorCycleTimeEx(ushort Group, ref uint BufferLength, ulong[] ProcessorIdleCycleTime); - /// Gets the current interrupt-time count. For a more precise count, use QueryInterruptTimePrecise. + /// Retrieves the accumulated cycle time for the idle thread on each logical processor in the specified processor group. + /// The number of the processor group for which to retrieve the cycle time. + /// The number of CPU clock cycles used by each idle thread. + [PInvokeData("realtimeapiset.h", MSDNShortId = "4bf05e40-96d1-4c01-b3a8-8a45934b38c6")] + public static ulong[] QueryIdleProcessorCycleTimeEx(ushort Group) + { + var ct = new ulong[Environment.ProcessorCount]; + var sz = (uint)ct.Length * sizeof(ulong); + if (!QueryIdleProcessorCycleTimeEx(Group, ref sz, ct)) + Win32Error.ThrowLastError(); + return ct; + } + + /// Gets the current interrupt-time count. For a more precise count, use QueryInterruptTimePrecise. /// - /// A pointer to a ULONGLONG in which to receive the interrupt-time count in system time units of 100 nanoseconds. Divide by ten million, or 1e7, to get - /// seconds (there are 1e9 nanoseconds in a second, so there are 1e7 100-nanoseconds in a second). + /// A pointer to a ULONGLONG in which to receive the interrupt-time count in system time units of 100 nanoseconds. Divide by ten + /// million, or 1e7, to get seconds (there are 1e9 nanoseconds in a second, so there are 1e7 100-nanoseconds in a second). /// /// This function does not return a value. - // VOID QueryInterruptTime( _Out_ PULONGLONG lpInterruptTime); https://msdn.microsoft.com/en-us/library/windows/desktop/dn903659(v=vs.85).aspx - [DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)] - [PInvokeData("Realtimeapiset.h", MSDNShortId = "dn903659")] + /// + /// + /// The interrupt-time count begins at zero when the system starts and is incremented at each clock interrupt by the length of a + /// clock tick. The exact length of a clock tick depends on underlying hardware and can vary between systems. + /// + /// + /// Unlike system time, the interrupt-time count is not subject to adjustments by users or the Windows time service. Applications can + /// use the interrupt-time count to measure finer durations than are possible with system time. Applications that require greater + /// precision than the interrupt-time count should use a high-resolution timer. Use the QueryPerformanceFrequency function to + /// retrieve the frequency of the high-resolution timer and the QueryPerformanceCounter function to retrieve the counter's value. + /// + /// + /// The timer resolution set by the timeBeginPeriod and timeEndPeriod functions affects the resolution of the + /// QueryInterruptTime function. However, increasing the timer resolution is not recommended because it can reduce overall + /// system performance and increase system power consumption by preventing the processor from entering power-saving states. Instead, + /// applications should use a high-resolution timer. + /// + /// + /// Note The QueryInterruptTime function produces different results on debug ("checked") builds of Windows, because the + /// interrupt-time count and tick count are advanced by approximately 49 days. This helps to identify bugs that might not occur until + /// the system has been running for a long time. The checked build is available to MSDN subscribers through the Microsoft Developer + /// Network (MSDN) Web site. + /// + /// + /// To compile an application that uses this function, define _WIN32_WINNT as 0x0601 or later. For more information, see Using the + /// Windows Headers. + /// + /// + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryinterrupttime void QueryInterruptTime( + // PULONGLONG lpInterruptTime ); + [DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true)] + [PInvokeData("realtimeapiset.h", MSDNShortId = "FB2B179B-5E44-4201-86E2-DB386607FD90")] public static extern void QueryInterruptTime(out ulong lpInterruptTime); - /// Gets the current interrupt-time count, in a more precise form than QueryInterruptTime does. + /// Gets the current interrupt-time count, in a more precise form than QueryInterruptTime does. /// - /// A pointer to a ULONGLONG in which to receive the interrupt-time count in system time units of 100 nanoseconds. Divide by ten million, or 1e7, to get - /// seconds (there are 1e9 nanoseconds in a second, so there are 1e7 100-nanoseconds in a second). + /// A pointer to a ULONGLONG in which to receive the interrupt-time count in system time units of 100 nanoseconds. Divide by ten + /// million, or 1e7, to get seconds (there are 1e9 nanoseconds in a second, so there are 1e7 100-nanoseconds in a second). /// /// This function does not return a value. - // VOID QueryInterruptTimePrecise( _Out_ PULONGLONG lpInterruptTimePrecise); https://msdn.microsoft.com/en-us/library/windows/desktop/dn903660(v=vs.85).aspx - [DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)] - [PInvokeData("Realtimeapiset.h", MSDNShortId = "dn903660")] + /// + /// + /// QueryInterruptTimePrecise is similar to the QueryInterruptTime routine, but is more precise. The interrupt time reported + /// by QueryInterruptTime is based on the latest tick of the system clock timer. The system clock timer is the hardware timer + /// that periodically generates interrupts for the system clock. The uniform period between system clock timer interrupts is referred + /// to as a system clock tick, and is typically in the range of 0.5 milliseconds to 15.625 milliseconds, depending on the hardware + /// platform. The interrupt time value retrieved by QueryInterruptTime is accurate within a system clock tick. + /// + /// + /// To provide a system time value that is more precise than that of QueryInterruptTime, QueryInterruptTimePrecise reads the + /// timer hardware directly, therefore a QueryInterruptTimePrecise call can be slower than a QueryInterruptTime call. + /// + /// Call the KeQueryTimeIncrement routine to determine the duration of a system clock tick. + /// Also see Remarks in QueryInterruptTime. + /// + /// Note The QueryInterruptTimePrecise function produces different results on debug ("checked") builds of Windows, + /// because the interrupt-time count and tick count are advanced by approximately 49 days. This helps to identify bugs that might not + /// occur until the system has been running for a long time. The checked build is available to MSDN subscribers through the Microsoft + /// Developer Network (MSDN) Web site. + /// + /// + /// To compile an application that uses this function, define _WIN32_WINNT as 0x0601 or later. For more information, see Using the + /// Windows Headers. + /// + /// + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryinterrupttimeprecise void + // QueryInterruptTimePrecise( PULONGLONG lpInterruptTimePrecise ); + [DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true)] + [PInvokeData("realtimeapiset.h", MSDNShortId = "0F65A707-0899-4F79-B7CD-16C9143C4173")] public static extern void QueryInterruptTimePrecise(out ulong lpInterruptTimePrecise); /// Retrieves the sum of the cycle time of all threads of the specified process. /// - /// A handle to the process. The handle must have the PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION access right. For more information, - /// see Process Security and Access Rights. + /// A handle to the process. The handle must have the PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION access right. + /// For more information, see Process Security and Access Rights. /// /// /// The number of CPU clock cycles used by the threads of the process. This value includes cycles spent in both user mode and kernel mode. /// /// /// If the function succeeds, the return value is nonzero. - /// If the function fails, the return value is zero. To get extended error information, call GetLastError. + /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// - // BOOL WINAPI QueryProcessCycleTime( _In_ HANDLE ProcessHandle, _Out_ PULONG64 CycleTime); https://msdn.microsoft.com/en-us/library/windows/desktop/ms684929(v=vs.85).aspx - [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] - [PInvokeData("WinBase.h", MSDNShortId = "ms684929")] + /// + /// To enumerate the processes in the system, use the EnumProcesses function. + /// To compile an application that uses this function, define _WIN32_WINNT as 0x0600 or later. + /// + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryprocesscycletime BOOL + // QueryProcessCycleTime( HANDLE ProcessHandle, PULONG64 CycleTime ); + [DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)] + [PInvokeData("realtimeapiset.h", MSDNShortId = "1859bc0f-8065-4104-b421-1b4c020ad5ea")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool QueryProcessCycleTime(HPROCESS ProcessHandle, out ulong CycleTime); /// Retrieves the cycle time for the specified thread. /// - /// A handle to the thread. The handle must have the PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION access right. For more information, - /// see Process Security and Access Rights. + /// A handle to the thread. The handle must have the PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION access right. For + /// more information, see Process Security and Access Rights. + /// + /// + /// The number of CPU clock cycles used by the thread. This value includes cycles spent in both user mode and kernel mode. /// - /// The number of CPU clock cycles used by the thread. This value includes cycles spent in both user mode and kernel mode. /// /// If the function succeeds, the return value is nonzero. - /// If the function fails, the return value is zero. To get extended error information, call GetLastError. + /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// - // BOOL WINAPI QueryThreadCycleTime( _In_ HANDLE ThreadHandle, _Out_ PULONG64 CycleTime); https://msdn.microsoft.com/en-us/library/windows/desktop/ms684943(v=vs.85).aspx - [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] - [PInvokeData("WinBase.h", MSDNShortId = "ms684943")] + /// + /// + /// To enumerate the threads of the process, use the Thread32First and Thread32Next functions. To get the thread handle for a thread + /// identifier, use the OpenThread function. + /// + /// + /// Do not attempt to convert the CPU clock cycles returned by QueryThreadCycleTime to elapsed time. This function uses timer + /// services provided by the CPU, which can vary in implementation. For example, some CPUs will vary the frequency of the timer when + /// changing the frequency at which the CPU runs and others will leave it at a fixed rate. The behavior of each CPU is described in + /// the documentation provided by the CPU vendor. + /// + /// To compile an application that uses this function, define _WIN32_WINNT as 0x0600 or later. + /// + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-querythreadcycletime BOOL + // QueryThreadCycleTime( HANDLE ThreadHandle, PULONG64 CycleTime ); + [DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)] + [PInvokeData("realtimeapiset.h", MSDNShortId = "5828b073-48af-4118-9206-096b87c978e7")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool QueryThreadCycleTime(HTHREAD ThreadHandle, out ulong CycleTime); /// - /// Gets the current unbiased interrupt-time count, in units of 100 nanoseconds. The unbiased interrupt-time count does not include time the system - /// spends in sleep or hibernation. + /// Gets the current unbiased interrupt-time count, in units of 100 nanoseconds. The unbiased interrupt-time count does not include + /// time the system spends in sleep or hibernation. /// - /// - /// A pointer to a ULONGLONG in which to receive the unbiased interrupt-time count in system time units of 100 nanoseconds. Divide by ten million, or - /// 1e7, to get seconds (there are 1e9 nanoseconds in a second, so there are 1e7 100-nanoseconds in a second). - /// + /// TBD /// - /// If the function succeeds, the return value is nonzero. If the function fails because it is called with a null parameter, the return value is zero. + /// If the function succeeds, the return value is nonzero. If the function fails because it is called with a null parameter, the + /// return value is zero. /// - // BOOL QueryUnbiasedInterruptTime( _Out_ PULONGLONG lpUnbiasedInterruptTime); https://msdn.microsoft.com/en-us/library/windows/desktop/ee662307(v=vs.85).aspx - [DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)] - [PInvokeData("Winbase.h", MSDNShortId = "ee662307")] + /// + /// + /// The interrupt-time count begins at zero when the system starts and is incremented at each clock interrupt by the length of a + /// clock tick. The exact length of a clock tick depends on underlying hardware and can vary between systems. + /// + /// + /// The interrupt-time count retrieved by the QueryUnbiasedInterruptTime function reflects only the time that the system is in + /// the working state. Therefore, the interrupt-time count is not "biased" by time the system spends in sleep or hibernation. The + /// system uses biased interrupt time for some operations, such as ensuring that relative timers that would have expired during sleep + /// expire immediately upon waking. + /// + /// + /// Unlike system time, the interrupt-time count is not subject to adjustments by users or the Windows time service. Applications can + /// use the interrupt-time count to measure finer durations than are possible with system time. Applications that require greater + /// precision than the interrupt-time count should use a high-resolution timer. Use the QueryPerformanceFrequency function to + /// retrieve the frequency of the high-resolution timer and the QueryPerformanceCounter function to retrieve the counter's value. + /// + /// + /// The timer resolution set by the timeBeginPeriod and timeEndPeriod functions affects the resolution of the + /// QueryUnbiasedInterruptTime function. However, increasing the timer resolution is not recommended because it can reduce + /// overall system performance and increase system power consumption by preventing the processor from entering power-saving states. + /// Instead, applications should use a high-resolution timer. + /// + /// + /// Note The QueryUnbiasedInterruptTime function produces different results on debug ("checked") builds of Windows, + /// because the interrupt-time count and tick count are advanced by approximately 49 days. This helps to identify bugs that might not + /// occur until the system has been running for a long time. The checked build is available to MSDN subscribers through the Microsoft + /// Developer Network (MSDN) Web site. + /// + /// + /// To compile an application that uses this function, define _WIN32_WINNT as 0x0601 or later. For more information, see Using the + /// Windows Headers. + /// + /// + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryunbiasedinterrupttime BOOL + // QueryUnbiasedInterruptTime( PULONGLONG UnbiasedTime ); + [DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true)] + [PInvokeData("realtimeapiset.h", MSDNShortId = "f9cf5440-9be9-4ff9-b85c-2779b847954c")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool QueryUnbiasedInterruptTime(out ulong lpUnbiasedInterruptTime); /// - /// Gets the current unbiased interrupt-time count, in a more precise form than QueryUnbiasedInterruptTime does. The unbiased interrupt-time count - /// does not include time the system spends in sleep or hibernation. + /// Gets the current unbiased interrupt-time count, in a more precise form than QueryUnbiasedInterruptTime does. The unbiased + /// interrupt-time count does not include time the system spends in sleep or hibernation. /// /// - /// A pointer to a ULONGLONG in which to receive the unbiased interrupt-time count in system time units of 100 nanoseconds. Divide by ten million, or - /// 1e7, to get seconds (there are 1e9 nanoseconds in a second, so there are 1e7 100-nanoseconds in a second). + /// A pointer to a ULONGLONG in which to receive the unbiased interrupt-time count in system time units of 100 nanoseconds. Divide by + /// ten million, or 1e7, to get seconds (there are 1e9 nanoseconds in a second, so there are 1e7 100-nanoseconds in a second). /// /// This function does not return a value. - // VOID QueryUnbiasedInterruptTimePrecise( _Out_ PULONGLONG lpUnbiasedInterruptTimePrecise); https://msdn.microsoft.com/en-us/library/windows/desktop/dn891448(v=vs.85).aspx - [DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)] - [PInvokeData("Realtimeapiset.h", MSDNShortId = "dn891448")] + /// + /// + /// QueryUnbiasedInterruptTimePrecise is similar to the QueryUnbiasedInterruptTime routine, but is more precise. The interrupt + /// time reported by QueryUnbiasedInterruptTime is based on the latest tick of the system clock timer. The system clock timer + /// is the hardware timer that periodically generates interrupts for the system clock. The uniform period between system clock timer + /// interrupts is referred to as a system clock tick, and is typically in the range of 0.5 milliseconds to 15.625 milliseconds, + /// depending on the hardware platform. The interrupt time value retrieved by QueryUnbiasedInterruptTime is accurate within a + /// system clock tick. + /// + /// + /// To provide a system time value that is more precise than that of QueryUnbiasedInterruptTime, + /// QueryUnbiasedInterruptTimePrecise reads the timer hardware directly, therefore a QueryUnbiasedInterruptTimePrecise + /// call can be slower than a QueryUnbiasedInterruptTime call. + /// + /// Call the KeQueryTimeIncrement routine to determine the duration of a system clock tick. + /// Also see Remarks in QueryUnbiasedInterruptTime. + /// + /// Note The QueryUnbiasedInterruptTimePrecise function produces different results on debug ("checked") builds of + /// Windows, because the interrupt-time count and tick count are advanced by approximately 49 days. This helps to identify bugs that + /// might not occur until the system has been running for a long time. The checked build is available to MSDN subscribers through the + /// Microsoft Developer Network (MSDN) Web site. + /// + /// + /// To compile an application that uses this function, define _WIN32_WINNT as 0x0601 or later. For more information, see Using the + /// Windows Headers. + /// + /// + // https://docs.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryunbiasedinterrupttimeprecise void + // QueryUnbiasedInterruptTimePrecise( PULONGLONG lpUnbiasedInterruptTimePrecise ); + [DllImport(Lib.KernelBase, SetLastError = false, ExactSpelling = true)] + [PInvokeData("realtimeapiset.h", MSDNShortId = "FADFC168-A3CF-4676-9B6E-7A4028049423")] public static extern void QueryUnbiasedInterruptTimePrecise(out ulong lpUnbiasedInterruptTimePrecise); } } \ No newline at end of file diff --git a/UnitTests/PInvoke/Kernel32/RealtimeApiSetTests.cs b/UnitTests/PInvoke/Kernel32/RealtimeApiSetTests.cs new file mode 100644 index 00000000..9c25550b --- /dev/null +++ b/UnitTests/PInvoke/Kernel32/RealtimeApiSetTests.cs @@ -0,0 +1,84 @@ +using NUnit.Framework; +using System; +using System.Runtime.InteropServices; +using System.Text; +using Vanara.InteropServices; +using static Vanara.PInvoke.AdvApi32; +using static Vanara.PInvoke.Kernel32; + +namespace Vanara.PInvoke.Tests +{ + [TestFixture] + public class RealtimeApiSetTests + { + [Test] + public void ConvertAuxiliaryCounterToPerformanceCounterTest() + { + ulong aux = (ulong)new Random().Next(); + Assert.That(ConvertAuxiliaryCounterToPerformanceCounter(aux, out var perf, out var err), ResultIs.Successful); + Assert.That(ConvertPerformanceCounterToAuxiliaryCounter(perf, out var aux2, out err), ResultIs.Successful); + Assert.That(aux, Is.EqualTo(aux2)); + } + + [Test] + public void QueryAuxiliaryCounterFrequencyTest() + { + Assert.That(QueryAuxiliaryCounterFrequency(out var f), ResultIs.Successful); + Assert.That(f, Is.Not.Zero); + } + + [Test] + public void QueryIdleProcessorCycleTimeTest() + { + Assert.That(() => { Assert.That(QueryIdleProcessorCycleTime(), Is.Not.Empty); }, Throws.Nothing); + } + + [Test] + public void QueryIdleProcessorCycleTimeExTest() + { + Assert.That(() => { Assert.That(QueryIdleProcessorCycleTimeEx(0), Is.Not.Empty); }, Throws.Nothing); + } + + [Test] + public void QueryInterruptTimeTest() + { + QueryInterruptTime(out var t); + Assert.That(t, Is.Not.Zero); + } + + [Test] + public void QueryInterruptTimePreciseTest() + { + QueryInterruptTimePrecise(out var t); + Assert.That(t, Is.Not.Zero); + } + + [Test] + public void QueryProcessCycleTimeTest() + { + Assert.That(QueryProcessCycleTime(GetCurrentProcess(), out var t), ResultIs.Successful); + Assert.That(t, Is.Not.Zero); + } + + [Test] + public void QueryThreadCycleTimeTest() + { + Assert.That(QueryThreadCycleTime(GetCurrentThread(), out var t), ResultIs.Successful); + Assert.That(t, Is.Not.Zero); + } + + [Test] + public void QueryUnbiasedInterruptTimeTest() + { + Assert.That(QueryUnbiasedInterruptTime(out var t), ResultIs.Successful); + Assert.That(t, Is.Not.Zero); + } + + [Test] + public void QueryUnbiasedInterruptTimePreciseTest() + { + QueryUnbiasedInterruptTimePrecise(out var t); + Assert.That(t, Is.Not.Zero); + } + } +} \ No newline at end of file