1/**
2 * \file
3 * \brief API to use the bomp library
4 */
5
6/*
7 * Copyright (c)2014 ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <bomp_internal.h>
16
17void bomp_start_processing(void (*fn)(void *),
18                           void *data,
19                           coreid_t tid_start,
20                           coreid_t nthreads)
21{
22    struct bomp_tls *tls = thread_get_tls();
23
24    debug_printf("bomp_start_processing(%p, %p, %u, %u)\n", fn, data, tid_start, nthreads);
25
26    /* this function must only be called by the program and node masters */
27    assert(tls->role == BOMP_THREAD_ROLE_MASTER || tls->role == BOMP_THREAD_ROLE_NODE);
28
29    /* add one to the tid_start as this will be our ID */
30    coreid_t tid_current = tid_start + 1;
31
32    struct bomp_node *node;
33
34    if (tls->role == BOMP_THREAD_ROLE_MASTER) {
35        node = &tls->r.master.local;
36
37        if (nthreads > (node->threads_max + 1)) {
38            /* send the requests to the node masters */
39            nthreads -= (node->threads_max + 1);
40            for (nodeid_t i = 0; i < tls->r.master.num_nodes; ++i) {
41                coreid_t num = bomp_node_exec(&tls->r.master.nodes[i], fn, data, tid_start, nthreads);
42                assert(num <= nthreads);
43                tls->r.master.nodes_active++;
44                nthreads -= num;
45                tid_current += num;
46                if (nthreads == 0) {
47                    break;
48                }
49            }
50            nthreads += (node->threads_max);
51        }
52    } else if (tls->role == BOMP_THREAD_ROLE_NODE) {
53        node = &tls->r.node;
54    }
55
56    debug_printf("nthreads=%u, max_threads=%u\n", nthreads, node->threads_max);
57
58    assert((node->threads_max + 1)>= nthreads);
59
60    struct omp_icv_task *icv = bomp_icv_get()->task;
61
62    for (coreid_t i = 1; i < nthreads; ++i) {
63        node->threads[i].icvt = icv;
64        node->threads_active++;
65        bomp_thread_exec(&node->threads[i], fn, data, tid_current);
66        tid_current++;
67    }
68
69    /* set the local thread ID */
70    tls->thread_id = 0;
71
72    return;
73#if 0
74    /* Create Threads and ask them to process the function specified */
75    /* Let them die as soon as they are done */
76    unsigned i;
77    struct bomp_work *xdata;
78    struct bomp_barrier *barrier;
79
80    g_bomp_state->num_threads = nthreads;
81
82    char *memory = calloc(
83                    1,
84                    nthreads * sizeof(struct bomp_thread_local_data *)
85                                    + sizeof(struct bomp_barrier)
86                                    + nthreads * sizeof(struct bomp_work));
87    assert(memory != NULL);
88
89    g_bomp_state->tld = (struct bomp_thread_local_data **) memory;
90    memory += nthreads * sizeof(struct bomp_thread_local_data *);
91
92    /* Create a barier for the work that will be carried out by the threads */
93    barrier = (struct bomp_barrier *) memory;
94    memory += sizeof(struct bomp_barrier);
95    bomp_barrier_init(barrier, nthreads);
96
97    /* For main thread */
98    xdata = (struct bomp_work *) memory;
99    memory += sizeof(struct bomp_work);
100
101    xdata->fn = fn;
102    xdata->data = data;
103    xdata->thread_id = 0;
104    xdata->barrier = barrier;
105    bomp_set_tls(xdata);
106
107    for (i = 1; i < nthreads; i++) {
108        xdata = (struct bomp_work *) memory;
109        memory += sizeof(struct bomp_work);
110
111        xdata->fn = fn;
112        xdata->data = data;
113        xdata->thread_id = i;
114        xdata->barrier = barrier;
115
116        /* Create threads */
117        bomp_run_on(i * BOMP_DEFAULT_CORE_STRIDE + THREAD_OFFSET, bomp_thread_fn,
118                    xdata);
119    }
120#endif
121}
122
123void bomp_end_processing(void)
124{
125    debug_printf("bomp_end_processing\n");
126    struct bomp_tls *tls = thread_get_tls();
127    struct waitset *ws = get_default_waitset();
128    if (tls->role == BOMP_THREAD_ROLE_MASTER) {
129        struct bomp_node *node = &tls->r.master.local;
130        struct bomp_master *master = &tls->r.master;
131        while(master->nodes_active != 1 || node->threads_active != 1) {
132            event_dispatch(ws);
133        }
134    } else if (tls->role == BOMP_THREAD_ROLE_NODE) {
135        struct bomp_node *node = &tls->r.node;
136        while(node->threads_active != 0) {
137            event_dispatch(ws);
138        }
139    }
140
141    free(tls->icv.task);
142    tls->icv.task = NULL;
143
144    debug_printf("bomp_end_processing: done\n");
145}
146