forked from microsoft/Xbox-GDK-Samples
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathXAsyncExamples.h
More file actions
165 lines (119 loc) · 6.64 KB
/
XAsyncExamples.h
File metadata and controls
165 lines (119 loc) · 6.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//--------------------------------------------------------------------------------------
// XAsyncExamples.h
//
// Advanced Technology Group (ATG)
// Copyright (C) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#pragma once
#include <XAsync.h>
#include <XAsyncProvider.h>
#include "RDTSCPStopWatch.h"
#include "StopwatchProfiler.h"
class Sample;
namespace ATG
{
// This example class shows how to use GDK's XAsync and XTaskQueue functionality for asynchronous programming
class XAsyncExamples
{
public:
XAsyncExamples(Sample* sample);
~XAsyncExamples();
void Update(float dt);
void Notify_TaskQueueMonitor(WPARAM wp, LPARAM lp);
protected:
void CreateTaskQueues();
void CreateThreads();
void ShutdownTaskQueues();
void ShutdownThreads();
void ThreadProc_SingleCore(unsigned int index);
void ThreadProc_ManualAndMessageLoop();
void Monitor_ManualAndMessageLoop(XTaskQueueHandle queue, XTaskQueuePort port);
static double GetTime();
public:
// Test cases:
// System Thread Pool Parallel Work + Manual Completion (Async+Manual)
// - Show off with custom async methods in GDK style
void StartTest_CustomGDKStyleAPIs();
// Default Asynchronous Task Queue Work + Replacing default task queue to a synchronous execution with same calling pattern (Async+Async vs Sync+Sync)
// - Show off with synchronous calls and replacing the default process task queue
void StartTest_SynchronousTaskQueue();
// Manual Work, Manual Completion
// - Show off with extra threads that share affinity off the first two threads. The manual completion is handled in the Windows Message Loop via a Queue Monitor.
void StartTest_ManualAndMessageLoop();
// Serialized Thread Pool Work (SerializedAsync+SerializedAsync)
// Show off with async tasks that have dependencies on each other
void StartTest_SerializedAsync();
// Special: Parallel Work, Immediate completion (Manual+Immediate)
// - Show off with ParallelFor and prefix sum
void StartTest_ParallelFor();
// Extra: Composite Queue, Duplicate Queue Handles, Waiters & delayed dispatch
void StartTest_AdvancedUsage();
// Canceling async requests.
void StartTest_Canceling();
// Calculate overhead of async functions and usage for different task queues and scenarios
void StartTest_OverheadCalculations();
protected:
enum Overheads
{
// Time spent between invocation and start of work callback
Overhead_XAsyncRun_InvokeToWork,
// Time spent between end of work callback and start of completion callback
Overhead_XAsyncRun_WorkToCompletion,
// Time spent between invocation and the start of the body of one of the threads
Overhead_ParallelFor_InvokeToBody,
// Time spent between invocation and the end of the function with an empty body
Overhead_ParallelFor_InvokeToReturn,
// Time spent in async provider callback per call on average, regardless of what the call enum is
Overhead_GDKAsyncStyle_TimeInProviderAverage,
// Time spent in async provider overall for a single async invocation
Overhead_GDKAsyncStyle_TimeInProviderOverall,
// Time spent between invocation and getting to the work callback
Overhead_GDKAsyncStyle_InvokeToWork,
// Time spent between the end of the work callback and the beginning of the completion callback
Overhead_GDKAsyncStyle_WorkToCompletion,
Overhead_Total
};
// Helper functions for overhead calculations to reduce code duplication
void CalculateOverhead_XAsyncRun(XTaskQueueHandle taskQueue, StopwatchProfiler<Overhead_Total>& overheadProfiler);
void CalculateOverhead_ParallelFor(StopwatchProfiler<Overhead_Total>& overheadProfiler);
void CalculateOverhead_GDKAsyncStyle(XTaskQueueHandle taskQueue, StopwatchProfiler<Overhead_Total>& overheadProfiler);
static void GetFormattedTimingInfo(double seconds, const char** outLabel, double* outValue);
static void LogTiming(StopwatchProfiler<Overhead_Total>::TimingAccumulator* accumulator, const char* prefixLabel);
public:
// Some basic slow single-thread algorithms
static bool IsPrime(uint64_t num);
static uint64_t NthPrime(uint64_t n);
// Async versions in GDK API style of the above single-threaded algorithms
static HRESULT NthPrimeAsync(uint64_t n, XAsyncBlock* async);
static HRESULT NthPrimeAsyncResult(XAsyncBlock* async, uint64_t* result);
// Cancelable async method. Method won't end unless it's canceled.
static HRESULT CancelableInfiniteTaskAsync(XAsyncBlock* async);
// ParallelFor function which runs from startIndex to endIndex and invokes the bodyFunction
// in parallel for each index. The end index is one-past the end, so a synchronous loop would
// look like this: for(unsigned int i = startIndex; i < endIndex; ++i) { bodyFunction(i); }
static void ParallelFor(unsigned int startIndex, unsigned int endIndex, std::function<void(unsigned int)> bodyFunction);
// Similar to ParallelFor, this function more generic in that it just runs N number of tasks in parallel and
// requires you specify the task queue to use. Note that parallelization is actually based on the task queue specified.
static void ParallelExecute(unsigned int numTasks, XTaskQueueHandle taskQueue, std::function<void(unsigned int)> bodyFunction);
// Runs a task on the specified task queue with the specified callbacks. If nullptr is passed for the tasks queue, then the default
// process test queue will be used.
static void RunTask(XTaskQueueHandle taskQueue, std::function<void()> workCallback, std::function<void()> completionCallback);
static void RunTask(XTaskQueueHandle taskQueue, std::function<void()> workCallback);
protected:
bool m_testInProgress;
XTaskQueueHandle m_taskQueue_CustomGDKStyleAPIs;
XTaskQueueHandle m_taskQueue_ParallelFor;
XTaskQueueHandle m_taskQueue_SynchronousTaskQueue;
XTaskQueueHandle m_taskQueue_SerializedAsync;
XTaskQueueHandle m_taskQueue_ManualAndMessageLoop;
XTaskQueueRegistrationToken m_taskQueueToken_ManualAndMessageloop;
XTaskQueueHandle m_cachedProcessDefaultTaskQueueHandle;
unsigned int m_numCores;
std::vector<std::thread> m_threads_SingleCore;
std::vector<std::thread> m_threads_ManualAndMessageLoop;
HANDLE m_shutdownEvent;
static XAsyncExamples* s_singleton;
static Sample* s_sample;
static RDTSCPStopWatch s_stopWatch;
};
}