Welcome, guest! Login / Register - Why register?
Psst.. new poll here.
Psst.. new forums here.
Microsoft is blocking us again (TY IP Reputation!) so just use oauth login instead. :)

Paste

Pasted as Plain Text by ARGHTOS ( 14 years ago )
void hyperqsort(int *list, int size)
{
    printf("num threads: %d\n", NUM_T);
    int i;
    int num_t = NUM_T;
    omp_set_num_threads(num_t);

    // Each thread has two lists; these are swapped on every iteration
    // This is called trading memory for sanity, since I don't want to try it without this :)
    List lists[2][NUM_T];

    for (i = 0; i < NUM_T; i++)
    {
        initList(&lists;[0][i], size);
        initList(&lists;[1][i], size);
    }

    // Calculate the number of elements each thread starts with
    int thread_e = (int)(ceil((double)size / num_t));

    int median[NUM_T/2]; // median values used on each iteration
    int level = NUM_T; // current recursion level, represented as number of threads cooperating directly

    int cur = 0, buf = 1; // pointers to current and buffer lists; swapped every iteration
#pragma omp parallel 
    {
        int rank = omp_get_thread_num();
        int start = rank * thread_e;


        List *cur_li = &lists;[cur][rank];
        List *buf_li = &lists;[buf][rank];

        cur_li->size = MIN(thread_e, size-start); // last thread may have diff start size
        buf_li->size = 0;

        memcpy(cur_li->list, list + start, cur_li->size * sizeof(int));
        seqsort(cur_li->list, 0, cur_li->size-1);

        // loop until level = 1, meaning all threads have no one to work with
        while (level > 1)
        {
            int med_rank = rank/level; // index into median table for current thread

            // I'm lazy, okay?
            int cur_size = cur_li->size;

            // if rank % level = 0, this thread should calculate its median
            if (rank % level == 0)
                median[med_rank] = cur_li->list[cur_size/2];
#pragma omp barrier // points must be found after medians are calculated

            // this is an awesome way of figuring out what to send (copy) to where
            partition(cur_li->list, cur_size, median[med_rank], 
                    &cur;_li->lo_s, &cur;_li->lo_e, 
                    &cur;_li->hi_s, &cur;_li->hi_e);

#pragma omp barrier // low swap must happen after li and ho points have been found
            // low process sends list to high procs
            if (rank % level < level/2)
            {
                int swp_rank = rank+level/2;
                List *swp_li = &lists;[buf][swp_rank];

                // first, copy low into own swap buffer (redundant but symmetrical to high case)
                if (cur_li->lo_s != -1)
                {
                    memcpy(buf_li->list, 
                            cur_li->list, 
                            loSize(cur_li) * sizeof(int));

                    buf_li->size = loSize(cur_li);
                }
                // copy high into beginning of partner process list
                if (cur_li->hi_e != -1)
                {
                    memcpy(swp_li->list, 
                            cur_li->list + cur_li->hi_s, 
                            hiSize(cur_li) * sizeof(int));

                    swp_li->size = hiSize(cur_li);
                }                                
            }
#pragma omp barrier // high swap must happen after low is completed
            // high process sends list to low procs
            if (rank % level >= level/2)
            {
                int swp_rank = rank-level/2;

                List *swp_li = &lists;[buf][swp_rank];

                // copy high into own list (way easier than doing this in place here)
                if (cur_li->hi_e != -1)
                {
                    memcpy(buf_li->list + buf_li->size, 
                            cur_li->list + cur_li->hi_s, 
                            hiSize(cur_li) * sizeof(int));

                    buf_li->size += hiSize(cur_li);
                }
                // copy low into high part of partner process lists
                if (cur_li->lo_e != -1)
                {
                    memcpy(swp_li->list + swp_li->size,
                            cur_li->list,
                            loSize(cur_li) * sizeof(int));

                    swp_li->size += loSize(cur_li);
                }
            }
#pragma omp barrier // sort must happen after lists are copied
            seqsort(buf_li->list, 0, buf_li->size-1);
#pragma omp single
            {
                level /= 2; // reduce cooperating thread count
                // swap buffer indices
                buf ^= 1;
                cur ^= 1;
            }
#pragma omp barrier
            
            cur_li = &lists;[cur][rank]; 
            buf_li = &lists;[buf][rank];
            buf_li->size = 0;
        }
    }

    // doing this sequentially happens to be much easier
    int offset = 0;
    for (i = 0; i < NUM_T; i++)
    {
        memcpy(list + offset, lists[cur][i].list, lists[cur][i].size * sizeof(int));
        offset += lists[cur][i].size;
    }
}

 

Revise this Paste

Your Name: Code Language: