void ISPCLaunch(void **taskGroupPtr, void *func, void *data, int count) { TaskGroup *taskGroup; if (*taskGroupPtr == NULL) { InitTaskSystem(); taskGroup = AllocTaskGroup(); *taskGroupPtr = taskGroup; } else taskGroup = (TaskGroup *)(*taskGroupPtr); int baseIndex = taskGroup->AllocTaskInfo(count); for (int i = 0; i < count; ++i) { TaskInfo *ti = taskGroup->GetTaskInfo(baseIndex+i); ti->func = (TaskFuncType)func; ti->data = data; ti->taskIndex = i; ti->taskCount = count; } taskGroup->Launch(baseIndex, count); }
inline void TaskGroup::Sync() { DBG(fprintf(stderr, "syncing %p - %d unfinished\n", tg, numUnfinishedTasks)); while (numUnfinishedTasks > 0) { // All of the tasks in this group aren't finished yet. We'll try // to help out here since we don't have anything else to do... DBG(fprintf(stderr, "while syncing %p - %d unfinished\n", tg, numUnfinishedTasks)); // // Acquire the global task system mutex to grab a task to work on // int err; if ((err = pthread_mutex_lock(&taskSysMutex)) != 0) { fprintf(stderr, "Error from pthread_mutex_lock: %s\n", strerror(err)); exit(1); } TaskInfo *myTask = NULL; TaskGroup *runtg = this; if (waitingTasks.size() > 0) { int taskNumber = waitingTasks.back(); waitingTasks.pop_back(); if (waitingTasks.size() == 0) { // There's nothing left to start running from this group, // so remove it from the active task list. activeTaskGroups.erase(std::find(activeTaskGroups.begin(), activeTaskGroups.end(), this)); inActiveList = false; } myTask = GetTaskInfo(taskNumber); DBG(fprintf(stderr, "running task %d from group %p in sync\n", taskNumber, tg)); } else { // Other threads are already working on all of the tasks in // this group, so we can't help out by running one ourself. // We'll try to run one from another group to make ourselves // useful here. if (activeTaskGroups.size() == 0) { // No active task groups left--there's nothing for us to do. if ((err = pthread_mutex_unlock(&taskSysMutex)) != 0) { fprintf(stderr, "Error from pthread_mutex_unlock: %s\n", strerror(err)); exit(1); } // FIXME: We basically end up busy-waiting here, which is // extra wasteful in a world with hyper-threading. It would // be much better to put this thread to sleep on a // condition variable that was signaled when the last task // in this group was finished. #ifndef ISPC_IS_KNC usleep(1); #else _mm_delay_32(8); #endif continue; } // Get a task to run from another task group. runtg = activeTaskGroups.back(); assert(runtg->waitingTasks.size() > 0); int taskNumber = runtg->waitingTasks.back(); runtg->waitingTasks.pop_back(); if (runtg->waitingTasks.size() == 0) { // There's left to start running from this group, so remove // it from the active task list. activeTaskGroups.pop_back(); runtg->inActiveList = false; } myTask = runtg->GetTaskInfo(taskNumber); DBG(fprintf(stderr, "running task %d from other group %p in sync\n", taskNumber, runtg)); } if ((err = pthread_mutex_unlock(&taskSysMutex)) != 0) { fprintf(stderr, "Error from pthread_mutex_unlock: %s\n", strerror(err)); exit(1); } // // Do work for _myTask_ // // FIXME: bogus values for thread index/thread count here as well.. myTask->func(myTask->data, 0, 1, myTask->taskIndex, myTask->taskCount); // // Decrement the number of unfinished tasks counter // lMemFence(); lAtomicAdd(&runtg->numUnfinishedTasks, -1); } DBG(fprintf(stderr, "sync for %p done!n", tg)); }
static void * lTaskEntry(void *arg) { int threadIndex = (int)((int64_t)arg); int threadCount = nThreads; while (1) { int err; // // Wait on the semaphore until we're woken up due to the arrival of // more work. // if ((err = sem_wait(workerSemaphore)) != 0) { fprintf(stderr, "Error from sem_wait: %s\n", strerror(err)); exit(1); } // // Acquire the mutex // if ((err = pthread_mutex_lock(&taskSysMutex)) != 0) { fprintf(stderr, "Error from pthread_mutex_lock: %s\n", strerror(err)); exit(1); } if (activeTaskGroups.size() == 0) { // // Task queue is empty, go back and wait on the semaphore // if ((err = pthread_mutex_unlock(&taskSysMutex)) != 0) { fprintf(stderr, "Error from pthread_mutex_unlock: %s\n", strerror(err)); exit(1); } continue; } // // Get the last task group on the active list and the last task // from its waiting tasks list. // TaskGroup *tg = activeTaskGroups.back(); assert(tg->waitingTasks.size() > 0); int taskNumber = tg->waitingTasks.back(); tg->waitingTasks.pop_back(); if (tg->waitingTasks.size() == 0) { // We just took the last task from this task group, so remove // it from the active list. activeTaskGroups.pop_back(); tg->inActiveList = false; } if ((err = pthread_mutex_unlock(&taskSysMutex)) != 0) { fprintf(stderr, "Error from pthread_mutex_unlock: %s\n", strerror(err)); exit(1); } // // And now actually run the task // DBG(fprintf(stderr, "running task %d from group %p\n", taskNumber, tg)); TaskInfo *myTask = tg->GetTaskInfo(taskNumber); myTask->func(myTask->data, threadIndex, threadCount, myTask->taskIndex, myTask->taskCount); // // Decrement the "number of unfinished tasks" counter in the task // group. // lMemFence(); lAtomicAdd(&tg->numUnfinishedTasks, -1); } pthread_exit(NULL); return 0; }