|
23 | 23 |
|
24 | 24 | enkiTaskScheduler* pETS; |
25 | 25 |
|
26 | | -struct CompletionArgs |
| 26 | +struct CompletionArgs_ModifyTask |
| 27 | +{ |
| 28 | + enkiTaskSet* pTaskB; |
| 29 | + uint32_t run; |
| 30 | +}; |
| 31 | + |
| 32 | +struct CompletionArgs_DeleteTask |
27 | 33 | { |
28 | 34 | enkiTaskSet* pTask; |
| 35 | + enkiDependency* pDependency; // in this example only 1 or 0 dependencies, but generally could be an array |
29 | 36 | enkiCompletionAction* pCompletionAction; |
| 37 | + uint32_t run; // only required for example output, not needed for a general purpose delete task |
30 | 38 | }; |
31 | 39 |
|
32 | | -void CompletionFunction( void* pArgs_, uint32_t threadNum_ ) |
| 40 | +// In this example all our TaskSet functions share the same args struct, but we could use different one |
| 41 | +struct TaskSetArgs |
| 42 | +{ |
| 43 | + enkiTaskSet* pTask; |
| 44 | + const char* name; |
| 45 | + uint32_t run; |
| 46 | +}; |
| 47 | + |
| 48 | +void CompletionFunctionPreComplete_ModifyDependentTask( void* pArgs_, uint32_t threadNum_ ) |
| 49 | +{ |
| 50 | + struct CompletionArgs_ModifyTask* pCompletionArgs_ModifyTask = pArgs_; |
| 51 | + struct enkiParamsTaskSet paramsTaskNext = enkiGetParamsTaskSet( pCompletionArgs_ModifyTask->pTaskB ); |
| 52 | + |
| 53 | + printf("CompletionFunctionPreComplete_ModifyDependentTask for run %u running on thread %u\n", |
| 54 | + pCompletionArgs_ModifyTask->run, threadNum_ ); |
| 55 | + |
| 56 | + // in this function we can modify the parameters of any task which depends on this CompletionFunction |
| 57 | + // pre complete functions should not be used to delete the current CompletionAction, for that use PostComplete functions |
| 58 | + paramsTaskNext.setSize = 10; // modify the set size of the next task - for example this could be based on output from previous task |
| 59 | + enkiSetParamsTaskSet( pCompletionArgs_ModifyTask->pTaskB, paramsTaskNext ); |
| 60 | + |
| 61 | + free( pCompletionArgs_ModifyTask ); |
| 62 | +} |
| 63 | + |
| 64 | + |
| 65 | +void CompletionFunctionPostComplete_DeleteTask( void* pArgs_, uint32_t threadNum_ ) |
33 | 66 | { |
34 | | - struct CompletionArgs* pCompletionArgs = pArgs_; |
35 | | - struct enkiParamsTaskSet params = enkiGetParamsTaskSet( pCompletionArgs->pTask ); |
36 | | - uint32_t* pTaskNum = params.pArgs; |
37 | | - printf("CompletionFunction for task %u running on thread %u\n", *pTaskNum, threadNum_ ); |
38 | | - enkiDeleteCompletionAction( pETS, pCompletionArgs->pCompletionAction ); |
39 | | - enkiDeleteTaskSet( pETS, pCompletionArgs->pTask ); |
40 | | - free( pTaskNum ); |
41 | | - free( pCompletionArgs ); |
| 67 | + struct CompletionArgs_DeleteTask* pCompletionArgs_DeleteTask = pArgs_; |
| 68 | + |
| 69 | + printf("CompletionFunctionPostComplete_DeleteTask for run %u running on thread %u\n", |
| 70 | + pCompletionArgs_DeleteTask->run, threadNum_ ); |
| 71 | + |
| 72 | + // can free memory in post complete |
| 73 | + |
| 74 | + // note must delete a dependency before you delete the dependency task and the task to run on completion |
| 75 | + if( pCompletionArgs_DeleteTask->pDependency ) |
| 76 | + { |
| 77 | + enkiDeleteDependency( pETS, pCompletionArgs_DeleteTask->pDependency ); |
| 78 | + } |
| 79 | + |
| 80 | + free( enkiGetParamsTaskSet( pCompletionArgs_DeleteTask->pTask ).pArgs ); |
| 81 | + enkiDeleteTaskSet( pETS, pCompletionArgs_DeleteTask->pTask ); |
| 82 | + |
| 83 | + enkiDeleteCompletionAction( pETS, pCompletionArgs_DeleteTask->pCompletionAction ); |
| 84 | + |
| 85 | + // safe to free our own args in this example as no other function dereferences them |
| 86 | + free( pCompletionArgs_DeleteTask ); |
42 | 87 | } |
43 | 88 |
|
44 | 89 | void TaskSetFunc( uint32_t start_, uint32_t end_, uint32_t threadnum_, void* pArgs_ ) |
45 | 90 | { |
46 | 91 | (void)start_; (void)end_; |
47 | | - uint32_t* pTaskNum = pArgs_; |
48 | | - printf("Task %u running on thread %u\n", *pTaskNum, threadnum_); |
| 92 | + struct TaskSetArgs* pTaskSetArgs = pArgs_; |
| 93 | + struct enkiParamsTaskSet paramsTaskNext = enkiGetParamsTaskSet( pTaskSetArgs->pTask ); |
| 94 | + if( 0 == start_ ) |
| 95 | + { |
| 96 | + // for clarity in this example we only output one printf per taskset func called, but would normally loop from start_ to end_ doing work |
| 97 | + printf("Task %s for run %u running on thread %u has set size %u\n", pTaskSetArgs->name, pTaskSetArgs->run, threadnum_, paramsTaskNext.setSize); |
| 98 | + } |
| 99 | + |
| 100 | + // A TastSetFunction is not a safe place to free it's own pArgs_ as when the setSize > 1 there may be multiple |
| 101 | + // calls to this function with the same pArgs_ |
49 | 102 | } |
50 | 103 |
|
| 104 | + |
51 | 105 | int main(int argc, const char * argv[]) |
52 | 106 | { |
| 107 | + // This examples shows CompletionActions used to modify a following tasks parameters and free allocations |
| 108 | + // Task Graph for this example (with names shortened to fit on screen): |
| 109 | + // |
| 110 | + // pTaskSetA |
| 111 | + // ->pCompletionActionA-PreFunc-PostFunc |
| 112 | + // ->pTaskSetB |
| 113 | + // ->pCompletionActionB-(no PreFunc)-PostFunc |
| 114 | + // |
| 115 | + // Note that pTaskSetB must depend on pCompletionActionA NOT pTaskSetA or it could run at the same time as pCompletionActionA |
| 116 | + // so cannot be modified. |
| 117 | + |
| 118 | + struct enkiTaskSet* pTaskSetA; |
| 119 | + struct enkiCompletionAction* pCompletionActionA; |
| 120 | + struct enkiTaskSet* pTaskSetB; |
| 121 | + struct enkiCompletionAction* pCompletionActionB; |
| 122 | + struct TaskSetArgs* pTaskSetArgsA; |
| 123 | + struct CompletionArgs_ModifyTask* pCompletionArgsA; |
| 124 | + struct enkiParamsCompletionAction paramsCompletionActionA; |
| 125 | + struct TaskSetArgs* pTaskSetArgsB; |
| 126 | + struct enkiDependency* pDependencyOfTaskSetBOnCompletionActionA; |
| 127 | + struct CompletionArgs_DeleteTask* pCompletionArgs_DeleteTaskA; |
| 128 | + struct CompletionArgs_DeleteTask* pCompletionArgs_DeleteTaskB; |
| 129 | + struct enkiParamsCompletionAction paramsCompletionActionB; |
53 | 130 | int run; |
54 | | - struct enkiParamsCompletionAction paramsCompletionAction; |
55 | | - uint32_t* pTaskNum; |
56 | | - struct CompletionArgs* pCompletionArgs; |
57 | 131 |
|
58 | 132 | pETS = enkiNewTaskScheduler(); |
59 | 133 | enkiInitTaskScheduler( pETS ); |
60 | 134 |
|
61 | | - // Here we demonstrate using the completion action to delete the tasks on the fly |
62 | 135 | for( run=0; run<10; ++run ) |
63 | 136 | { |
64 | | - pCompletionArgs = malloc(sizeof(struct CompletionArgs)); // we will free in CompletionFunction |
65 | | - pCompletionArgs->pTask = enkiCreateTaskSet( pETS, TaskSetFunc ); |
66 | | - pTaskNum = malloc(sizeof(uint32_t)); // we will free in CompletionFunction |
67 | | - *pTaskNum = run; |
68 | | - enkiSetArgsTaskSet( pCompletionArgs->pTask, pTaskNum ); |
69 | | - pCompletionArgs->pCompletionAction = enkiCreateCompletionAction( pETS, CompletionFunction ); |
70 | | - paramsCompletionAction = enkiGetParamsCompletionAction( pCompletionArgs->pCompletionAction ); |
71 | | - paramsCompletionAction.pArgs = pCompletionArgs; |
72 | | - paramsCompletionAction.pDependency = enkiGetCompletableFromTaskSet( pCompletionArgs->pTask ); |
73 | | - enkiSetParamsCompletionAction( pCompletionArgs->pCompletionAction, paramsCompletionAction ); |
74 | | - |
75 | | - enkiAddTaskSet( pETS, pCompletionArgs->pTask ); |
| 137 | + // Create all this runs tasks and completion actions |
| 138 | + pTaskSetA = enkiCreateTaskSet( pETS, TaskSetFunc ); |
| 139 | + pCompletionActionA = enkiCreateCompletionAction( pETS, |
| 140 | + CompletionFunctionPreComplete_ModifyDependentTask, |
| 141 | + CompletionFunctionPostComplete_DeleteTask ); |
| 142 | + pTaskSetB = enkiCreateTaskSet( pETS, TaskSetFunc ); |
| 143 | + pCompletionActionB = enkiCreateCompletionAction( pETS, |
| 144 | + NULL, |
| 145 | + CompletionFunctionPostComplete_DeleteTask ); |
| 146 | + |
| 147 | + // Set args for TaskSetA |
| 148 | + pTaskSetArgsA = malloc(sizeof(struct TaskSetArgs)); |
| 149 | + pTaskSetArgsA->run = run; |
| 150 | + pTaskSetArgsA->pTask = pTaskSetA; |
| 151 | + pTaskSetArgsA->name = "A"; |
| 152 | + enkiSetArgsTaskSet( pTaskSetA, pTaskSetArgsA ); |
| 153 | + |
| 154 | + // Set args for CompletionActionA, and make dependent on TaskSetA through pDependency |
| 155 | + pCompletionArgsA = malloc(sizeof(struct CompletionArgs_ModifyTask)); |
| 156 | + pCompletionArgsA->pTaskB = pTaskSetB; |
| 157 | + pCompletionArgsA->run = run; |
| 158 | + pCompletionArgs_DeleteTaskA = malloc(sizeof(struct CompletionArgs_DeleteTask)); |
| 159 | + pCompletionArgs_DeleteTaskA->pTask = pTaskSetA; |
| 160 | + pCompletionArgs_DeleteTaskA->pCompletionAction = pCompletionActionA; |
| 161 | + pCompletionArgs_DeleteTaskA->pDependency = NULL; |
| 162 | + pCompletionArgs_DeleteTaskA->run = run; |
| 163 | + |
| 164 | + paramsCompletionActionA = enkiGetParamsCompletionAction( pCompletionActionA ); |
| 165 | + paramsCompletionActionA.pArgsPreComplete = pCompletionArgsA; |
| 166 | + paramsCompletionActionA.pArgsPostComplete = pCompletionArgs_DeleteTaskA; |
| 167 | + paramsCompletionActionA.pDependency = enkiGetCompletableFromTaskSet( pTaskSetA ); |
| 168 | + enkiSetParamsCompletionAction( pCompletionActionA, paramsCompletionActionA ); |
| 169 | + |
| 170 | + |
| 171 | + // Set args for TaskSetB |
| 172 | + pTaskSetArgsB = malloc(sizeof(struct TaskSetArgs)); |
| 173 | + pTaskSetArgsB->run = run; |
| 174 | + pTaskSetArgsB->pTask = pTaskSetB; |
| 175 | + pTaskSetArgsB->name = "B"; |
| 176 | + enkiSetArgsTaskSet( pTaskSetB, pTaskSetArgsB ); |
| 177 | + |
| 178 | + // TaskSetB depends on pCompletionActionA |
| 179 | + pDependencyOfTaskSetBOnCompletionActionA = enkiCreateDependency( pETS ); |
| 180 | + enkiSetDependency( pDependencyOfTaskSetBOnCompletionActionA, |
| 181 | + enkiGetCompletableFromCompletionAction( pCompletionActionA ), |
| 182 | + enkiGetCompletableFromTaskSet( pTaskSetB ) ); |
| 183 | + |
| 184 | + // Set args for CompletionActionB, and make dependent on TaskSetB through pDependency |
| 185 | + pCompletionArgs_DeleteTaskB = malloc(sizeof(struct CompletionArgs_DeleteTask)); |
| 186 | + pCompletionArgs_DeleteTaskB->pTask = pTaskSetB; |
| 187 | + pCompletionArgs_DeleteTaskB->pDependency = pDependencyOfTaskSetBOnCompletionActionA; |
| 188 | + pCompletionArgs_DeleteTaskB->pCompletionAction = pCompletionActionB; |
| 189 | + pCompletionArgs_DeleteTaskB->run = run; |
| 190 | + |
| 191 | + paramsCompletionActionB = enkiGetParamsCompletionAction( pCompletionActionB ); |
| 192 | + paramsCompletionActionB.pArgsPreComplete = NULL; // pCompletionActionB does not have a PreComplete function |
| 193 | + paramsCompletionActionB.pArgsPostComplete = pCompletionArgs_DeleteTaskB; |
| 194 | + paramsCompletionActionB.pDependency = enkiGetCompletableFromTaskSet( pTaskSetB ); |
| 195 | + enkiSetParamsCompletionAction( pCompletionActionB, paramsCompletionActionB ); |
| 196 | + |
| 197 | + |
| 198 | + // To launch all, we only add the first TaskSet |
| 199 | + enkiAddTaskSet( pETS, pTaskSetA ); |
76 | 200 | } |
77 | 201 | enkiWaitForAll( pETS ); |
78 | 202 |
|
|
0 commit comments