/ani/mrses

To get this branch, use:
bzr branch http://suren.me/webbzr/ani/mrses
1 by Suren A. Chilingaryan
Initial import
1
#define _GNU_SOURCE
2
3
#include <stdio.h>
4
#include <stdlib.h>
5
#include <string.h>
6
#include <sys/types.h>
7
#include <unistd.h>
8
#include <sched.h>
9
#include <pthread.h>
10
#include <errno.h>
11
12
#include "msg.h"
13
#include "hw_sched.h"
14
15
#include "mrses_ppu.h"
16
17
#ifdef HW_HAVE_SPU
18
# include <libspe2.h>
19
# include "mrses_spu.h"
20
21
extern spe_program_handle_t mrses_spe;
22
#endif /* HW_HAVE_SPU */
23
24
25
#define MUTEX_INIT(ctx, name) \
26
    if (!err) err = pthread_mutex_init(&ctx->name##_mutex, NULL);
27
    
28
#define MUTEX_FREE(ctx, name) \
29
    pthread_mutex_destroy(&ctx->name##_mutex);
30
31
#define COND_INIT(ctx, name) \
32
    MUTEX_INIT(ctx, name##_cond) \
33
    if (!err) { \
34
	err = pthread_cond_init(&ctx->name##_cond, NULL); \
35
	if (err) { MUTEX_FREE(ctx, name##_cond) } \
36
    }
37
38
#define COND_FREE(ctx, name) \
39
    pthread_cond_destroy(&ctx->name##_cond); \
40
    MUTEX_FREE(ctx, name##_cond)
41
42
HWRunFunction ppu_run[] = {
43
    (HWRunFunction)mrses_ppu_run,
44
    (HWRunFunction)mrses_ppu_iterate,
45
    NULL
46
};
47
48
#ifdef HW_HAVE_SPU
49
HWRunFunction spu_run[] = {
50
    (HWRunFunction)mrses_spu_run,
51
    (HWRunFunction)mrses_spu_iterate,
52
    NULL
53
};
54
#endif /* HW_HAVE_SPU */
55
56
HWSched hw_sched_create() {
57
    int i;
58
    int err = 0;
59
    cpu_set_t mask;
60
61
    int ppu_count;
62
    HWSched ctx;
63
    
64
#ifdef HW_HAVE_SPU
65
    int spu_count;
66
    spe_context_ptr_t spe;
67
#endif /* HW_HAVE_SPU */
68
69
    ctx = (HWSched)malloc(sizeof(HWSchedS));
70
    if (!ctx) return NULL;
71
72
    memset(ctx, 0, sizeof(HWSchedS));
73
74
    ctx->status = 1;
75
76
    MUTEX_INIT(ctx, data);
77
78
    COND_INIT(ctx, compl);
79
    if (err) {
80
	MUTEX_FREE(ctx, data);
81
    }
82
83
    COND_INIT(ctx, job);
84
    if (err) {
85
	COND_FREE(ctx, compl);
86
	MUTEX_FREE(ctx, data);
87
    } else {
88
	ctx->sync_init = 1;
89
    }
90
    
91
    if (err) {
92
	fprintf(stderr, "Error initializing conditions and mutexes, errnon: %i\n", errno);
93
	hw_sched_destroy(ctx);
94
	return NULL;
95
    }
96
97
98
    err = sched_getaffinity(getpid(), sizeof(mask), &mask);
99
100
#ifdef CPU_COUNT
101
    ppu_count = CPU_COUNT(&mask);
102
#else
103
    for (ppu_count = 0; ppu_count < CPU_SETSIZE; ppu_count++) {
104
	if (!CPU_ISSET(ppu_count, &mask)) break;
105
    }
106
#endif
107
108
#ifdef HW_MAX_PPU
109
    if (ppu_count > HW_MAX_PPU) ppu_count = HW_MAX_PPU;
110
#endif /* HW_MAX_PPU */
111
112
    ctx->n_threads = 0;
113
    for (i = 0; i < ppu_count; i++) {
114
	ctx->thread[ctx->n_threads] = hw_thread_create(ctx, ctx->n_threads, NULL, ppu_run, NULL);
115
	if (ctx->thread[ctx->n_threads]) ++ctx->n_threads;
116
    }
117
    
118
#ifdef HW_HAVE_SPU
119
    spu_count = spe_cpu_info_get(SPE_COUNT_USABLE_SPES, -1);
120
    if ((spu_count + ctx->n_threads) > HW_MAX_THREADS) spu_count = HW_MAX_THREADS - ctx->n_threads;
121
122
#ifdef HW_MAX_SPU
123
    if (spu_count > HW_MAX_SPU) spu_count = HW_MAX_SPU;
124
#endif /* HW_MAX_SPU */
125
126
    for (i = 0; i < spu_count; i++) {
127
	spe = spe_context_create (0, NULL);
128
	if (spe == NULL) {
129
    	    reportError("Failed to create SPE context");
130
	    hw_sched_destroy(ctx);
131
	    return NULL;
132
	}
133
	
134
	err = spe_program_load (spe, &mrses_spe);
135
        if (err) {
136
    	    reportError("Failed to load program into the SPE, error: %i", err);
137
	    return NULL;
138
	}
139
140
	ctx->thread[ctx->n_threads] = hw_thread_create(ctx, ctx->n_threads, spe, spu_run, (HWFreeFunction)spe_context_destroy);
141
	if (ctx->thread[ctx->n_threads]) ++ctx->n_threads;
142
    }
143
144
    reportMessage("ppu: %i, spu: %i", ppu_count, spu_count);
145
#else /* HW_HAVE_SPU */
146
    reportMessage("threads: %i", ppu_count);
147
#endif /* HW_HAVE_SPU */
148
149
150
    return ctx;
151
}
152
153
static int hw_sched_wait_threads(HWSched ctx) {
154
    int i = 0;
155
    
156
    hw_sched_lock(ctx, compl_cond);
157
    while (i < ctx->n_threads) {
158
        for (; i < ctx->n_threads; i++) {
159
	    if (ctx->thread[i]->status == HW_THREAD_STATUS_INIT) {
160
		hw_sched_wait(ctx, compl);
161
		break;
162
	    }
163
	}
164
	
165
    }
166
    hw_sched_unlock(ctx, compl_cond);
167
    
168
    ctx->started = 1;
169
170
    return 0;
171
}
172
173
void hw_sched_destroy(HWSched ctx) {
174
    int i;
175
176
    if (ctx->n_threads > 0) {
177
	if (!ctx->started) {
178
	    hw_sched_wait_threads(ctx);
179
	}
180
181
	ctx->status = 0;
182
	hw_sched_lock(ctx, job_cond);
183
	hw_sched_broadcast(ctx, job);
184
	hw_sched_unlock(ctx, job_cond);
185
    
186
	for (i = 0; i < ctx->n_threads; i++) {
187
	    hw_thread_destroy(ctx->thread[i]);
188
	}
189
    }
190
191
    if (ctx->sync_init) {
192
        COND_FREE(ctx, job);
193
	COND_FREE(ctx, compl);
194
	MUTEX_FREE(ctx, data);
195
    }
196
197
    free(ctx);
198
}
199
200
int hw_sched_set_sequential_mode(HWSched ctx, int *n_blocks, int *cur_block) {
201
    ctx->mode = HW_SCHED_MODE_SEQUENTIAL;
202
    ctx->n_blocks = n_blocks;
203
    ctx->cur_block = cur_block;
204
    
205
    return 0;
206
}
207
208
int hw_sched_get_chunk(HWSched ctx, int thread_id) {
209
    int block;
210
211
    switch (ctx->mode) {
212
	case HW_SCHED_MODE_PREALLOCATED:
213
	    if (ctx->thread[thread_id]->status == HW_THREAD_STATUS_IDLE) {
214
		return thread_id;
215
	    } else {
216
		return -1;
217
	    }
218
	case HW_SCHED_MODE_SEQUENTIAL:
219
	    hw_sched_lock(ctx, data);
220
	    block = *ctx->cur_block;
221
	    if (block < *ctx->n_blocks) {
222
		*ctx->cur_block = *ctx->cur_block + 1;
223
	    } else {
224
		block = -1;
225
	    }
226
	    hw_sched_unlock(ctx, data);
227
	    return block;
228
	default:
229
	    return -1;
230
    }
231
232
    return -1;
233
}
234
235
    
236
int hw_sched_schedule_task(HWSched ctx, void *appctx, int entry) {
237
    if (!ctx->started) {
238
	hw_sched_wait_threads(ctx);
239
    }
240
    
241
    ctx->ctx = appctx;
242
    ctx->entry = entry;
243
    
244
    hw_sched_lock(ctx, compl_cond);
245
246
    hw_sched_lock(ctx, job_cond);
247
    hw_sched_broadcast(ctx, job);
248
    hw_sched_unlock(ctx, job_cond);
249
250
    return 0;
251
}
252
253
int hw_sched_wait_task(HWSched ctx) {
254
    int i = 0;
255
256
    while (i < ctx->n_threads) {
257
        for (; i < ctx->n_threads; i++) {
258
	    if (ctx->thread[i]->status == HW_THREAD_STATUS_DONE) {
259
		ctx->thread[i]->status = HW_THREAD_STATUS_IDLE;
260
	    } else {
261
		hw_sched_wait(ctx, compl);
262
		break;
263
	    }
264
	}
265
	
266
    }
267
268
/*        
269
    int i, running = 1;
270
271
	//wait all threads set running mode
272
273
    while (running) {
274
	hw_sched_wait(ctx, compl);
275
	
276
	running = 0;
277
        for (i = 0; i < ctx->n_threads; i++) {
278
	    if (ctx->thread[i]->status) {
279
		if (ctx->thread[i]->status == HW_THREAD_STATUS_DONE) {
280
		    ctx->thread[i]->status = HW_THREAD_STATUS_IDLE;
281
		} else {
282
		    running = 1;
283
		    break;
284
		}
285
	    }
286
	}
287
    }
288
*/
289
290
    hw_sched_unlock(ctx, compl_cond);
291
292
293
    return 0;
294
}