Exemple #1
0
WEAK void *halide_worker_thread(void *void_arg) {
    work *owned_job = (work *)void_arg;

    // Grab the lock
    pthread_mutex_lock(&halide_work_queue.mutex);

    // If I'm a job owner, then I was the thread that called
    // do_par_for, and I should only stay in this function until my
    // job is complete. If I'm a lowly worker thread, I should stay in
    // this function as long as the work queue is running.
    while (owned_job != NULL ? owned_job->running()
           : halide_work_queue.running()) {

        if (halide_work_queue.jobs == NULL) {
            // There are no jobs pending, though some tasks may still
            // be in flight from the last job. Release the lock and
            // wait for something new to happen.
            pthread_cond_wait(&halide_work_queue.state_change, &halide_work_queue.mutex);
        } else {
            // There are jobs still to do. Grab the next one.
            work *job = halide_work_queue.jobs;

            // Claim a task from it.
            work myjob = *job;
            job->next++;

            // If there were no more tasks pending for this job, or if
            // it has failed, remove it from the stack.
            if (job->next == job->max) {
                halide_work_queue.jobs = job->next_job;
            }

            // Increment the active_worker count so that other threads
            // are aware that this job is still in progress even
            // though there are no outstanding tasks for it.
            job->active_workers++;

            // Release the lock and do the task.
            pthread_mutex_unlock(&halide_work_queue.mutex);
            int result = halide_do_task(myjob.f, myjob.next, myjob.closure);
            pthread_mutex_lock(&halide_work_queue.mutex);

            // If this task failed, set the exit status on the job.
            if (result) {
                job->exit_status = result;
            }

            // We are no longer active on this job
            job->active_workers--;

            // If the job is done and I'm not the owner of it, wake up
            // the owner.
            if (!job->running() && job != owned_job) {
                pthread_cond_broadcast(&halide_work_queue.state_change);
            }
        }
    }
    pthread_mutex_unlock(&halide_work_queue.mutex);
    return NULL;
}
Exemple #2
0
int halide_do_par_for(void *user_context, halide_task_t f,
                      int min, int size, uint8_t *closure) {
    for (int x = min; x < min + size; x++) {
        int result = halide_do_task(user_context, f, x, closure);
        if (result) {
            return result;
        }
    }
    return 0;
}
WEAK void halide_do_par_for(void (*f)(int, uint8_t *), int min, int size, uint8_t *closure) {
    if (halide_custom_do_par_for) {
        (*halide_custom_do_par_for)(f, min, size, closure);
        return;
    }

    for (int x = min; x < min + size; x++) {
        halide_do_task(f, x, closure);
    }
}
WEAK void *halide_worker_thread(void *void_arg) {
    /*
    int id = -1;
    for (int i = 0; i < threads-1; i++) {
        if (halide_work_queue.threads[i] == pthread_self()) id = i;
    }
    */
    worker_arg *arg = (worker_arg *)void_arg;
    //fprintf(stderr, "Worker %d: thread running\n", id);
    while (1) {
        //fprintf(stderr, "Worker %d: About to lock mutex\n", id);
        pthread_mutex_lock(&halide_work_queue.mutex);
        //fprintf(stderr, "Worker %d: Mutex locked, checking for work\n", id);

        // we're master, and there's no more work
        if (arg && arg->job->id != arg->id) {
            // wait until other workers are done
            if (arg->job->active_workers) {
                pthread_mutex_unlock(&halide_work_queue.mutex);
                while (true) {
                    //fprintf(stderr, "Master %d: waiting for workers to finish\n", arg->id);
                    pthread_mutex_lock(&halide_work_queue.mutex);
                    //fprintf(stderr, "Master %d: mutex grabbed. %d workers still going\n", arg->id, arg->job->active_workers);
                    if (!arg->job->active_workers)
                        break;
                    pthread_mutex_unlock(&halide_work_queue.mutex);
                }
            }
            // job is actually done
            pthread_mutex_unlock(&halide_work_queue.mutex);
            //fprintf(stderr, "Master %d: This task is done.\n", arg->id);
            return NULL;
        }

        if (halide_work_queue.shutdown) {
            pthread_mutex_unlock(&halide_work_queue.mutex);
            //fprintf(stderr, "Worker %d: quitting\n", id);
            return NULL;
        }
            
        if (halide_work_queue.head == halide_work_queue.tail) {
            //assert(!arg); // the master should never get here
            //fprintf(stderr, "Worker %d: Going to sleep.\n", id); fflush(stderr);
            pthread_cond_wait(&halide_work_queue.not_empty, &halide_work_queue.mutex);
            pthread_mutex_unlock(&halide_work_queue.mutex);
            //fprintf(stderr, "Worker %d: Waking up.\n", id); fflush(stderr);
            continue;
        }

        //fprintf(stderr, "Worker %d: There is work\n", id);
        work *job = halide_work_queue.jobs + halide_work_queue.head;
        if (job->next == job->max) {
            //fprintf(stderr, "Worker %d: Found a finished job. Removing it\n", id);
            halide_work_queue.head = (halide_work_queue.head + 1) % MAX_JOBS;            
            job->id = 0; // mark the job done
            pthread_mutex_unlock(&halide_work_queue.mutex);
        } else {
            // Claim some tasks
            //int claimed = (remaining + threads - 1)/threads;
            int claimed = 1;
            //fprintf(stderr, "Worker %d: Claiming %d tasks\n", id, claimed);
            work myjob = *job;
            job->next += claimed;            
            myjob.max = job->next;
            job->active_workers++;
            pthread_mutex_unlock(&halide_work_queue.mutex);
            for (; myjob.next < myjob.max; myjob.next++) {
                //fprintf(stderr, "Worker %d: Doing job %d\n", id, myjob.next);
                halide_do_task(myjob.f, myjob.next, myjob.closure);
                //fprintf(stderr, "Worker %d: Done with job %d\n", id, myjob.next);
            }
            pthread_mutex_lock(&halide_work_queue.mutex);
            job->active_workers--;
            pthread_mutex_unlock(&halide_work_queue.mutex);
        }        
    }
}
Exemple #5
0
// Take a call from grand-central-dispatch's parallel for loop, and
// make a call to Halide's do task
WEAK void halide_do_gcd_task(void *job, size_t idx) {
    halide_gcd_job *j = (halide_gcd_job *)job;
    j->exit_status = halide_do_task(j->user_context, j->f, j->min + (int)idx,
                                    j->closure);
}
Exemple #6
0
// Take a call from grand-central-dispatch's parallel for loop, and
// make a call to Halide's do task
WEAK void halide_do_gcd_task(void *job, size_t idx) {
    halide_gcd_job *j = (halide_gcd_job *)job;
    halide_do_task(j->f, j->min + (int)idx, j->closure);
}
Exemple #7
0
WEAK void *halide_worker_thread(void *void_arg) {
    work *owned_job = (work *)void_arg;

    // Grab the lock
    pthread_mutex_lock(&halide_work_queue.mutex);

    // If I'm a job owner, then I was the thread that called
    // do_par_for, and I should only stay in this function until my
    // job is complete. If I'm a lowly worker thread, I should stay in
    // this function as long as the work queue is running.
    while (owned_job != NULL ? owned_job->running()
           : halide_work_queue.running()) {

        if (halide_work_queue.jobs == NULL) {
            if (owned_job) {
                // There are no jobs pending. Wait for the last worker
                // to signal that the job is finished.
                pthread_cond_wait(&halide_work_queue.wakeup_owners, &halide_work_queue.mutex);
            } else if (halide_work_queue.a_team_size <= halide_work_queue.target_a_team_size) {
                // There are no jobs pending. Wait until more jobs are enqueued.
                pthread_cond_wait(&halide_work_queue.wakeup_a_team, &halide_work_queue.mutex);
            } else {
                // There are no jobs pending, and there are too many
                // threads in the A team. Transition to the B team
                // until the wakeup_b_team condition is fired.
                halide_work_queue.a_team_size--;
                pthread_cond_wait(&halide_work_queue.wakeup_b_team, &halide_work_queue.mutex);
                halide_work_queue.a_team_size++;
            }
        } else {
            // Grab the next job.
            work *job = halide_work_queue.jobs;

            // Claim a task from it.
            work myjob = *job;
            job->next++;

            // If there were no more tasks pending for this job,
            // remove it from the stack.
            if (job->next == job->max) {
                halide_work_queue.jobs = job->next_job;
            }

            // Increment the active_worker count so that other threads
            // are aware that this job is still in progress even
            // though there are no outstanding tasks for it.
            job->active_workers++;

            // Release the lock and do the task.
            pthread_mutex_unlock(&halide_work_queue.mutex);
            int result = halide_do_task(myjob.user_context, myjob.f, myjob.next,
                                        myjob.closure);
            pthread_mutex_lock(&halide_work_queue.mutex);

            // If this task failed, set the exit status on the job.
            if (result) {
                job->exit_status = result;
            }

            // We are no longer active on this job
            job->active_workers--;

            // If the job is done and I'm not the owner of it, wake up
            // the owner.
            if (!job->running() && job != owned_job) {
                pthread_cond_broadcast(&halide_work_queue.wakeup_owners);
            }
        }
    }
    pthread_mutex_unlock(&halide_work_queue.mutex);
    return NULL;
}