mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3241 lines
72 KiB
3241 lines
72 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
timt.c
|
|
|
|
Abstract:
|
|
|
|
This module contains native NT performance tests for the system
|
|
calls and context switching.
|
|
|
|
Author:
|
|
|
|
David N. Cutler (davec) 23-Nov-1991
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdlib.h"
|
|
#include "stdio.h"
|
|
#include "string.h"
|
|
#include "nt.h"
|
|
#include "ntrtl.h"
|
|
#include "nturtl.h"
|
|
#include "slist.h"
|
|
|
|
//
|
|
// Define locals constants.
|
|
//
|
|
|
|
#define CALLBACK_ITERATIONS 500000
|
|
#define CHECKSUM_BUFFER_SIZE (1 << 16)
|
|
#define CHECKSUM_ITERATIONS 1000
|
|
#define CHECKSUM_IP_ITERATIONS 40000000
|
|
#define EVENT_CLEAR_ITERATIONS 500000
|
|
#define EVENT_RESET_ITERATIONS 500000
|
|
#define EVENT_CREATION_ITERATIONS 20000
|
|
#define EVENT_OPEN_ITERATIONS 20000
|
|
#define EVENT_QUERY_ITERATIONS 500000
|
|
#define EVENT1_SWITCHES 300000
|
|
#define EVENT2_SWITCHES 200000
|
|
#define EVENT3_SWITCHES 1500000
|
|
#define EVENT4_SWITCHES 400000
|
|
#define IO_ITERATIONS 70000
|
|
#define MUTANT_SWITCHES 100000
|
|
#define SLIST_ITERATIONS 20000000
|
|
#define SEMAPHORE1_SWITCHES 300000
|
|
#define SEMAPHORE2_SWITCHES 600000
|
|
#define SYSCALL_ITERATIONS 2000000
|
|
#define TIMER_INDEX_ITERATIONS 10000000
|
|
#define TIMER_OPERATION_ITERATIONS 500000
|
|
#define WAIT_SINGLE_ITERATIONS 200000
|
|
#define WAIT_MULTIPLE_ITERATIONS 200000
|
|
|
|
//
|
|
// Define event desired access.
|
|
//
|
|
|
|
#define DESIRED_EVENT_ACCESS (EVENT_QUERY_STATE | EVENT_MODIFY_STATE | SYNCHRONIZE)
|
|
|
|
//
|
|
// Define local types.
|
|
//
|
|
|
|
typedef struct _PERFINFO {
|
|
LARGE_INTEGER StartTime;
|
|
LARGE_INTEGER StopTime;
|
|
LARGE_INTEGER StartCycles;
|
|
LARGE_INTEGER StopCycles;
|
|
ULONG ContextSwitches;
|
|
ULONG InterruptCount;
|
|
ULONG FirstLevelFills;
|
|
ULONG SecondLevelFills;
|
|
ULONG SystemCalls;
|
|
PCHAR Title;
|
|
ULONG Iterations;
|
|
} PERFINFO, *PPERFINFO;
|
|
|
|
//
|
|
// Define test prototypes.
|
|
//
|
|
|
|
VOID
|
|
CallbackTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
ChecksumTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
EventClearTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
EventCreationTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
EventOpenTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
EventQueryTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
EventResetTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
Event1SwitchTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
Event2SwitchTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
Event3SwitchTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
Event4SwitchTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
Io1Test (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
MutantSwitchTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
Semaphore1SwitchTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
Semaphore2SwitchTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
SlistTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
SystemCallTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
TimerIndexTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
TimerOperationTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
WaitSingleTest (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
WaitMultipleTest (
|
|
VOID
|
|
);
|
|
|
|
//
|
|
// Define thread routine prototypes.
|
|
//
|
|
|
|
NTSTATUS
|
|
Event1Thread1 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
Event1Thread2 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
Event2Thread1 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
Event2Thread2 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
Event3Thread1 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
Event3Thread2 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
Event4Thread1 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
Event4Thread2 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
MutantThread1 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
MutantThread2 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
Semaphore1Thread1 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
Semaphore1Thread2 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
Semaphore2Thread1 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
Semaphore2Thread2 (
|
|
IN PVOID Context
|
|
);
|
|
|
|
NTSTATUS
|
|
TimerThread (
|
|
IN PVOID Context
|
|
);
|
|
|
|
//
|
|
// Define utility routine prototypes.
|
|
//
|
|
|
|
NTSTATUS
|
|
CreateThread (
|
|
OUT PHANDLE Handle,
|
|
IN PUSER_THREAD_START_ROUTINE StartRoutine,
|
|
IN KPRIORITY Priority
|
|
);
|
|
|
|
VOID
|
|
FinishBenchMark (
|
|
IN PPERFINFO PerfInfo
|
|
);
|
|
|
|
VOID
|
|
StartBenchMark (
|
|
IN PCHAR Title,
|
|
IN ULONG Iterations,
|
|
IN PPERFINFO PerfInfo
|
|
);
|
|
|
|
//
|
|
// Define external routine prototypes.
|
|
//
|
|
|
|
ULONG
|
|
ComputeTimerTableIndex32 (
|
|
IN LARGE_INTEGER Interval,
|
|
IN LARGE_INTEGER CurrentTime,
|
|
IN PULONGLONG DueTime
|
|
);
|
|
|
|
ULONG
|
|
ComputeTimerTableIndex64 (
|
|
IN LARGE_INTEGER Interval,
|
|
IN LARGE_INTEGER CurrentTime,
|
|
IN PULONGLONG DueTime
|
|
);
|
|
|
|
ULONG
|
|
ChkSum (
|
|
IN ULONG Sum,
|
|
IN PUSHORT Buffer,
|
|
IN ULONG Length
|
|
);
|
|
|
|
ULONG
|
|
oldxsum (
|
|
IN ULONG Sum,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Length
|
|
);
|
|
|
|
ULONG
|
|
tcpxsum (
|
|
IN ULONG Sum,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Length
|
|
);
|
|
|
|
|
|
//
|
|
// Define static storage.
|
|
//
|
|
|
|
HANDLE EventHandle1;
|
|
HANDLE EventHandle2;
|
|
HANDLE EventPairHandle;
|
|
HANDLE MutantHandle;
|
|
HANDLE SemaphoreHandle1;
|
|
HANDLE SemaphoreHandle2;
|
|
HANDLE Thread1Handle;
|
|
HANDLE Thread2Handle;
|
|
HANDLE TimerEventHandle;
|
|
HANDLE TimerTimerHandle;
|
|
HANDLE TimerThreadHandle;
|
|
USHORT ChecksumBuffer[CHECKSUM_BUFFER_SIZE / sizeof(USHORT)];
|
|
|
|
VOID
|
|
main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
|
|
{
|
|
|
|
KPRIORITY Priority = LOW_REALTIME_PRIORITY + 8;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// set priority of current thread.
|
|
//
|
|
|
|
Status = NtSetInformationThread(NtCurrentThread(),
|
|
ThreadPriority,
|
|
&Priority,
|
|
sizeof(KPRIORITY));
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to set thread priority during initialization\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Create an event object to signal the timer thread at the end of the
|
|
// test.
|
|
//
|
|
|
|
Status = NtCreateEvent(&TimerEventHandle,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event during initialization\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Create a timer object for use by the timer thread.
|
|
//
|
|
|
|
Status = NtCreateTimer(&TimerTimerHandle,
|
|
TIMER_ALL_ACCESS,
|
|
NULL,
|
|
NotificationTimer);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create timer during initialization\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Create and start the background timer thread.
|
|
//
|
|
|
|
Status = CreateThread(&TimerThreadHandle,
|
|
TimerThread,
|
|
LOW_REALTIME_PRIORITY + 12);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create timer thread during initialization\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Execute performance tests.
|
|
//
|
|
|
|
// CallbackTest();
|
|
// ChecksumTest();
|
|
// EventClearTest();
|
|
// EventCreationTest();
|
|
// EventOpenTest();
|
|
// EventQueryTest();
|
|
// EventResetTest();
|
|
// Event1SwitchTest();
|
|
// Event2SwitchTest();
|
|
// Event3SwitchTest();
|
|
// Event4SwitchTest();
|
|
// Io1Test();
|
|
// MutantSwitchTest();
|
|
// Semaphore1SwitchTest();
|
|
// Semaphore2SwitchTest();
|
|
SlistTest();
|
|
// SystemCallTest();
|
|
// TimerIndexTest();
|
|
// TimerOperationTest();
|
|
// WaitSingleTest();
|
|
// WaitMultipleTest();
|
|
|
|
//
|
|
// Set timer event and wait for timer thread to terminate.
|
|
//
|
|
|
|
Status = NtSetEvent(TimerEventHandle, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to set event in main loop\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtWaitForSingleObject(TimerThreadHandle,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to wait for timer thread at end of test\n");
|
|
}
|
|
|
|
//
|
|
// Close event, timer, and timer thread handles.
|
|
//
|
|
|
|
EndOfTest:
|
|
NtClose(TimerEventHandle);
|
|
NtClose(TimerTimerHandle);
|
|
NtClose(TimerThreadHandle);
|
|
return;
|
|
}
|
|
|
|
CHAR InputBuffer[] = "this is the input buffer";
|
|
CHAR OutputBuffer[] = "this is the output buffer";
|
|
|
|
NTSTATUS
|
|
Callback (
|
|
IN PVOID ValueBuffer,
|
|
IN ULONG ValueLength
|
|
)
|
|
|
|
{
|
|
|
|
NtCallbackReturn((PVOID)&OutputBuffer[0], 26, STATUS_SUCCESS);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
CallbackTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
PVOID Buffer;
|
|
ULONG Index;
|
|
ULONG Length;
|
|
PERFINFO PerfInfo;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Callback Benchmark (NtW32Call)",
|
|
CALLBACK_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly call a short callback routine.
|
|
//
|
|
|
|
for (Index = 0; Index < CALLBACK_ITERATIONS; Index += 1) {
|
|
NtW32Call((ULONG)Callback, (PVOID)&InputBuffer[0], 24, &Buffer, &Length);
|
|
if ((Buffer != (PVOID)&OutputBuffer[0]) || (Length != 26)) {
|
|
printf("**** output buffer mismatch\n");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
return;
|
|
}
|
|
|
|
ULONG
|
|
SwapSum(
|
|
ULONG Sum
|
|
)
|
|
{
|
|
ULONG newSum;
|
|
|
|
newSum = ((Sum & 0x000000FF) << 8); // byte 1 -> byte 2
|
|
newSum |= ((Sum & 0x0000FF00) >> 8); // byte 2 -> byte 1
|
|
newSum |= ((Sum & 0x00FF0000) << 8); // byte 3 -> byte 4
|
|
newSum |= ((Sum & 0xFF000000) >> 8); // byte 4 -> byte 3
|
|
|
|
return(newSum);
|
|
}
|
|
|
|
ULONG
|
|
xsum(
|
|
PVOID Buffer,
|
|
ULONG Size)
|
|
|
|
{
|
|
USHORT UNALIGNED *Buffer1 = (USHORT UNALIGNED *)Buffer;
|
|
ULONG csum = 0;
|
|
|
|
while (Size > 1) {
|
|
csum += *Buffer1++;
|
|
Size -= sizeof(USHORT);
|
|
}
|
|
|
|
if (Size)
|
|
csum += *(PUCHAR)Buffer1;
|
|
|
|
csum = (csum >> 16) + (csum & 0xffff);
|
|
csum += (csum >> 16);
|
|
return (ULONG)((USHORT)csum);
|
|
}
|
|
|
|
ULONG
|
|
oldxsum(
|
|
ULONG Sum,
|
|
PVOID Buffer,
|
|
ULONG BufferLength
|
|
)
|
|
{
|
|
if (BufferLength) {
|
|
//
|
|
// Check for word alignment.
|
|
//
|
|
if (!((ULONG)Buffer & 0x1)) {
|
|
//
|
|
// Make sure the length is an even number of words. If not, add
|
|
// in the last byte now.
|
|
//
|
|
if (!(BufferLength & 0x1)) {
|
|
return(ChkSum(Sum, (PUSHORT)Buffer, BufferLength >> 1));
|
|
}
|
|
|
|
Sum += (ULONG) *(((PUCHAR) Buffer) + BufferLength - 1);
|
|
|
|
return(ChkSum(Sum, (PUSHORT) Buffer, BufferLength >> 1));
|
|
}
|
|
|
|
//
|
|
// Buffer is not word aligned. Add in the first byte now and then
|
|
// swap the sum. When we're finished, we'll swap it back.
|
|
//
|
|
Sum += (ULONG) *((PUCHAR) Buffer);
|
|
((PUCHAR) Buffer)++;
|
|
BufferLength--;
|
|
Sum = SwapSum(Sum);
|
|
|
|
//
|
|
// Make sure the length is an even number of words. If not, add in the
|
|
// last byte now. Since we've already taken care of alignment, the last
|
|
// byte must be the low order one (if not, we've already swapped to
|
|
// handle it).
|
|
//
|
|
if (BufferLength & 0x1) {
|
|
Sum += (ULONG) *(((PUCHAR) Buffer) + BufferLength - 1);
|
|
}
|
|
|
|
return(SwapSum(ChkSum(Sum, Buffer, BufferLength >> 1)));
|
|
}
|
|
|
|
return(Sum);
|
|
}
|
|
|
|
VOID
|
|
ChecksumTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
LONG Count;
|
|
LONG Index;
|
|
PERFINFO PerfInfo;
|
|
ULONG Sum1;
|
|
ULONG Sum2;
|
|
PUCHAR Source;
|
|
|
|
//
|
|
// Initial the checksum buffers.
|
|
//
|
|
|
|
for (Index = 0; Index < (CHECKSUM_BUFFER_SIZE / sizeof(USHORT)); Index += 1) {
|
|
ChecksumBuffer[Index] = (USHORT)rand();
|
|
}
|
|
|
|
Source = (PUCHAR)&ChecksumBuffer[0];
|
|
Source += 1;
|
|
|
|
//
|
|
// Test if old and new get algorithms get the same checksum.
|
|
//
|
|
|
|
Sum1 = oldxsum(0, &ChecksumBuffer[0], CHECKSUM_BUFFER_SIZE);
|
|
Sum2 = tcpxsum(0, &ChecksumBuffer[0], CHECKSUM_BUFFER_SIZE);
|
|
Sum1 = (Sum1 >> 16) + (Sum1 & 0xffff);
|
|
Sum1 = ((Sum1 >> 16) + Sum1) & 0xffff;
|
|
if (Sum1 != Sum2) {
|
|
printf("Checksum 1 mismatch, sum1 = %lx, sum2 = %lx\n", Sum1, Sum2);
|
|
}
|
|
|
|
Sum1 = oldxsum(Sum1, Source, CHECKSUM_BUFFER_SIZE - 1);
|
|
Sum2 = tcpxsum(Sum2, Source, CHECKSUM_BUFFER_SIZE - 1);
|
|
Sum1 = (Sum1 >> 16) + (Sum1 & 0xffff);
|
|
Sum1 = ((Sum1 >> 16) + Sum1) & 0xffff;
|
|
if (Sum1 != Sum2) {
|
|
printf("Checksum 2 mismatch, sum1 = %lx, sum2 = %lx\n", Sum1, Sum2);
|
|
}
|
|
|
|
Sum1 = oldxsum(Sum1, Source, CHECKSUM_BUFFER_SIZE - 2);
|
|
Sum2 = tcpxsum(Sum2, Source, CHECKSUM_BUFFER_SIZE - 2);
|
|
Sum1 = (Sum1 >> 16) + (Sum1 & 0xffff);
|
|
Sum1 = ((Sum1 >> 16) + Sum1) & 0xffff;
|
|
if (Sum1 != Sum2) {
|
|
printf("Checksum 4 mismatch, sum1 = %lx, sum2 = %lx\n", Sum1, Sum2);
|
|
}
|
|
|
|
for (Index = (CHECKSUM_BUFFER_SIZE - 2); Index >= 2 ; Index -= 2) {
|
|
Sum1 = oldxsum(Sum1, Source, Index);
|
|
Sum2 = tcpxsum(Sum2, Source, Index);
|
|
Sum1 = (Sum1 >> 16) + (Sum1 & 0xffff);
|
|
Sum1 = ((Sum1 >> 16) + Sum1) & 0xffff;
|
|
if (Sum1 != Sum2) {
|
|
printf("Checksum 3 mismatch, size = %d sum1 = %lx, sum2 = %lx\n",
|
|
Index,
|
|
Sum1,
|
|
Sum2);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("New Checksum (aligned) Benchmark",
|
|
CHECKSUM_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly checksum buffers of varying sizes.
|
|
//
|
|
|
|
for (Count = 0; Count < CHECKSUM_ITERATIONS; Count += 1) {
|
|
for (Index = 1024; Index >= 2 ; Index -= 1) {
|
|
Sum2 = tcpxsum(Sum2, &ChecksumBuffer[0], Index);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("New Checksum (unaligned) Benchmark",
|
|
CHECKSUM_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly checksum buffers of varying sizes.
|
|
//
|
|
|
|
for (Count = 0; Count < CHECKSUM_ITERATIONS; Count += 1) {
|
|
for (Index = 1024; Index >= 2 ; Index -= 1) {
|
|
Sum2 = tcpxsum(Sum2, Source, Index);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("Old Checksum (aligned) Benchmark",
|
|
CHECKSUM_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly checksum buffers of varying sizes.
|
|
//
|
|
|
|
for (Count = 0; Count < CHECKSUM_ITERATIONS; Count += 1) {
|
|
for (Index = 1024; Index >= 2 ; Index -= 1) {
|
|
Sum1 = oldxsum(Sum1, &ChecksumBuffer[0], Index);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("Old Checksum (unaligned) Benchmark",
|
|
CHECKSUM_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly checksum buffers of varying sizes.
|
|
//
|
|
|
|
for (Count = 0; Count < CHECKSUM_ITERATIONS; Count += 1) {
|
|
for (Index = 1024; Index >= 2 ; Index -= 1) {
|
|
Sum2 = oldxsum(Sum2, Source, Index);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("Ip Checksum (aligned) Benchmark",
|
|
CHECKSUM_ITERATIONS / 2,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly checksum buffers of varying sizes.
|
|
//
|
|
|
|
for (Count = 0; Count < (CHECKSUM_ITERATIONS / 2); Count += 1) {
|
|
for (Index = 1024; Index >= 2 ; Index -= 1) {
|
|
Sum1 = xsum(&ChecksumBuffer[0], Index);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("Ip Checksum (unaligned) Benchmark",
|
|
CHECKSUM_ITERATIONS / 2,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly checksum buffers of varying sizes.
|
|
//
|
|
|
|
for (Count = 0; Count < (CHECKSUM_ITERATIONS / 2); Count += 1) {
|
|
for (Index = 1024; Index >= 2 ; Index -= 1) {
|
|
Sum2 = xsum(Source, Index);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("New Ip Header Checksum (aligned) Benchmark",
|
|
CHECKSUM_IP_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly checksum buffers of varying sizes.
|
|
//
|
|
|
|
for (Count = 0; Count < CHECKSUM_IP_ITERATIONS; Count += 1) {
|
|
Sum1 = tcpxsum(0, &ChecksumBuffer[0], 20);
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("New Ip Header Checksum (unaligned) Benchmark",
|
|
CHECKSUM_IP_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly checksum buffers of varying sizes.
|
|
//
|
|
|
|
for (Count = 0; Count < CHECKSUM_IP_ITERATIONS; Count += 1) {
|
|
Sum2 = tcpxsum(0, Source, 20);
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("Old Ip Header Checksum (aligned) Benchmark",
|
|
CHECKSUM_IP_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly checksum buffers of varying sizes.
|
|
//
|
|
|
|
for (Count = 0; Count < CHECKSUM_IP_ITERATIONS; Count += 1) {
|
|
Sum1 = xsum(&ChecksumBuffer[0], 20);
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("Old Ip Header Checksum (unaligned) Benchmark",
|
|
CHECKSUM_IP_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly checksum buffers of varying sizes.
|
|
//
|
|
|
|
for (Count = 0; Count < CHECKSUM_IP_ITERATIONS; Count += 1) {
|
|
Sum2 = xsum(Source, 20);
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
EventClearTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
HANDLE EventHandle;
|
|
LONG Index;
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Create an event for clear operations.
|
|
//
|
|
|
|
Status = NtCreateEvent(&EventHandle,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event object for clear test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("Clear Event Benchmark",
|
|
EVENT_CLEAR_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly clear an event.
|
|
//
|
|
|
|
for (Index = 0; Index < EVENT_RESET_ITERATIONS; Index += 1) {
|
|
Status = NtClearEvent(EventHandle);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Clear event bad status, %x\n", Status);
|
|
goto EndOfTest;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of clear event test.
|
|
//
|
|
|
|
EndOfTest:
|
|
ZwClose(EventHandle);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
EventCreationTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Event Creation Benchmark",
|
|
EVENT_CREATION_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Create an event and then close it.
|
|
//
|
|
|
|
for (Index = 0; Index < EVENT_CREATION_ITERATIONS; Index += 1) {
|
|
Status = NtCreateEvent(&EventHandle1,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event object for event creation test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
NtClose(EventHandle1);
|
|
}
|
|
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of event creation test.
|
|
//
|
|
|
|
EndOfTest:
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
EventOpenTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
ANSI_STRING EventName;
|
|
ULONG Index;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING UnicodeEventName;
|
|
|
|
//
|
|
// Create a named event for event open test.
|
|
//
|
|
|
|
RtlInitAnsiString(&EventName, "\\BaseNamedObjects\\EventOpenName");
|
|
Status = RtlAnsiStringToUnicodeString(&UnicodeEventName,
|
|
&EventName,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create UNICODE string for event open test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeEventName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtCreateEvent(&EventHandle1,
|
|
DESIRED_EVENT_ACCESS,
|
|
&ObjectAttributes,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event object for event open test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Event Open Benchmark",
|
|
EVENT_OPEN_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Open a named event and then close it.
|
|
//
|
|
|
|
for (Index = 0; Index < EVENT_OPEN_ITERATIONS; Index += 1) {
|
|
Status = NtOpenEvent(&EventHandle2,
|
|
EVENT_QUERY_STATE | EVENT_MODIFY_STATE | SYNCHRONIZE,
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to open event for open event test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
NtClose(EventHandle2);
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of event open test.
|
|
//
|
|
|
|
EndOfTest:
|
|
NtClose(EventHandle1);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
EventQueryTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
HANDLE EventHandle;
|
|
EVENT_BASIC_INFORMATION EventInformation;
|
|
LONG Index;
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Create an event for query operations.
|
|
//
|
|
|
|
Status = NtCreateEvent(&EventHandle,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event object for query test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("Query Event Benchmark",
|
|
EVENT_QUERY_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly query an event.
|
|
//
|
|
|
|
for (Index = 0; Index < EVENT_QUERY_ITERATIONS; Index += 1) {
|
|
Status = NtQueryEvent(EventHandle,
|
|
EventBasicInformation,
|
|
&EventInformation,
|
|
sizeof(EVENT_BASIC_INFORMATION),
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Query event bad status, %x\n", Status);
|
|
goto EndOfTest;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of query event test.
|
|
//
|
|
|
|
EndOfTest:
|
|
ZwClose(EventHandle);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
EventResetTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
HANDLE EventHandle;
|
|
LONG Index;
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Create an event for reset operations.
|
|
//
|
|
|
|
Status = NtCreateEvent(&EventHandle,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event object for reset test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("Reset Event Benchmark",
|
|
EVENT_RESET_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly reset an event.
|
|
//
|
|
|
|
for (Index = 0; Index < EVENT_RESET_ITERATIONS; Index += 1) {
|
|
Status = NtResetEvent(EventHandle,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Reset event bad status, %x\n", Status);
|
|
goto EndOfTest;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of reset event test.
|
|
//
|
|
|
|
EndOfTest:
|
|
ZwClose(EventHandle);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
Event1SwitchTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
HANDLE WaitObjects[2];
|
|
|
|
//
|
|
// Create two event objects for the event1 context switch test.
|
|
//
|
|
|
|
Status = NtCreateEvent(&EventHandle1,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event1 object for context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtCreateEvent(&EventHandle2,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event1 object for context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Create the thread objects to execute the test.
|
|
//
|
|
|
|
Status = CreateThread(&Thread1Handle,
|
|
Event1Thread1,
|
|
LOW_REALTIME_PRIORITY - 2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create first thread event1 context switch test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = CreateThread(&Thread2Handle,
|
|
Event1Thread2,
|
|
LOW_REALTIME_PRIORITY - 2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create second thread event1 context switch test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Initialize the wait objects array.
|
|
//
|
|
|
|
WaitObjects[0] = Thread1Handle;
|
|
WaitObjects[1] = Thread2Handle;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Event (synchronization) Context Switch Benchmark (Round Trips)",
|
|
EVENT1_SWITCHES,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Set event and wait for threads to terminate.
|
|
//
|
|
|
|
Status = NtSetEvent(EventHandle1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to set event event1 context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtWaitForMultipleObjects(2,
|
|
WaitObjects,
|
|
WaitAll,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to wait event1 context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of event1 context switch test.
|
|
//
|
|
|
|
EndOfTest:
|
|
NtClose(EventHandle1);
|
|
NtClose(EventHandle2);
|
|
NtClose(Thread1Handle);
|
|
NtClose(Thread2Handle);
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
Event1Thread1 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for event 1 and then set event 2.
|
|
//
|
|
|
|
for (Index = 0; Index < EVENT1_SWITCHES; Index += 1) {
|
|
Status = NtWaitForSingleObject(EventHandle1,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread1 event1 test bad wait status, %x\n", Status);
|
|
break;
|
|
}
|
|
|
|
Status = NtSetEvent(EventHandle2, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread1 event1 test bad set status, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
|
|
NtTerminateThread(Thread1Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
Event1Thread2 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for event 2 and then set event 1.
|
|
//
|
|
|
|
for (Index = 0; Index < EVENT1_SWITCHES; Index += 1) {
|
|
Status = NtWaitForSingleObject(EventHandle2,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread2 event1 test bad wait status, %x\n", Status);
|
|
break;
|
|
}
|
|
|
|
Status = NtSetEvent(EventHandle1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread2 event1 test bad set status, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
|
|
NtTerminateThread(Thread2Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
Event2SwitchTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
PVOID WaitObjects[2];
|
|
|
|
//
|
|
// Create two event objects for the event2 context switch test.
|
|
//
|
|
|
|
Status = NtCreateEvent(&EventHandle1,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event2 object for context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtCreateEvent(&EventHandle2,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event2 object for context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Create the thread objects to execute the test.
|
|
//
|
|
|
|
Status = CreateThread(&Thread1Handle,
|
|
Event2Thread1,
|
|
LOW_REALTIME_PRIORITY - 2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create first thread event2 context switch test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = CreateThread(&Thread2Handle,
|
|
Event2Thread2,
|
|
LOW_REALTIME_PRIORITY - 2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create second thread event2 context switch test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Initialize the wait objects array.
|
|
//
|
|
|
|
WaitObjects[0] = Thread1Handle;
|
|
WaitObjects[1] = Thread2Handle;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Event (notification) Context Switch Benchmark (Round Trips)",
|
|
EVENT2_SWITCHES,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Set event and wait for threads to terminate.
|
|
//
|
|
|
|
Status = NtSetEvent(EventHandle1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to set event2 object for context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtWaitForMultipleObjects(2,
|
|
WaitObjects,
|
|
WaitAll,
|
|
FALSE,
|
|
NULL);
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of event2 context switch test.
|
|
//
|
|
|
|
EndOfTest:
|
|
NtClose(EventHandle1);
|
|
NtClose(EventHandle2);
|
|
NtClose(Thread1Handle);
|
|
NtClose(Thread2Handle);
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
Event2Thread1 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for event 1, reset event 1, and then set event 2.
|
|
//
|
|
|
|
for (Index = 0; Index < EVENT2_SWITCHES; Index += 1) {
|
|
Status = NtWaitForSingleObject(EventHandle1, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread1 event2 test bad wait status, %x\n", Status);
|
|
break;
|
|
}
|
|
|
|
Status = NtResetEvent(EventHandle1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread1 event2 test bad reset status, %x\n", Status);
|
|
break;
|
|
}
|
|
|
|
Status = NtSetEvent(EventHandle2, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread1 event2 test bad set status, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
|
|
NtTerminateThread(Thread1Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
Event2Thread2 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for event 2, reset event 2, and then set event 1.
|
|
//
|
|
|
|
for (Index = 0; Index < EVENT2_SWITCHES; Index += 1) {
|
|
Status = NtWaitForSingleObject(EventHandle2, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread2 event2 test bad wait status, %x\n", Status);
|
|
break;
|
|
}
|
|
|
|
Status = NtResetEvent(EventHandle2, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread1 event2 test bad reset status, %x\n", Status);
|
|
break;
|
|
}
|
|
|
|
Status = NtSetEvent(EventHandle1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread2 event2 test bad set status, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
|
|
NtTerminateThread(Thread2Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
Event3SwitchTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
PVOID WaitObjects[2];
|
|
|
|
//
|
|
// Create an event pair object for the event3 context switch test.
|
|
//
|
|
|
|
Status = NtCreateEventPair(&EventPairHandle,
|
|
EVENT_PAIR_ALL_ACCESS,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event3 object for context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Create the thread objects to execute the test.
|
|
//
|
|
|
|
Status = CreateThread(&Thread1Handle,
|
|
Event3Thread1,
|
|
LOW_REALTIME_PRIORITY - 2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create first thread event3 context switch test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = CreateThread(&Thread2Handle,
|
|
Event3Thread2,
|
|
LOW_REALTIME_PRIORITY - 2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create second thread event3 context switch test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Set the client/server event pair object for thread1.
|
|
//
|
|
|
|
Status = NtSetInformationThread(Thread1Handle,
|
|
ThreadEventPair,
|
|
&EventPairHandle,
|
|
sizeof(HANDLE));
|
|
|
|
// if (!NT_SUCCESS(Status)) {
|
|
// printf("Failed to set client/server event pair handle thread 1\n");
|
|
// goto EndOfTest;
|
|
// }
|
|
|
|
//
|
|
// Set the client/server event pair object for thread2.
|
|
//
|
|
|
|
Status = NtSetInformationThread(Thread2Handle,
|
|
ThreadEventPair,
|
|
&EventPairHandle,
|
|
sizeof(HANDLE));
|
|
|
|
// if (!NT_SUCCESS(Status)) {
|
|
// printf("Failed to set client/server event pair handle thread 2\n");
|
|
// goto EndOfTest;
|
|
// }
|
|
|
|
//
|
|
// Initialize the wait objects array.
|
|
//
|
|
|
|
WaitObjects[0] = Thread1Handle;
|
|
WaitObjects[1] = Thread2Handle;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Event (pair) Context Switch Benchmark (Round Trips)",
|
|
EVENT3_SWITCHES,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Set event and wait for threads to terminate.
|
|
//
|
|
|
|
Status = NtSetLowEventPair(EventPairHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to set event3 object for context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtWaitForMultipleObjects(2,
|
|
WaitObjects,
|
|
WaitAll,
|
|
FALSE,
|
|
NULL);
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of event3 context switch test.
|
|
//
|
|
|
|
EndOfTest:
|
|
NtClose(EventPairHandle);
|
|
NtClose(Thread1Handle);
|
|
NtClose(Thread2Handle);
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
Event3Thread1 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for low event before entering loop.
|
|
//
|
|
|
|
Status = NtWaitLowEventPair(EventPairHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread1 event3 test bad wait status, %x\n", Status);
|
|
NtTerminateThread(Thread1Handle, Status);
|
|
}
|
|
|
|
//
|
|
// Set high event and wait for low event.
|
|
//
|
|
|
|
for (Index = 0; Index < EVENT3_SWITCHES; Index += 1) {
|
|
Status = NtSetHighWaitLowThread();
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread1 event3 test bad wait status, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Status = NtSetHighEventPair(EventPairHandle);
|
|
NtTerminateThread(Thread1Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
Event3Thread2 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for high event before entering loop.
|
|
//
|
|
|
|
Status = NtWaitHighEventPair(EventPairHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread2 event3 test bad wait status, %x\n", Status);
|
|
NtTerminateThread(Thread2Handle, Status);
|
|
}
|
|
|
|
//
|
|
// Set low event and wait for high event.
|
|
//
|
|
|
|
for (Index = 0; Index < EVENT3_SWITCHES; Index += 1) {
|
|
Status = NtSetLowWaitHighThread();
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread2 event3 test bad wait status, %x\n", Status);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
Status = NtSetLowEventPair(EventPairHandle);
|
|
NtTerminateThread(Thread2Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
Event4SwitchTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
PVOID WaitObjects[2];
|
|
|
|
//
|
|
// Create two event objects for the event1 context switch test.
|
|
//
|
|
|
|
Status = NtCreateEvent(&EventHandle1,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("EVENT4: Failed to create event1 object for context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtCreateEvent(&EventHandle2,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
SynchronizationEvent,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("EVENT4: Failed to create event2 object for context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Create the thread objects to execute the test.
|
|
//
|
|
|
|
Status = CreateThread(&Thread1Handle,
|
|
Event4Thread1,
|
|
LOW_REALTIME_PRIORITY - 2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("EVENT4: Failed to create first thread event4 context switch test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = CreateThread(&Thread2Handle,
|
|
Event4Thread2,
|
|
LOW_REALTIME_PRIORITY - 2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("EVENT4: Failed to create second thread event3 context switch test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Initialize the wait objects array.
|
|
//
|
|
|
|
WaitObjects[0] = Thread1Handle;
|
|
WaitObjects[1] = Thread2Handle;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Event (signal/wait) Context Switch Benchmark (Round Trips)",
|
|
EVENT4_SWITCHES,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Set event and wait for threads to terminate.
|
|
//
|
|
|
|
Status = NtSetEvent(EventHandle1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("EVENT4: Failed to set event event1 context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtWaitForMultipleObjects(2,
|
|
WaitObjects,
|
|
WaitAll,
|
|
FALSE,
|
|
NULL);
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of event3 context switch test.
|
|
//
|
|
|
|
EndOfTest:
|
|
NtClose(EventHandle1);
|
|
NtClose(EventHandle2);
|
|
NtClose(Thread1Handle);
|
|
NtClose(Thread2Handle);
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
Event4Thread1 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for event 1 and then enter signal/wait loop.
|
|
//
|
|
|
|
Status = NtWaitForSingleObject(EventHandle1,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("EVENT4: Thread1 initial wait failed, %x\n", Status);
|
|
|
|
} else {
|
|
for (Index = 0; Index < EVENT4_SWITCHES; Index += 1) {
|
|
Status = NtSignalAndWaitForSingleObject(EventHandle2,
|
|
EventHandle1,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("EVENT4: Thread1 signal/wait failed, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = NtSetEvent(EventHandle2, NULL);
|
|
NtTerminateThread(Thread1Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
Event4Thread2 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for event 1 and then enter signal/wait loop.
|
|
//
|
|
|
|
Status = NtWaitForSingleObject(EventHandle2,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("EVENT4: Thread2 initial wait failed, %x\n", Status);
|
|
|
|
} else {
|
|
for (Index = 0; Index < EVENT4_SWITCHES; Index += 1) {
|
|
Status = NtSignalAndWaitForSingleObject(EventHandle1,
|
|
EventHandle2,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("EVENT4: Thread2 signal/wait failed, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
NtTerminateThread(Thread2Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
Io1Test (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Buffer[128];
|
|
HANDLE DeviceHandle;
|
|
ANSI_STRING AnsiName;
|
|
HANDLE EventHandle;
|
|
LARGE_INTEGER FileAddress;
|
|
LONG Index;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER SystemTime;
|
|
UNICODE_STRING UnicodeName;
|
|
|
|
//
|
|
// Create an event for synchronization of I/O operations.
|
|
//
|
|
|
|
Status = NtCreateEvent(&EventHandle,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event object for I/O test 1\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Open device object for I/O operations.
|
|
//
|
|
|
|
RtlInitString(&AnsiName, "\\Device\\Null");
|
|
Status = RtlAnsiStringToUnicodeString(&UnicodeName,
|
|
&AnsiName,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to convert device name to unicode for I/O test 1\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UnicodeName,
|
|
0,
|
|
(HANDLE)0,
|
|
NULL);
|
|
|
|
Status = NtOpenFile(&DeviceHandle,
|
|
FILE_READ_DATA | FILE_WRITE_DATA,
|
|
&ObjectAttributes,
|
|
&IoStatus,
|
|
0,
|
|
0);
|
|
|
|
RtlFreeUnicodeString(&UnicodeName);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to open device I/O test 1, status = %lx\n", Status);
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Initialize file address parameter.
|
|
//
|
|
|
|
FileAddress.LowPart = 0;
|
|
FileAddress.HighPart = 0;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("I/O Benchmark for Synchronous Null Device",
|
|
IO_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly write data to null device.
|
|
//
|
|
|
|
for (Index = 0; Index < IO_ITERATIONS; Index += 1) {
|
|
Status = NtWriteFile(DeviceHandle,
|
|
EventHandle,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
Buffer,
|
|
512,
|
|
&FileAddress,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Failed to write device I/O test 1, status = %lx\n",
|
|
Status);
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtWaitForSingleObject(EventHandle, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" I/O test 1 bad wait status, %x\n", Status);
|
|
goto EndOfTest;
|
|
}
|
|
|
|
if (NT_SUCCESS(IoStatus.Status) == FALSE) {
|
|
printf(" I/O test 1 bad I/O status, %x\n", Status);
|
|
goto EndOfTest;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of I/O test 1.
|
|
//
|
|
|
|
EndOfTest:
|
|
ZwClose(DeviceHandle);
|
|
ZwClose(EventHandle);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
MutantSwitchTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
HANDLE WaitObjects[2];
|
|
|
|
//
|
|
// Create a mutant object for the mutant context switch test.
|
|
//
|
|
|
|
Status = NtCreateMutant(&MutantHandle, MUTANT_ALL_ACCESS, NULL, TRUE);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create mutant object for context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Create the thread objects to execute the test.
|
|
//
|
|
|
|
Status = CreateThread(&Thread1Handle,
|
|
MutantThread1,
|
|
LOW_REALTIME_PRIORITY + 11);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create first thread mutant context switch test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = CreateThread(&Thread2Handle,
|
|
MutantThread2,
|
|
LOW_REALTIME_PRIORITY + 11);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create second thread mutant context switch test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Initialize the wait objects array.
|
|
//
|
|
|
|
WaitObjects[0] = Thread1Handle;
|
|
WaitObjects[1] = Thread2Handle;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Mutant Context Switch Benchmark (Round Trips)",
|
|
MUTANT_SWITCHES,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Release mutant and wait for threads to terminate.
|
|
//
|
|
|
|
Status = NtReleaseMutant(MutantHandle, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to release mutant object for context switch test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtWaitForMultipleObjects(2,
|
|
WaitObjects,
|
|
WaitAll,
|
|
FALSE,
|
|
NULL);
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of mutant context switch test.
|
|
//
|
|
|
|
EndOfTest:
|
|
NtClose(MutantHandle);
|
|
NtClose(Thread1Handle);
|
|
NtClose(Thread2Handle);
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
MutantThread1 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for mutant and then release mutant.
|
|
//
|
|
|
|
for (Index = 0; Index < MUTANT_SWITCHES; Index += 1) {
|
|
Status = NtWaitForSingleObject(MutantHandle, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread1 mutant test bad wait status, %x\n", Status);
|
|
break;
|
|
}
|
|
Status = NtReleaseMutant(MutantHandle, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread1 mutant test bad release status, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
|
|
NtTerminateThread(Thread1Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
MutantThread2 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for mutant and then release mutant.
|
|
//
|
|
|
|
for (Index = 0; Index < MUTANT_SWITCHES; Index += 1) {
|
|
Status = NtWaitForSingleObject(MutantHandle, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread2 mutant test bad wait status, %x\n", Status);
|
|
break;
|
|
}
|
|
Status = NtReleaseMutant(MutantHandle, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Thread2 mutant test bad release status, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
|
|
NtTerminateThread(Thread2Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
Semaphore1SwitchTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
HANDLE WaitObjects[2];
|
|
|
|
//
|
|
// Create two semaphore objects for the semaphore1 context switch test.
|
|
//
|
|
|
|
Status = NtCreateSemaphore(&SemaphoreHandle1,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
0,
|
|
1);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE1: Failed to create semaphore1 object.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtCreateSemaphore(&SemaphoreHandle2,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
0,
|
|
1);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE1: Failed to create semaphore2 object.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Create the thread objects to execute the test.
|
|
//
|
|
|
|
Status = CreateThread(&Thread1Handle,
|
|
Semaphore1Thread1,
|
|
LOW_REALTIME_PRIORITY - 2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE1: Failed to create thread1 object.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = CreateThread(&Thread2Handle,
|
|
Semaphore1Thread2,
|
|
LOW_REALTIME_PRIORITY - 2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE1: Failed to create thread2 object.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Initialize the wait objects array.
|
|
//
|
|
|
|
WaitObjects[0] = Thread1Handle;
|
|
WaitObjects[1] = Thread2Handle;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Semaphore (release/wait) Context Switch Benchmark (Round Trips)",
|
|
SEMAPHORE1_SWITCHES,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Release semaphore and wait for threads to terminate.
|
|
//
|
|
|
|
Status = NtReleaseSemaphore(SemaphoreHandle1, 1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE1: Failed to release semaphore1 at start of test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtWaitForMultipleObjects(2,
|
|
WaitObjects,
|
|
WaitAll,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE1: Failed to wait for threads.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of semaphore1 context switch test.
|
|
//
|
|
|
|
EndOfTest:
|
|
NtClose(SemaphoreHandle1);
|
|
NtClose(SemaphoreHandle2);
|
|
NtClose(Thread1Handle);
|
|
NtClose(Thread2Handle);
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
Semaphore1Thread1 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for semaphore 1 and then release semaphore 2.
|
|
//
|
|
|
|
for (Index = 0; Index < SEMAPHORE1_SWITCHES; Index += 1) {
|
|
Status = NtWaitForSingleObject(SemaphoreHandle1,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE1: Thread1 bad wait status, %x\n", Status);
|
|
break;
|
|
}
|
|
|
|
Status = NtReleaseSemaphore(SemaphoreHandle2, 1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE1: Thread1 bad release status, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
|
|
NtTerminateThread(Thread1Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
Semaphore1Thread2 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for semaphore 2 and then release semaphore 1.
|
|
//
|
|
|
|
for (Index = 0; Index < SEMAPHORE1_SWITCHES; Index += 1) {
|
|
Status = NtWaitForSingleObject(SemaphoreHandle2,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE1: Thread2 bad wait status, %x\n", Status);
|
|
break;
|
|
}
|
|
|
|
Status = NtReleaseSemaphore(SemaphoreHandle1, 1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE1: Thread2 bad release status, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
|
|
NtTerminateThread(Thread2Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
Semaphore2SwitchTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
HANDLE WaitObjects[2];
|
|
|
|
//
|
|
// Create two semaphore objects for the semaphore1 context switch test.
|
|
//
|
|
|
|
Status = NtCreateSemaphore(&SemaphoreHandle1,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
0,
|
|
1);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE2: Failed to create semaphore1 object.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtCreateSemaphore(&SemaphoreHandle2,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
0,
|
|
1);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE2: Failed to create semaphore2 object.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Create the thread objects to execute the test.
|
|
//
|
|
|
|
Status = CreateThread(&Thread1Handle,
|
|
Semaphore2Thread1,
|
|
LOW_REALTIME_PRIORITY - 2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE2: Failed to create thread1 object.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = CreateThread(&Thread2Handle,
|
|
Semaphore2Thread2,
|
|
LOW_REALTIME_PRIORITY - 2);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE2: Failed to create thread2 object.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Initialize the wait objects array.
|
|
//
|
|
|
|
WaitObjects[0] = Thread1Handle;
|
|
WaitObjects[1] = Thread2Handle;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Semaphore (signal/wait) Context Switch Benchmark (Round Trips)",
|
|
SEMAPHORE2_SWITCHES,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Release semaphore and wait for threads to terminate.
|
|
//
|
|
|
|
Status = NtReleaseSemaphore(SemaphoreHandle1, 1, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE2: Failed to release semaphore1 at start of test.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtWaitForMultipleObjects(2,
|
|
WaitObjects,
|
|
WaitAll,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE2: Failed to wait for threads.\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of semaphore 2 context switch test.
|
|
//
|
|
|
|
EndOfTest:
|
|
NtClose(SemaphoreHandle1);
|
|
NtClose(SemaphoreHandle2);
|
|
NtClose(Thread1Handle);
|
|
NtClose(Thread2Handle);
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
Semaphore2Thread1 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for semaphore 1 and then enter signal/wait loop.
|
|
//
|
|
|
|
Status = NtWaitForSingleObject(SemaphoreHandle1,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE2: Thread1 initial wait failed, %x\n", Status);
|
|
|
|
} else {
|
|
for (Index = 0; Index < SEMAPHORE2_SWITCHES; Index += 1) {
|
|
Status = NtSignalAndWaitForSingleObject(SemaphoreHandle2,
|
|
SemaphoreHandle1,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE2: Thread1 signal/wait failed, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = NtReleaseSemaphore(SemaphoreHandle2, 1, NULL);
|
|
NtTerminateThread(Thread1Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
NTSTATUS
|
|
Semaphore2Thread2 (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Wait for semaphore 2 and then enter signal/wait loop.
|
|
//
|
|
|
|
Status = NtWaitForSingleObject(SemaphoreHandle2,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE2: Thread2 initial wait failed, %x\n", Status);
|
|
|
|
} else {
|
|
for (Index = 0; Index < SEMAPHORE2_SWITCHES; Index += 1) {
|
|
Status = NtSignalAndWaitForSingleObject(SemaphoreHandle1,
|
|
SemaphoreHandle2,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("SEMAPHORE2: Thread2 signal/wait failed, %x\n", Status);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
NtTerminateThread(Thread2Handle, STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
SlistTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
SINGLE_LIST_ENTRY Entry;
|
|
SLIST_HEADER SListHead;
|
|
ULONG Index;
|
|
PERFINFO PerfInfo;
|
|
LARGE_INTEGER SystemTime;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("S-List Benchmark",
|
|
SLIST_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly call a short system service.
|
|
//
|
|
|
|
InitializeSListHead(&SListHead);
|
|
for (Index = 0; Index < SLIST_ITERATIONS; Index += 1) {
|
|
InterlockedPushEntrySList(&SListHead, &Entry);
|
|
if (InterlockedPopEntrySList(&SListHead) != (PVOID)&Entry) {
|
|
printf("SLIST: Entry does match %lx\n", Entry);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
SystemCallTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
ULONG Index;
|
|
PERFINFO PerfInfo;
|
|
LARGE_INTEGER SystemTime;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("System Call Benchmark (NtQuerySystemTime)",
|
|
SYSCALL_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly call a short system service.
|
|
//
|
|
|
|
for (Index = 0; Index < SYSCALL_ITERATIONS; Index += 1) {
|
|
NtQuerySystemTime(&SystemTime);
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
TimerIndexTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
#if defined(_MIPS_)
|
|
|
|
ULONG Count;
|
|
LARGE_INTEGER CurrentTime;
|
|
LONG Index1;
|
|
LONG Index2;
|
|
PERFINFO PerfInfo;
|
|
LARGE_INTEGER Interval;
|
|
ULONGLONG Result1;
|
|
ULONGLONG Result2;
|
|
|
|
//
|
|
// Test if old and new timer index algorithms get the same index and
|
|
// due time.
|
|
//
|
|
|
|
printf("*** Start timer index verification\n");
|
|
CurrentTime.QuadPart = 0x7fff000;
|
|
Interval.QuadPart = -1;
|
|
for (Count = 0; Count < 10000000 ; Count += 1) {
|
|
Index1 = ComputeTimerTableIndex32(Interval, CurrentTime, &Result1);
|
|
Index2 = ComputeTimerTableIndex64(Interval, CurrentTime, &Result2);
|
|
if (Result1 != Result2) {
|
|
printf(" Timer result mismatch result1 = %lx%0lx result2 = %ls%0lx\n",
|
|
(ULONG)Result1,
|
|
(ULONG)(Result1 >> 32),
|
|
(ULONG)Result2,
|
|
(ULONG)(Result2 >> 32));
|
|
}
|
|
|
|
if (Index1 != Index2) {
|
|
printf(" Timer index mismatch index1 = %d index2 = %d\n",
|
|
Index1,
|
|
Index2);
|
|
}
|
|
|
|
Interval.QuadPart -= 100000;
|
|
CurrentTime.QuadPart += 10000;
|
|
}
|
|
|
|
printf("*** End timer index verification\n");
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("Old Timer Index Computation Benchmark",
|
|
TIMER_INDEX_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly compute the timer index.
|
|
//
|
|
|
|
for (Count = 0; Count < TIMER_INDEX_ITERATIONS; Count += 1) {
|
|
Index1 = ComputeTimerTableIndex32(Interval, CurrentTime, &Result1);
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parameters.
|
|
//
|
|
|
|
StartBenchMark("New Timer Index Computation Benchmark",
|
|
TIMER_INDEX_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly compute the timer index.
|
|
//
|
|
|
|
for (Count = 0; Count < TIMER_INDEX_ITERATIONS; Count += 1) {
|
|
Index1 = ComputeTimerTableIndex64(Interval, CurrentTime, &Result1);
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
TimerOperationTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
LARGE_INTEGER DueTime;
|
|
HANDLE Handle;
|
|
ULONG Index;
|
|
PERFINFO PerfInfo;
|
|
LARGE_INTEGER SystemTime;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Timer Operation Benchmark (NtSet/CancelTimer)",
|
|
TIMER_OPERATION_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Create a timer object for use in the test.
|
|
//
|
|
|
|
Status = NtCreateTimer(&Handle,
|
|
TIMER_ALL_ACCESS,
|
|
NULL,
|
|
NotificationTimer);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create timer during initialization\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Repeatedly set and cancel a timer.
|
|
//
|
|
|
|
DueTime = RtlConvertLongToLargeInteger(- 100 * 1000 * 10);
|
|
for (Index = 0; Index < TIMER_OPERATION_ITERATIONS; Index += 1) {
|
|
NtSetTimer(Handle, &DueTime, NULL, NULL, FALSE, 0, NULL);
|
|
NtCancelTimer(Handle, NULL);
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
EndOfTest:
|
|
FinishBenchMark(&PerfInfo);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
WaitSingleTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
HANDLE EventHandle;
|
|
LONG Index;
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Create an event for synchronization of wait single operations.
|
|
//
|
|
|
|
Status = NtCreateEvent(&EventHandle,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event object for wait single test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Wait Single Benchmark",
|
|
WAIT_SINGLE_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly wait for a single event.
|
|
//
|
|
|
|
for (Index = 0; Index < WAIT_SINGLE_ITERATIONS; Index += 1) {
|
|
Status = NtWaitForSingleObject(EventHandle, FALSE, NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Wait single bad wait status, %x\n", Status);
|
|
goto EndOfTest;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of Wait Single Test.
|
|
//
|
|
|
|
EndOfTest:
|
|
ZwClose(EventHandle);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
WaitMultipleTest (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
HANDLE Event1Handle;
|
|
HANDLE Event2Handle;
|
|
HANDLE WaitObjects[2];
|
|
LONG Index;
|
|
PERFINFO PerfInfo;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Create two events for synchronization of wait multiple operations.
|
|
//
|
|
|
|
Status = NtCreateEvent(&Event1Handle,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event object 1 for wait multiple test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
Status = NtCreateEvent(&Event2Handle,
|
|
DESIRED_EVENT_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to create event object 2 for wait multiple test\n");
|
|
goto EndOfTest;
|
|
}
|
|
|
|
//
|
|
// Announce start of benchmark and capture performance parmeters.
|
|
//
|
|
|
|
StartBenchMark("Wait Multiple Benchmark",
|
|
WAIT_MULTIPLE_ITERATIONS,
|
|
&PerfInfo);
|
|
|
|
//
|
|
// Repeatedly wait for a multiple events.
|
|
//
|
|
|
|
WaitObjects[0] = Event1Handle;
|
|
WaitObjects[1] = Event2Handle;
|
|
for (Index = 0; Index < WAIT_SINGLE_ITERATIONS; Index += 1) {
|
|
Status = NtWaitForMultipleObjects(2,
|
|
WaitObjects,
|
|
WaitAny,
|
|
FALSE,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf(" Wait multiple bad wait status, %x\n", Status);
|
|
goto EndOfTest;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print out performance statistics.
|
|
//
|
|
|
|
FinishBenchMark(&PerfInfo);
|
|
|
|
//
|
|
// End of Wait Multiple Test.
|
|
//
|
|
|
|
EndOfTest:
|
|
ZwClose(Event1Handle);
|
|
ZwClose(Event2Handle);
|
|
return;
|
|
}
|
|
|
|
NTSTATUS
|
|
TimerThread (
|
|
IN PVOID Context
|
|
)
|
|
|
|
{
|
|
|
|
LARGE_INTEGER DueTime;
|
|
NTSTATUS Status;
|
|
HANDLE WaitObjects[2];
|
|
|
|
//
|
|
// Initialize variables and loop until the timer event is set.
|
|
//
|
|
|
|
DueTime.LowPart = -(5 * 1000 * 1000);
|
|
DueTime.HighPart = -1;
|
|
|
|
WaitObjects[0] = TimerEventHandle;
|
|
WaitObjects[1] = TimerTimerHandle;
|
|
|
|
do {
|
|
Status = NtSetTimer(TimerTimerHandle,
|
|
&DueTime,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
0,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
break;
|
|
}
|
|
|
|
Status = NtWaitForMultipleObjects(2,
|
|
WaitObjects,
|
|
WaitAny,
|
|
FALSE,
|
|
NULL);
|
|
|
|
} while (Status != STATUS_SUCCESS);
|
|
|
|
NtTerminateThread(TimerThreadHandle, Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
CreateThread (
|
|
OUT PHANDLE Handle,
|
|
IN PUSER_THREAD_START_ROUTINE StartRoutine,
|
|
IN KPRIORITY Priority
|
|
)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Create a thread in the suspended state, sets its priority, and then
|
|
// resume the thread.
|
|
//
|
|
|
|
Status = RtlCreateUserThread(NtCurrentProcess(),
|
|
NULL,
|
|
TRUE,
|
|
0,
|
|
0,
|
|
0,
|
|
StartRoutine,
|
|
NULL,
|
|
Handle,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = NtSetInformationThread(*Handle,
|
|
ThreadPriority,
|
|
&Priority,
|
|
sizeof(KPRIORITY));
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(*Handle);
|
|
return Status;
|
|
}
|
|
|
|
Status = NtResumeThread(*Handle,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtClose(*Handle);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
FinishBenchMark (
|
|
IN PPERFINFO PerfInfo
|
|
)
|
|
|
|
{
|
|
|
|
ULONG ContextSwitches;
|
|
LARGE_INTEGER Duration;
|
|
ULONG FirstLevelFills;
|
|
ULONG InterruptCount;
|
|
ULONG Length;
|
|
ULONG Performance;
|
|
ULONG Remainder;
|
|
ULONG SecondLevelFills;
|
|
NTSTATUS Status;
|
|
ULONG SystemCalls;
|
|
SYSTEM_PERFORMANCE_INFORMATION SystemInfo;
|
|
LARGE_INTEGER TotalCycles;
|
|
|
|
|
|
//
|
|
// Print results and announce end of test.
|
|
//
|
|
|
|
NtQuerySystemTime((PLARGE_INTEGER)&PerfInfo->StopTime);
|
|
Status = NtQueryInformationThread(NtCurrentThread(),
|
|
ThreadPerformanceCount,
|
|
&PerfInfo->StopCycles,
|
|
sizeof(LARGE_INTEGER),
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to query performance count, status = %lx\n", Status);
|
|
return;
|
|
}
|
|
|
|
Status = NtQuerySystemInformation(SystemPerformanceInformation,
|
|
(PVOID)&SystemInfo,
|
|
sizeof(SYSTEM_PERFORMANCE_INFORMATION),
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to query performance information, status = %lx\n", Status);
|
|
return;
|
|
}
|
|
|
|
Duration.QuadPart = PerfInfo->StopTime.QuadPart - PerfInfo->StartTime.QuadPart;
|
|
Length = Duration.LowPart / 10000;
|
|
TotalCycles.QuadPart = PerfInfo->StopCycles.QuadPart - PerfInfo->StartCycles.QuadPart;
|
|
TotalCycles = RtlExtendedLargeIntegerDivide(TotalCycles,
|
|
PerfInfo->Iterations,
|
|
&Remainder);
|
|
|
|
printf(" Test time in milliseconds %d\n", Length);
|
|
printf(" Number of iterations %d\n", PerfInfo->Iterations);
|
|
printf(" Cycles per iteration %d\n", TotalCycles.LowPart);
|
|
|
|
Performance = PerfInfo->Iterations * 1000 / Length;
|
|
printf(" Iterations per second %d\n", Performance);
|
|
|
|
ContextSwitches = SystemInfo.ContextSwitches - PerfInfo->ContextSwitches;
|
|
FirstLevelFills = SystemInfo.FirstLevelTbFills - PerfInfo->FirstLevelFills;
|
|
// InterruptCount = SystemInfo.InterruptCount - PerfInfo->InterruptCount;
|
|
SecondLevelFills = SystemInfo.SecondLevelTbFills - PerfInfo->SecondLevelFills;
|
|
SystemCalls = SystemInfo.SystemCalls - PerfInfo->SystemCalls;
|
|
printf(" First Level TB Fills %d\n", FirstLevelFills);
|
|
printf(" Second Level TB Fills %d\n", SecondLevelFills);
|
|
// printf(" Number of Interrupts %d\n", InterruptCount);
|
|
printf(" Total Context Switches %d\n", ContextSwitches);
|
|
printf(" Number of System Calls %d\n", SystemCalls);
|
|
|
|
printf("*** End of Test ***\n\n");
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
StartBenchMark (
|
|
IN PCHAR Title,
|
|
IN ULONG Iterations,
|
|
IN PPERFINFO PerfInfo
|
|
)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
SYSTEM_PERFORMANCE_INFORMATION SystemInfo;
|
|
|
|
//
|
|
// Announce start of test and the number of iterations.
|
|
//
|
|
|
|
printf("*** Start of test ***\n %s\n", Title);
|
|
PerfInfo->Title = Title;
|
|
PerfInfo->Iterations = Iterations;
|
|
NtQuerySystemTime((PLARGE_INTEGER)&PerfInfo->StartTime);
|
|
Status = NtQueryInformationThread(NtCurrentThread(),
|
|
ThreadPerformanceCount,
|
|
&PerfInfo->StartCycles,
|
|
sizeof(LARGE_INTEGER),
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to query performance count, status = %lx\n", Status);
|
|
return;
|
|
}
|
|
|
|
Status = NtQuerySystemInformation(SystemPerformanceInformation,
|
|
(PVOID)&SystemInfo,
|
|
sizeof(SYSTEM_PERFORMANCE_INFORMATION),
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Failed to query performance information, status = %lx\n", Status);
|
|
return;
|
|
}
|
|
|
|
PerfInfo->ContextSwitches = SystemInfo.ContextSwitches;
|
|
PerfInfo->FirstLevelFills = SystemInfo.FirstLevelTbFills;
|
|
// PerfInfo->InterruptCount = SystemInfo.InterruptCount;
|
|
PerfInfo->SecondLevelFills = SystemInfo.SecondLevelTbFills;
|
|
PerfInfo->SystemCalls = SystemInfo.SystemCalls;
|
|
return;
|
|
}
|