Changes

Jump to: navigation, search

GPU621/Pragmatic

6,913 bytes added, 00:35, 21 November 2016
Added source code for Walkthrough Part I
====Source Code====
// Line 1 // Prepared by Vadym Karpenko // Debugging OpenMP (Without Parallel Stacks) // This program is using "Vector Magnitude - SPMD - Critical Version" and "Vector Magnitude - Work Sharing Version" examples. // Source: https://scs.senecac.on.ca/~gpu621/pages/content/omp_1.html #include <iostream> #include <string> #include <omp.h> #include <windows.h> #include <intrin.h> // Include for __debugbreak(); #define N_SIZE 1000000 void SetThreadName(DWORD dwThreadID, const char* threadName); void barrierFunction(int currentThread, int totalThrads); int main() { // Get a number of maximum threads. int maxNumThreads = omp_get_max_threads(); // A counter that will be shared between threads. int counterShared = 0; // A counter that will be private for each thread. int counterPrivate = 0; // NOTE: counterPrivate needs to be initialized by each thread. float* num = new float[N_SIZE]; // Initialize "num" array. for (int i = 0; i < N_SIZE; i++) { num[i] = 1.0f; } float magnitude = 0.0f; /*** Break and inspect initial threads in Threads window ***/ // Enter parallel region and set number of threads to maximum number of threads. #pragma omp parallel num_threads(maxNumThreads) shared(counterShared) private(counterPrivate) /*** Break and inspect "num" in Watch, Parallel Watch, and Locals windows ***/ { // Get current thread id. int threadId = omp_get_thread_num(); /*** Break and inspect "num" in Watch, Parallel Watch, and Locals windows again (Track with Memory window) ***/ int numThreads = omp_get_num_threads(); std::string threadName; // Display number of threads and identify each thread by id in the console using critical region (To ensure proper formatting). #pragma omp critical { // Display number of threads by only a master thread. #pragma omp master { std::cout << "Number of threads: " << numThreads << std::endl; } // Identify each thread by id for each thread. std::cout << "Forked a thread with id: " << threadId << std::endl; } // If a thread is not calling thread (Main Thread, or master thread), attempt to rename the thread. if (threadId != 0) { // Build a thread name. threadName = "GPU621 Thread - OpenMP ID: " + std::to_string(threadId); // Use "SetThreadName" function provided by Microsoft to rename calling (current) thread. SetThreadName((DWORD)-1, threadName.c_str()); } else { threadName = "Main Thread"; } // Wait until all the threads reach the barrier. #pragma omp barrier /*** Break and inspect all threads (New thread and name changes) in Threads window (Worker and monitor threads) ***/ // Display a message before each thread enters an SPMD loop. #pragma omp critical { std::cout << threadName << " enters SPMD loop..." << std::endl; } float sum = 0.0f; //counterPrivate = 0; // Uncomment this to initialize private variable. for (int i = threadId; i < N_SIZE; i += numThreads) { sum += num[i] * num[i]; /*** Break and inspect thread private varuable ("sum") accumulation in Parallel Watch window ***/ if (counterShared == threadId) { counterShared++; counterPrivate += counterShared; if (counterPrivate != counterShared) /*** Break and inspect thread shared and private varuables ("counterShared" and "counterPrivate") change each time a new thread reaches this point in Parallel Watch window ***/ { __debugbreak(); } } } // Accumulate into "magnitude" and display a message when each thread leaves an SPMD loop. #pragma omp critical { magnitude += sum; std::cout << threadName << " left SPMD loop..." << std::endl; } // Wait until all the threads reach the barrier. #pragma omp barrier /*** Break and inspect "magnitude" accumulation in Parallel Watch window ***/ #pragma omp master { // Reset "magnitude" and "num" array values on master thread. for (int i = 0; i < N_SIZE; i++) { num[i] = 1.0f; } magnitude = 0.0f; } // Wait until all the threads reach the barrier. #pragma omp barrier // Perform magnitude calculation using work sharing. #pragma omp for reduction(+:magnitude) for (int i = 0; i < N_SIZE; i++) { magnitude += num[i] * num[i]; /*** Break and inspect starting value of "i" for each thread based on "N_SIZE" in Parallel Watch window ***/ } // Wait until all the threads reach the barrier. #pragma omp barrier // Following block will create a deadlock condition because barrier will be encountered by each thread more than once (One of the threads will encounter barrier twice). #pragma omp for for (int i = 0; i <= numThreads; i++) { barrierFunction(i + 1, numThreads); // Call a function that contains a barrier from a parallel for region. } // Wait until all the threads reach the barrier. #pragma omp barrier /*** Break and change values of "counterPrivate" and "counterShared" to 101 on one of the threads in Parallel Watch window ***/ // If values were successfully modified, a message will be displayed in the console. if (counterPrivate == 101 && counterShared == 101) { std::cout << threadName << " successfully modified counters." << std::endl; } } std::cout << "Press any button to exit..."; std::getchar(); /*** Break and inspect "num" in Watch, Parallel Watch, and Locals windows ***/ return 0; } // This function is taken from https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx // It renames the thread specified by thread id. If thread id is -1, then specified thread // is calling thread. // Usage: SetThreadName ((DWORD)-1, "Enter thread name here"); const DWORD MS_VC_EXCEPTION = 0x406D1388; #pragma pack(push,8) typedef struct tagTHREADNAME_INFO { DWORD dwType; // Must be 0x1000. LPCSTR szName; // Pointer to name (in user addr space). DWORD dwThreadID; // Thread ID (-1=caller thread). DWORD dwFlags; // Reserved for future use, must be zero. } THREADNAME_INFO; #pragma pack(pop) void SetThreadName(DWORD dwThreadID, const char* threadName) { THREADNAME_INFO info; info.dwType = 0x1000; info.szName = threadName; info.dwThreadID = dwThreadID; info.dwFlags = 0; #pragma warning(push) #pragma warning(disable: 6320 6322) __try { RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); } __except (EXCEPTION_EXECUTE_HANDLER) {} #pragma warning(pop) } // barrierFunction() function allows to create deadlock condition. void barrierFunction(int currentThread, int totalThrads) { #pragma omp critical { std::cout << "Thread number " << currentThread << " reached barrierFunction()" << std::endl; } // Wait until all the threads reach the barrier. #pragma omp barrier }
===Part II: Debugging a simple application using the Parallel Stacks window (By Oleksandr Zhurbenko)===
54
edits

Navigation menu