├── .github └── FUNDING.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── License.txt ├── README.md ├── enkiTSMicroprofileExample.cpp ├── enkiTSRemoteryExample.c ├── enkiTSRemoteryExample.cpp └── images ├── enkiTSMicroprofileExample.png └── enkiTSRemoteryExample.png /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: dougbinks 4 | patreon: enkisoftware 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: https://www.enkisoftware.com/avoyd 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .vscode 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "enkiTS"] 2 | path = enkiTS 3 | url = https://github.com/dougbinks/enkiTS 4 | [submodule "Remotery"] 5 | path = Remotery 6 | url = https://github.com/Celtoys/Remotery 7 | [submodule "microprofile"] 8 | path = microprofile 9 | url = https://github.com/dougbinks/microprofile 10 | [submodule "imgui"] 11 | path = imgui 12 | url = https://github.com/ocornut/imgui 13 | [submodule "glfw"] 14 | path = glfw 15 | url = https://github.com/glfw/glfw.git 16 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | project( enkiTSExamples ) 4 | 5 | find_package(OpenGL) 6 | 7 | include_directories("enkiTS/src") 8 | include_directories("Remotery/lib") 9 | include_directories("imgui") 10 | include_directories("microprofile") 11 | include_directories("glfw/include") 12 | include_directories("imgui/examples") 13 | include_directories( ${OPENGL_INCLUDE_DIRS} ) 14 | 15 | set( ENKITS_BUILD_EXAMPLES OFF CACHE BOOL "Build basic example applications" ) 16 | set( GLFW_BUILD_EXAMPLES OFF CACHE BOOL "GLFW lib only" ) 17 | set( GLFW_BUILD_TESTS OFF CACHE BOOL "GLFW lib only" ) 18 | set( GLFW_BUILD_DOCS OFF CACHE BOOL "GLFW lib only" ) 19 | set( GLFW_BUILD_INSTALL OFF CACHE BOOL "GLFW lib only" ) 20 | 21 | add_subdirectory( enkiTS ) 22 | 23 | if(OpenGL_FOUND) 24 | add_subdirectory( glfw ) 25 | endif() 26 | 27 | set( ENKITSREMOTERYSAMPLE_SRC 28 | enkiTSRemoteryExample.cpp 29 | Remotery/lib/Remotery.h 30 | Remotery/lib/Remotery.c 31 | ) 32 | 33 | add_executable( enkiTSRemoteryExample ${ENKITSREMOTERYSAMPLE_SRC} ) 34 | target_link_libraries(enkiTSRemoteryExample enkiTS ) 35 | 36 | if( ENKITS_BUILD_C_INTERFACE ) 37 | set( ENKITSREMOTERYSAMPLE_C_SRC 38 | enkiTSRemoteryExample.c 39 | Remotery/lib/Remotery.h 40 | Remotery/lib/Remotery.c 41 | ) 42 | add_executable( enkiTSRemoteryExample_C ${ENKITSREMOTERYSAMPLE_C_SRC} ) 43 | target_link_libraries(enkiTSRemoteryExample_C enkiTS ) 44 | endif() 45 | 46 | if(UNIX) 47 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 48 | endif() 49 | if(APPLE) 50 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 51 | endif() 52 | if( MSVC ) 53 | SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:mainCRTStartup" ) 54 | endif() 55 | 56 | if(OpenGL_FOUND) 57 | set( ENKITSMICROPROFILESAMPLE_SRC 58 | microprofile/microprofile.h 59 | microprofile/microprofileui.h 60 | imgui/imgui.h 61 | imgui/imgui.cpp 62 | imgui/imgui_internal.h 63 | imgui/imgui_demo.cpp 64 | imgui/imgui_draw.cpp 65 | imgui/imgui_widgets.cpp 66 | imgui/imconfig.h 67 | imgui/examples/imgui_impl_glfw.h 68 | imgui/examples/imgui_impl_glfw.cpp 69 | imgui/examples/imgui_impl_opengl2.h 70 | imgui/examples/imgui_impl_opengl2.cpp 71 | enkiTSMicroprofileExample.cpp 72 | ) 73 | add_executable( enkiTSMicroprofileExample WIN32 ${ENKITSMICROPROFILESAMPLE_SRC} ) 74 | target_link_libraries(enkiTSMicroprofileExample enkiTS ${OPENGL_LIBRARIES} glfw ${GLFW_LIBRARIES} ) 75 | endif() 76 | 77 | if( MSVC ) 78 | if(${CMAKE_VERSION} VERSION_LESS "3.6.0") 79 | message( "\n\t[ WARNING ]\n\n\tCMake version lower than 3.6.\n\n\t - Please update CMake and rerun; OR\n\t - Manually set one of the 'Example' projects as StartUp Project in Visual Studio.\n" ) 80 | else() 81 | set_property( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT enkiTSMicroprofileExample ) 82 | endif() 83 | endif() -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Doug Binks 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgement in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Support development of enkiTS through [Github Sponsors](https://github.com/sponsors/dougbinks) or [Patreon](https://www.patreon.com/enkisoftware) 2 | 3 | [](https://github.com/sponsors/dougbinks) [Become a Patron](https://www.patreon.com/enkisoftware) 4 | 5 | ![enkiTS Logo](https://github.com/dougbinks/images/blob/master/enkiTS_logo_no_padding.png?raw=true) 6 | # [enkiTS](https://github.com/dougbinks/enkiTS/) Examples 7 | 8 | **Submodules are licensed under their own licenses, see their contents for details** 9 | 10 | ## Building 11 | 12 | First [make sure you've cloned all submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules#Cloning-a-Project-with-Submodules). On Windows / Mac OS X / Linux with cmake installed, open a prompt in the enkiTS directory and: 13 | 14 | 1. `mkdir build` 15 | 2. `cmake ..` 16 | 3. either run `make` or on Windows with Visual Studio open `enkiTSExamples.sln` 17 | 18 | ## enki Task Scheduler Extended Samples 19 | 20 | [enkiTS](https://github.com/dougbinks/enkiTS/) is a permissively licensed C and C++ Task Scheduler for creating parallel programs. 21 | 22 | This repository hosts extended examples. 23 | 24 | ## [enkiTSRemoteryExample.cpp](enkiTSRemoteryExample.cpp) 25 | 26 | This example shows how to use [Remotery](https://github.com/Celtoys/Remotery) with [enkiTS](https://github.com/dougbinks/enkiTS/). 27 | 28 | Note that currently in release the sums might be optimized away. 29 | 30 | ![Remotery Screenshot](images/enkiTSRemoteryExample.png?raw=true) 31 | 32 | ## [enkiTSRemoteryExample.c](enkiTSRemoteryExample.c) 33 | 34 | As above but using the C interface. 35 | 36 | ## [enkiTSMicroprofileExample.cpp](enkiTSMicroprofileExample.cpp) 37 | 38 | This example shows how to use [microprofile](https://github.com/dougbinks/microprofile) with [enkiTS](https://github.com/dougbinks/enkiTS/). 39 | 40 | To view context switching on Windows, run the application (or Visual Studio if launching from that) as administrator and set Options->Cswitch Trace->Enable on. 41 | 42 | ![Microprofile Screenshot](images/enkiTSMicroprofileExample.png?raw=true) 43 | 44 | ## License (zlib) 45 | 46 | Copyright (c) 2013 Doug Binks 47 | 48 | This software is provided 'as-is', without any express or implied 49 | warranty. In no event will the authors be held liable for any damages 50 | arising from the use of this software. 51 | 52 | Permission is granted to anyone to use this software for any purpose, 53 | including commercial applications, and to alter it and redistribute it 54 | freely, subject to the following restrictions: 55 | 56 | 1. The origin of this software must not be misrepresented; you must not 57 | claim that you wrote the original software. If you use this software 58 | in a product, an acknowledgement in the product documentation would be 59 | appreciated but is not required. 60 | 2. Altered source versions must be plainly marked as such, and must not be 61 | misrepresented as being the original software. 62 | 3. This notice may not be removed or altered from any source distribution. 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /enkiTSMicroprofileExample.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 Doug Binks 2 | // 3 | // This software is provided 'as-is', without any express or implied 4 | // warranty. In no event will the authors be held liable for any damages 5 | // arising from the use of this software. 6 | // 7 | // Permission is granted to anyone to use this software for any purpose, 8 | // including commercial applications, and to alter it and redistribute it 9 | // freely, subject to the following restrictions: 10 | // 11 | // 1. The origin of this software must not be misrepresented; you must not 12 | // claim that you wrote the original software. If you use this software 13 | // in a product, an acknowledgement in the product documentation would be 14 | // appreciated but is not required. 15 | // 2. Altered source versions must be plainly marked as such, and must not be 16 | // misrepresented as being the original software. 17 | // 3. This notice may not be removed or altered from any source distribution. 18 | 19 | #ifdef _WIN32 20 | #pragma warning(disable:4996) 21 | #endif 22 | #define MICROPROFILE_IMPL 23 | #define MICROPROFILEUI_IMPL 24 | #define MICROPROFILE_WEBSERVER 0 25 | #define MICROPROFILE_TEXT_HEIGHT 12 26 | #define MICROPROFILE_TEXT_WIDTH 7 27 | #define MICROPROFILE_GPU_TIMERS 0 28 | #define NOMINMAX 29 | #include "microprofile.h" 30 | #include "microprofileui.h" 31 | 32 | #include "TaskScheduler.h" 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | 42 | #include 43 | #include "imgui_impl_glfw.h" 44 | #include "imgui_impl_opengl2.h" 45 | #include 46 | 47 | static const int MINRANGE = 10 * 1024; 48 | static const int SUMS = 10*1024*1024; 49 | 50 | // UI functions 51 | static ImDrawList* g_pImDraw = 0; 52 | static ImVec2 g_DrawStart; 53 | static ImVec2 g_DrawSize; 54 | 55 | void MicroProfileDrawText(int nX, int nY, uint32_t nColor, const char* pText, uint32_t nNumCharacters) 56 | { 57 | g_pImDraw->AddText( ImVec2(nX + g_DrawStart.x,nY + g_DrawStart.y ), nColor, pText, pText + nNumCharacters ); 58 | } 59 | 60 | inline bool IsBoxInside( ImVec2 p0, ImVec2 p1 ) 61 | { 62 | return ( p1.x >= g_DrawStart.x && p0.x < g_DrawStart.x + g_DrawSize.x ) && ( p1.y >= g_DrawStart.y && p0.y < g_DrawStart.y + g_DrawSize.y ); 63 | } 64 | 65 | void MicroProfileDrawBox(int nX, int nY, int nX1, int nY1, uint32_t nColor, MicroProfileBoxType boxType ) 66 | { 67 | ImVec2 p0(nX + g_DrawStart.x,nY + g_DrawStart.y ); 68 | ImVec2 p1(nX1 + g_DrawStart.x,nY1 + g_DrawStart.y ); 69 | if( !IsBoxInside(p0,p1)) 70 | { 71 | return; 72 | } 73 | 74 | switch( boxType ) 75 | { 76 | case MicroProfileBoxTypeBar: 77 | { 78 | uint32_t cul = nColor; 79 | uint32_t cur = ( nColor & 0x00FFFFFF ) + 0xFF000000; 80 | uint32_t clr = ( nColor & 0x00FFFFFF ) + 0x50000000; 81 | uint32_t cll = ( nColor & 0x00FFFFFF ) + 0x50000000; 82 | g_pImDraw->AddRectFilledMultiColor(p0, p1, cul, cur, clr, cll ); 83 | if( nX1 - nX > 5 ) 84 | { 85 | g_pImDraw->AddRect(p0, p1, 0x50000000 ); 86 | } 87 | break; 88 | } 89 | case MicroProfileBoxTypeFlat: 90 | g_pImDraw->AddRectFilled(p0, p1, nColor ); 91 | break; 92 | default: 93 | assert(false); 94 | } 95 | } 96 | 97 | void MicroProfileDrawLine2D(uint32_t nVertices, float* pVertices, uint32_t nColor) 98 | { 99 | for( uint32_t vert = 0; vert + 1 < nVertices; ++vert ) 100 | { 101 | uint32_t i = 2*vert; 102 | ImVec2 posA( pVertices[i] + g_DrawStart.x, pVertices[i+1] + g_DrawStart.y ); 103 | ImVec2 posB( pVertices[i+2] + g_DrawStart.x, pVertices[i+3] + g_DrawStart.y ); 104 | g_pImDraw->AddLine( posA, posB, nColor ); 105 | } 106 | } 107 | 108 | static void error_callback(int error, const char* description) 109 | { 110 | fprintf(stderr, "Error %d: %s\n", error, description); 111 | } 112 | 113 | 114 | using namespace enki; 115 | 116 | 117 | TaskScheduler g_TS; 118 | 119 | 120 | struct ParallelSumTaskSet : ITaskSet 121 | { 122 | struct Count 123 | { 124 | // prevent false sharing. 125 | uint64_t count; 126 | char cacheline[64]; 127 | }; 128 | Count* m_pPartialSums; 129 | uint32_t m_NumPartialSums; 130 | 131 | ParallelSumTaskSet( uint32_t size_ ) : m_pPartialSums(NULL), m_NumPartialSums(0) { m_SetSize = size_; m_MinRange = MINRANGE; } 132 | virtual ~ParallelSumTaskSet() 133 | { 134 | delete[] m_pPartialSums; 135 | } 136 | 137 | void Init() 138 | { 139 | MICROPROFILE_SCOPEI("Parallel", "SumInit", 0xFF008800 ); 140 | delete[] m_pPartialSums; 141 | m_NumPartialSums = g_TS.GetNumTaskThreads(); 142 | m_pPartialSums = new Count[ m_NumPartialSums ]; 143 | memset( m_pPartialSums, 0, sizeof(Count)*m_NumPartialSums ); 144 | } 145 | 146 | virtual void ExecuteRange( TaskSetPartition range, uint32_t threadnum ) 147 | { 148 | MICROPROFILE_SCOPEI("Parallel", "SumTask", 0xFF00D000 ); 149 | assert( m_pPartialSums && m_NumPartialSums ); 150 | uint64_t sum = m_pPartialSums[threadnum].count; 151 | for( uint64_t i = range.start; i < range.end; ++i ) 152 | { 153 | sum += i + 1; 154 | } 155 | m_pPartialSums[threadnum].count = sum; 156 | } 157 | 158 | }; 159 | 160 | struct ParallelReductionSumTaskSet : ITaskSet 161 | { 162 | ParallelSumTaskSet m_ParallelSumTaskSet; 163 | uint64_t m_FinalSum; 164 | 165 | ParallelReductionSumTaskSet( uint32_t size_ ) : m_ParallelSumTaskSet( size_ ), m_FinalSum(0) {} 166 | 167 | void Init() 168 | { 169 | m_ParallelSumTaskSet.Init(); 170 | } 171 | 172 | virtual void ExecuteRange( TaskSetPartition range, uint32_t threadnum ) 173 | { 174 | MICROPROFILE_SCOPEI("Parallel", "ReductionTask", 0xFF20C000 ); 175 | g_TS.AddTaskSetToPipe( &m_ParallelSumTaskSet ); 176 | g_TS.WaitforTask( &m_ParallelSumTaskSet ); 177 | 178 | for( uint32_t i = 0; i < m_ParallelSumTaskSet.m_NumPartialSums; ++i ) 179 | { 180 | m_FinalSum += m_ParallelSumTaskSet.m_pPartialSums[i].count; 181 | } 182 | } 183 | }; 184 | 185 | void threadStartCallback( uint32_t threadnum_ ) 186 | { 187 | std::ostringstream out; 188 | out << "enkiTS_" << threadnum_; 189 | MicroProfileOnThreadCreate( out.str().c_str() ); 190 | } 191 | 192 | // tickstore implements a stack the same size as Microprofiles, but continues to function 193 | // without reporting timings for deeper stacks 194 | struct TickStore 195 | { 196 | uint64_t tickStack[MICROPROFILE_STACK_MAX] = {0}; 197 | int32_t tickStackNext = 0; 198 | 199 | void ProfileEnter( MicroProfileToken token_ ) { 200 | if( tickStackNext < MICROPROFILE_STACK_MAX ) { 201 | tickStack[ tickStackNext ] = MicroProfileEnter( token_ ); 202 | } 203 | ++tickStackNext; 204 | } 205 | 206 | void ProfileLeave( MicroProfileToken token_ ) { 207 | assert( tickStackNext > 0 ); // unmatched enter/leave 208 | --tickStackNext; 209 | if( tickStackNext < MICROPROFILE_STACK_MAX ) { 210 | MicroProfileLeave( token_, tickStack[ tickStackNext ] ); 211 | } 212 | } 213 | }; 214 | 215 | static TickStore* g_pTicks = NULL; 216 | 217 | void profilerInit() { 218 | g_pTicks = new TickStore[ enki::GetNumHardwareThreads() ]; 219 | } 220 | 221 | MicroProfileToken g_ProfileWaitForNewTaskSuspend = MicroProfileGetToken( "enkiTS", "waitForNewTaskSuspend", 0xFF505000, MicroProfileTokenTypeCpu); 222 | void waitForNewTaskSuspendStartCallback( uint32_t threadnum_ ) { 223 | g_pTicks[ threadnum_ ].ProfileEnter( g_ProfileWaitForNewTaskSuspend ); 224 | } 225 | 226 | void waitForNewTaskSuspendStopCallback( uint32_t threadnum_ ) { 227 | g_pTicks[ threadnum_ ].ProfileLeave( g_ProfileWaitForNewTaskSuspend ); 228 | } 229 | 230 | MicroProfileToken g_ProfileWaitForTaskComplete = MicroProfileGetToken( "enkiTS", "waitForTaskComplete", 0xFF005050, MicroProfileTokenTypeCpu); 231 | void waitForTaskCompleteStartCallback( uint32_t threadnum_ ) { 232 | 233 | g_pTicks[ threadnum_ ].ProfileEnter( g_ProfileWaitForTaskComplete ); 234 | } 235 | 236 | void waitForTaskCompleteStopCallback( uint32_t threadnum_ ) { 237 | g_pTicks[ threadnum_ ].ProfileLeave( g_ProfileWaitForTaskComplete ); 238 | } 239 | 240 | MicroProfileToken g_ProfileWaitForTaskCompleteSuspend = MicroProfileGetToken( "enkiTS", "waitForTaskCompleteSuspend", 0xFF005090, MicroProfileTokenTypeCpu); 241 | void waitForTaskCompleteSuspendStartCallback( uint32_t threadnum_ ) { 242 | g_pTicks[ threadnum_ ].ProfileEnter( g_ProfileWaitForTaskCompleteSuspend ); 243 | } 244 | 245 | void waitForTaskCompleteSuspendStopCallback( uint32_t threadnum_ ) { 246 | g_pTicks[ threadnum_ ].ProfileLeave( g_ProfileWaitForTaskCompleteSuspend ); 247 | } 248 | 249 | int main(int argc, const char * argv[]) 250 | { 251 | // Setup window 252 | glfwSetErrorCallback(error_callback); 253 | if (!glfwInit()) 254 | exit(1); 255 | GLFWwindow* window = glfwCreateWindow(1280, 720, "enkiTS microprofile example", NULL, NULL); 256 | glfwMakeContextCurrent(window); 257 | glfwSwapInterval(1); // Enable vsync 258 | 259 | // Setup Dear ImGui binding 260 | IMGUI_CHECKVERSION(); 261 | ImGui::CreateContext(); 262 | 263 | ImGui_ImplGlfw_InitForOpenGL(window, true); 264 | ImGui_ImplOpenGL2_Init(); 265 | 266 | // Setup style 267 | ImGui::StyleColorsDark(); 268 | 269 | 270 | // Set up Microprofile 271 | MicroProfileToggleDisplayMode(); 272 | MicroProfileInitUI(); 273 | MicroProfileOnThreadCreate("Main"); 274 | 275 | // setup profile default settings 276 | MicroProfile& profiler = *MicroProfileGet(); 277 | profiler.nDisplay = MP_DRAW_DETAILED; 278 | profiler.nAllGroupsWanted = 1; 279 | 280 | enki::TaskSchedulerConfig tsConfig; 281 | tsConfig.profilerCallbacks.threadStart = threadStartCallback; 282 | tsConfig.profilerCallbacks.waitForNewTaskSuspendStart = waitForNewTaskSuspendStartCallback; 283 | tsConfig.profilerCallbacks.waitForNewTaskSuspendStop = waitForNewTaskSuspendStopCallback; 284 | tsConfig.profilerCallbacks.waitForTaskCompleteStart = waitForTaskCompleteStartCallback; 285 | tsConfig.profilerCallbacks.waitForTaskCompleteStop = waitForTaskCompleteStopCallback; 286 | tsConfig.profilerCallbacks.waitForTaskCompleteSuspendStart = waitForTaskCompleteSuspendStartCallback; 287 | tsConfig.profilerCallbacks.waitForTaskCompleteSuspendStop = waitForTaskCompleteSuspendStopCallback; 288 | 289 | profilerInit(); 290 | g_TS.Initialize( tsConfig ); 291 | 292 | double avSpeedUp = 0.0; 293 | ImVec4 clear_color = ImColor(114, 144, 154); 294 | while (!glfwWindowShouldClose(window)) 295 | { 296 | MICROPROFILE_SCOPEI("MainThread", "MainLoop", 0xFF555555 ); 297 | glfwPollEvents(); 298 | 299 | // Start the Dear ImGui frame 300 | ImGui_ImplOpenGL2_NewFrame(); 301 | ImGui_ImplGlfw_NewFrame(); 302 | ImGui::NewFrame(); 303 | 304 | 305 | ParallelReductionSumTaskSet m_ParallelReductionSumTaskSet( SUMS ); 306 | { 307 | MICROPROFILE_SCOPEI("MainThread", "LaunchAndRunParallel", 0xFF555555 ); 308 | 309 | m_ParallelReductionSumTaskSet.Init(); 310 | 311 | g_TS.AddTaskSetToPipe(&m_ParallelReductionSumTaskSet); 312 | 313 | g_TS.WaitforTask(&m_ParallelReductionSumTaskSet); 314 | } 315 | 316 | 317 | 318 | volatile uint64_t sum = 0; 319 | { 320 | MICROPROFILE_SCOPEI("Serial", "Sum", 0xFF0000D0 ); 321 | for (uint64_t i = 0; i < (uint64_t)m_ParallelReductionSumTaskSet.m_ParallelSumTaskSet.m_SetSize; ++i) 322 | { 323 | sum += i + 1; 324 | } 325 | } 326 | 327 | if(true) 328 | { 329 | MicroProfileFlip(NULL); 330 | ImGui::SetNextWindowSize(ImVec2(1200,700), ImGuiCond_FirstUseEver); 331 | ImGui::SetNextWindowPos(ImVec2(10,10), ImGuiCond_FirstUseEver); 332 | ImGui::Begin( "Microprofile" ); 333 | 334 | g_pImDraw = ImGui::GetWindowDrawList(); 335 | g_DrawStart = ImGui::GetCursorScreenPos(); 336 | g_DrawSize = ImGui::GetContentRegionAvail(); 337 | 338 | ImGui::InvisibleButton("canvas", g_DrawSize); 339 | if (ImGui::IsItemHovered()) 340 | { 341 | MicroProfileMouseButton( ImGui::GetIO().MouseDown[0], ImGui::GetIO().MouseDown[1] ); 342 | } 343 | else 344 | { 345 | MicroProfileMouseButton( 0, 0 ); 346 | } 347 | MicroProfileMousePosition((uint32_t)(ImGui::GetIO().MousePos.x- g_DrawStart.x), (uint32_t)(ImGui::GetIO().MousePos.y - g_DrawStart.y), (int)ImGui::GetIO().MouseWheel ); 348 | MicroProfileDraw((uint32_t)g_DrawSize.x, (uint32_t)g_DrawSize.y); 349 | 350 | ImGui::End(); 351 | } 352 | 353 | // Rendering 354 | { 355 | MICROPROFILE_SCOPEI("MainThread", "Render", 0xFF882222 ); 356 | glViewport(0, 0, (int)ImGui::GetIO().DisplaySize.x, (int)ImGui::GetIO().DisplaySize.y); 357 | glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); 358 | glClear(GL_COLOR_BUFFER_BIT); 359 | ImGui::Render(); 360 | ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); 361 | glfwSwapBuffers(window); 362 | } 363 | } 364 | 365 | 366 | // Cleanup 367 | g_TS.WaitforAllAndShutdown(); 368 | ImGui_ImplOpenGL2_Shutdown(); 369 | ImGui_ImplGlfw_Shutdown(); 370 | ImGui::DestroyContext(); 371 | glfwTerminate(); 372 | 373 | return 0; 374 | } 375 | -------------------------------------------------------------------------------- /enkiTSRemoteryExample.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 Doug Binks 2 | // 3 | // This software is provided 'as-is', without any express or implied 4 | // warranty. In no event will the authors be held liable for any damages 5 | // arising from the use of this software. 6 | // 7 | // Permission is granted to anyone to use this software for any purpose, 8 | // including commercial applications, and to alter it and redistribute it 9 | // freely, subject to the following restrictions: 10 | // 11 | // 1. The origin of this software must not be misrepresented; you must not 12 | // claim that you wrote the original software. If you use this software 13 | // in a product, an acknowledgement in the product documentation would be 14 | // appreciated but is not required. 15 | // 2. Altered source versions must be plainly marked as such, and must not be 16 | // misrepresented as being the original software. 17 | // 3. This notice may not be removed or altered from any source distribution. 18 | 19 | #include "TaskScheduler_c.h" 20 | #include 21 | #include 22 | #include 23 | 24 | #include "Remotery.h" 25 | 26 | enkiTaskScheduler* pETS; 27 | enkiTaskSet* pPSumTask; 28 | enkiTaskSet* pPSumReductionTask; 29 | 30 | static const int RUNS = 1024 * 1024; 31 | static const int MINRANGE = 10 * 1024; 32 | static const int SUMS = 10 * 1024 * 1024; 33 | 34 | 35 | typedef struct ParallelSumTaskSetArgs 36 | { 37 | uint64_t* pPartialSums; 38 | uint32_t numPartialSums; 39 | } ParallelSumTaskSetArgs; 40 | 41 | void ParallelSumTaskSetArgsInit( ParallelSumTaskSetArgs* pArgs_ ) 42 | { 43 | pArgs_->numPartialSums = enkiGetNumTaskThreads( pETS ); 44 | pArgs_->pPartialSums = (uint64_t*)malloc( sizeof(uint64_t) * pArgs_->numPartialSums ); 45 | memset( pArgs_->pPartialSums, 0, sizeof(uint64_t) * pArgs_->numPartialSums ); 46 | } 47 | 48 | void ParallelSumTaskSetFunc( uint32_t start_, uint32_t end, uint32_t threadnum_, void* pArgs_ ) 49 | { 50 | rmt_BeginCPUSample(Sum, 0); 51 | 52 | ParallelSumTaskSetArgs args; 53 | uint64_t sum, i; 54 | 55 | args = *(ParallelSumTaskSetArgs*)pArgs_; 56 | 57 | sum = args.pPartialSums[threadnum_]; 58 | for( i = start_; i < end; ++i ) 59 | { 60 | sum += i + 1; 61 | } 62 | args.pPartialSums[threadnum_] = sum; 63 | 64 | rmt_EndCPUSample(); 65 | } 66 | 67 | void ParallelReductionSumTaskSet( uint32_t start_, uint32_t end, uint32_t threadnum_, void* pArgs_ ) 68 | { 69 | rmt_BeginCPUSample(Reduce, 0); 70 | 71 | ParallelSumTaskSetArgs args; 72 | uint64_t sum; 73 | uint64_t inMax_outSum, i; 74 | 75 | inMax_outSum = *(uint64_t*)pArgs_; 76 | 77 | ParallelSumTaskSetArgsInit( &args ); 78 | 79 | enkiAddTaskSetMinRange( pETS, pPSumTask, &args, (uint32_t)inMax_outSum, MINRANGE ); 80 | enkiWaitForTaskSet( pETS, pPSumTask ); 81 | 82 | sum = 0; 83 | for( i = 0; i < args.numPartialSums; ++i ) 84 | { 85 | sum += args.pPartialSums[i]; 86 | } 87 | 88 | free( args.pPartialSums ); 89 | 90 | *(uint64_t*)pArgs_ = sum; 91 | 92 | rmt_EndCPUSample(); 93 | } 94 | 95 | 96 | static char* nameTable[] = { 97 | "enkiTS_00", "enkiTS_01", "enkiTS_02", "enkiTS_03", "enkiTS_04", "enkiTS_05", "enkiTS_06", "enkiTS_07", "enkiTS_08", "enkiTS_09", 98 | "enkiTS_10", "enkiTS_11", "enkiTS_12", "enkiTS_13", "enkiTS_14", "enkiTS_15", "enkiTS_16", "enkiTS_17", "enkiTS_18", "enkiTS_19", 99 | "enkiTS_20", "enkiTS_21", "enkiTS_22", "enkiTS_23", "enkiTS_24", "enkiTS_25", "enkiTS_26", "enkiTS_27", "enkiTS_28", "enkiTS_29", 100 | "enkiTS_30", "enkiTS_31", "enkiTS_32", "enkiTS_33", "enkiTS_34", "enkiTS_35", "enkiTS_36", "enkiTS_37", "enkiTS_38", "enkiTS_39", 101 | "enkiTS_40", "enkiTS_41", "enkiTS_42", "enkiTS_43", "enkiTS_44", "enkiTS_45", "enkiTS_46", "enkiTS_47", "enkiTS_48", "enkiTS_49", 102 | "enkiTS_50", "enkiTS_51", "enkiTS_52", "enkiTS_53", "enkiTS_54", "enkiTS_55", "enkiTS_56", "enkiTS_57", "enkiTS_58", "enkiTS_59", 103 | "enkiTS_60", "enkiTS_61", "enkiTS_62", "enkiTS_63", "enkiTS_64", "enkiTS_XX", 104 | }; 105 | const uint32_t nameTableSize = (uint32_t)sizeof( nameTable ) / sizeof( const char* ); 106 | 107 | void threadStartCallback( uint32_t threadnum_ ) 108 | { 109 | uint32_t nameNum = threadnum_; 110 | if( nameNum >= nameTableSize ) { nameNum = nameTableSize-1; } 111 | rmt_SetCurrentThreadName( nameTable[ nameNum ] ); 112 | } 113 | 114 | void waitForNewTaskSuspendStartCallback( uint32_t threadnum_ ) 115 | { 116 | rmt_BeginCPUSample(WaitForNewTaskSuspend, 0); 117 | } 118 | 119 | void waitForTaskCompleteStartCallback( uint32_t threadnum_ ) 120 | { 121 | rmt_BeginCPUSample(WaitForTaskComplete, 0); 122 | } 123 | 124 | void waitForTaskCompleteSuspendStartCallback( uint32_t threadnum_ ) 125 | { 126 | rmt_BeginCPUSample(WaitForTaskCompleteSuspend, 0); 127 | } 128 | 129 | void stopCallback( uint32_t threadnum_ ) 130 | { 131 | rmt_EndCPUSample(); 132 | } 133 | 134 | int main(int argc, const char * argv[]) 135 | { 136 | int run; 137 | uint64_t inMax_outSum, i; 138 | volatile uint64_t serialSum; 139 | Remotery* rmt; 140 | 141 | // the example generates a lot of samples, so increase update rate for profiler 142 | rmt_Settings()->maxNbMessagesPerUpdate = 128 * rmt_Settings()->maxNbMessagesPerUpdate; 143 | rmt_CreateGlobalInstance(&rmt); 144 | 145 | pETS = enkiNewTaskScheduler(); 146 | struct enkiTaskSchedulerConfig tsConfig = enkiGetTaskSchedulerConfig( pETS ); 147 | 148 | tsConfig.profilerCallbacks.threadStart = threadStartCallback; 149 | tsConfig.profilerCallbacks.waitForNewTaskSuspendStart = waitForNewTaskSuspendStartCallback; 150 | tsConfig.profilerCallbacks.waitForNewTaskSuspendStop = stopCallback; 151 | tsConfig.profilerCallbacks.waitForTaskCompleteStart = waitForTaskCompleteStartCallback; 152 | tsConfig.profilerCallbacks.waitForTaskCompleteStop = stopCallback; 153 | tsConfig.profilerCallbacks.waitForTaskCompleteSuspendStart = waitForTaskCompleteSuspendStartCallback; 154 | tsConfig.profilerCallbacks.waitForTaskCompleteSuspendStop = stopCallback; 155 | 156 | enkiInitTaskSchedulerWithConfig( pETS, tsConfig ); 157 | 158 | rmt_SetCurrentThreadName("Main"); 159 | 160 | pPSumTask = enkiCreateTaskSet( pETS, ParallelSumTaskSetFunc ); 161 | pPSumReductionTask = enkiCreateTaskSet( pETS, ParallelReductionSumTaskSet ); 162 | 163 | for (run = 0; run < RUNS; ++run) 164 | { 165 | rmt_BeginCPUSample(Run, 0); 166 | 167 | printf("Run %d\t Open Remotery\\vis\\index.html to view profiler\n", run); 168 | 169 | rmt_BeginCPUSample(Parallel, 0); 170 | inMax_outSum = SUMS; 171 | enkiAddTaskSetArgs(pETS, pPSumReductionTask, &inMax_outSum, 1); 172 | enkiWaitForTaskSet(pETS, pPSumReductionTask); 173 | rmt_EndCPUSample(); 174 | 175 | 176 | rmt_BeginCPUSample(Serial, 0); 177 | serialSum = 0; 178 | for (i = 0; i < SUMS; ++i) 179 | { 180 | serialSum += i + 1; 181 | } 182 | if( inMax_outSum == serialSum ) 183 | { 184 | printf("Sums Correct.\n"); 185 | } 186 | else 187 | { 188 | printf("Sums ERROR.\n"); 189 | } 190 | 191 | rmt_EndCPUSample(); 192 | 193 | rmt_EndCPUSample(); 194 | } 195 | 196 | enkiDeleteTaskScheduler( pETS ); 197 | } -------------------------------------------------------------------------------- /enkiTSRemoteryExample.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 Doug Binks 2 | // 3 | // This software is provided 'as-is', without any express or implied 4 | // warranty. In no event will the authors be held liable for any damages 5 | // arising from the use of this software. 6 | // 7 | // Permission is granted to anyone to use this software for any purpose, 8 | // including commercial applications, and to alter it and redistribute it 9 | // freely, subject to the following restrictions: 10 | // 11 | // 1. The origin of this software must not be misrepresented; you must not 12 | // claim that you wrote the original software. If you use this software 13 | // in a product, an acknowledgement in the product documentation would be 14 | // appreciated but is not required. 15 | // 2. Altered source versions must be plainly marked as such, and must not be 16 | // misrepresented as being the original software. 17 | // 3. This notice may not be removed or altered from any source distribution. 18 | 19 | #include "TaskScheduler.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "Remotery.h" 28 | 29 | using namespace enki; 30 | 31 | TaskScheduler g_TS; 32 | 33 | static const int RUNS = 1024*1024; 34 | static const int MINRANGE = 10 * 1024; 35 | static const int SUMS = 10*1024*1024; 36 | 37 | 38 | struct ParallelSumTaskSet : ITaskSet 39 | { 40 | struct Count 41 | { 42 | // prevent false sharing. 43 | uint64_t count; 44 | char cacheline[64]; 45 | }; 46 | Count* m_pPartialSums; 47 | uint32_t m_NumPartialSums; 48 | 49 | ParallelSumTaskSet( uint32_t size_ ) : m_pPartialSums(NULL), m_NumPartialSums(0) { m_SetSize = size_; m_MinRange = MINRANGE; } 50 | virtual ~ParallelSumTaskSet() 51 | { 52 | delete[] m_pPartialSums; 53 | } 54 | 55 | void Init() 56 | { 57 | delete[] m_pPartialSums; 58 | m_NumPartialSums = g_TS.GetNumTaskThreads(); 59 | m_pPartialSums = new Count[ m_NumPartialSums ]; 60 | memset( m_pPartialSums, 0, sizeof(Count)*m_NumPartialSums ); 61 | } 62 | 63 | virtual void ExecuteRange( TaskSetPartition range, uint32_t threadnum ) 64 | { 65 | rmt_ScopedCPUSample(Sum, 0); 66 | assert( m_pPartialSums && m_NumPartialSums ); 67 | uint64_t sum = m_pPartialSums[threadnum].count; 68 | for( uint64_t i = range.start; i < range.end; ++i ) 69 | { 70 | sum += i + 1; 71 | } 72 | m_pPartialSums[threadnum].count = sum; 73 | } 74 | 75 | }; 76 | 77 | struct ParallelReductionSumTaskSet : ITaskSet 78 | { 79 | ParallelSumTaskSet m_ParallelSumTaskSet; 80 | uint64_t m_FinalSum; 81 | 82 | ParallelReductionSumTaskSet( uint32_t size_ ) : m_ParallelSumTaskSet( size_ ), m_FinalSum(0) {} 83 | 84 | void Init() 85 | { 86 | m_ParallelSumTaskSet.Init(); 87 | } 88 | 89 | virtual void ExecuteRange( TaskSetPartition range, uint32_t threadnum ) 90 | { 91 | rmt_ScopedCPUSample(Reduce, 0); 92 | 93 | g_TS.AddTaskSetToPipe( &m_ParallelSumTaskSet ); 94 | g_TS.WaitforTask( &m_ParallelSumTaskSet ); 95 | 96 | for( uint32_t i = 0; i < m_ParallelSumTaskSet.m_NumPartialSums; ++i ) 97 | { 98 | m_FinalSum += m_ParallelSumTaskSet.m_pPartialSums[i].count; 99 | } 100 | } 101 | }; 102 | 103 | void threadStartCallback( uint32_t threadnum_ ) 104 | { 105 | std::ostringstream out; 106 | out << "enkiTS_" << threadnum_; 107 | rmt_SetCurrentThreadName( out.str().c_str() ); 108 | } 109 | 110 | void waitForNewTaskSuspendStartCallback( uint32_t threadnum_ ) 111 | { 112 | rmt_BeginCPUSample(WaitForNewTaskSuspend, 0); 113 | } 114 | 115 | void waitForTaskCompleteStartCallback( uint32_t threadnum_ ) 116 | { 117 | rmt_BeginCPUSample(WaitForTaskComplete, 0); 118 | } 119 | 120 | void waitForTaskCompleteSuspendStartCallback( uint32_t threadnum_ ) 121 | { 122 | rmt_BeginCPUSample(WaitForTaskCompleteSuspend, 0); 123 | } 124 | 125 | void stopCallback( uint32_t threadnum_ ) 126 | { 127 | rmt_EndCPUSample(); 128 | } 129 | 130 | int main(int argc, const char * argv[]) 131 | { 132 | // the example generates a lot of samples, so increase update rate for profiler 133 | rmt_Settings()->maxNbMessagesPerUpdate = 128 * rmt_Settings()->maxNbMessagesPerUpdate; 134 | 135 | Remotery* rmt; 136 | rmt_CreateGlobalInstance(&rmt); 137 | 138 | enki::TaskSchedulerConfig tsConfig; 139 | tsConfig.profilerCallbacks.threadStart = threadStartCallback; 140 | tsConfig.profilerCallbacks.waitForNewTaskSuspendStart = waitForNewTaskSuspendStartCallback; 141 | tsConfig.profilerCallbacks.waitForNewTaskSuspendStop = stopCallback; 142 | tsConfig.profilerCallbacks.waitForTaskCompleteStart = waitForTaskCompleteStartCallback; 143 | tsConfig.profilerCallbacks.waitForTaskCompleteStop = stopCallback; 144 | tsConfig.profilerCallbacks.waitForTaskCompleteSuspendStart = waitForTaskCompleteSuspendStartCallback; 145 | tsConfig.profilerCallbacks.waitForTaskCompleteSuspendStop = stopCallback; 146 | 147 | g_TS.Initialize( tsConfig ); 148 | 149 | 150 | rmt_SetCurrentThreadName("Main"); 151 | 152 | double avSpeedUp = 0.0; 153 | for( int run = 0; run< RUNS; ++run ) 154 | { 155 | rmt_ScopedCPUSample(Run, 0); 156 | 157 | printf("Run %d\t Open Remotery\\vis\\index.html to view profiler\n", run); 158 | ParallelReductionSumTaskSet m_ParallelReductionSumTaskSet( SUMS ); 159 | { 160 | rmt_ScopedCPUSample(Parallel, 0); 161 | 162 | m_ParallelReductionSumTaskSet.Init(); 163 | 164 | g_TS.AddTaskSetToPipe(&m_ParallelReductionSumTaskSet); 165 | 166 | g_TS.WaitforTask(&m_ParallelReductionSumTaskSet); 167 | } 168 | 169 | 170 | 171 | uint64_t sum = 0; 172 | { 173 | rmt_ScopedCPUSample(Serial, 0); 174 | for (uint64_t i = 0; i < (uint64_t)m_ParallelReductionSumTaskSet.m_ParallelSumTaskSet.m_SetSize; ++i) 175 | { 176 | sum += i + 1; 177 | } 178 | } 179 | printf("Sun Parallel: %" PRIu64 ", sum serial %" PRIu64, m_ParallelReductionSumTaskSet.m_FinalSum, sum ); 180 | if( m_ParallelReductionSumTaskSet.m_FinalSum == sum ) 181 | { 182 | printf(" - Sums Correct.\n"); 183 | } 184 | else 185 | { 186 | assert(false); 187 | printf(" - Sums ERROR.\n"); 188 | } 189 | 190 | } 191 | g_TS.WaitforAllAndShutdown(); 192 | rmt_DestroyGlobalInstance(rmt); 193 | return 0; 194 | } 195 | -------------------------------------------------------------------------------- /images/enkiTSMicroprofileExample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dougbinks/enkiTSExamples/b0438f94ff99203fb6eb01c8871ea3f5b1bbecf5/images/enkiTSMicroprofileExample.png -------------------------------------------------------------------------------- /images/enkiTSRemoteryExample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dougbinks/enkiTSExamples/b0438f94ff99203fb6eb01c8871ea3f5b1bbecf5/images/enkiTSRemoteryExample.png --------------------------------------------------------------------------------