source: soft/giet_vm/applications/transpose/transpose_rw.c

Last change on this file was 772, checked in by meunier, 11 years ago
  • Ajout de l'application rosenfeld
  • Changement du nom du flag O_CREATE en O_CREAT
File size: 21.3 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////////
2// File : transpose.c
3// Date : september 2015
4// author : Alain Greiner
5///////////////////////////////////////////////////////////////////////////////////////
6// This multi-threaded aplication transposes a raw image (one pbyte per pixel).
7// It can run on a multi-processors, multi-clusters architecture, with one thread
8// per processor, and uses the POSIX threads API.
9// It does not use the CMA to display the result image.
10//
11// The main() function can be launched on any processor P[x,y,l].
12// It makes the initialisations, launch (N-1) threads to run the execute() function
13// on the (N-1) other processors than P[x,y,l], call himself the execute() function,
14// and finally call the instrument() function to display instrumentation results
15// when the parallel execution is completed.
16//
17// The input and output buffers containing the image are distributed in clusters.
18//
19// The execute() function read a set of lines from an input file on disk,
20// to the local buffer buf_in[x][y], transpose it, write the result to a remote buffer
21// buf_out[x'][y'], display the content of the local buffer buf_out[x][y] to the
22// frame buffer, and store it on disk to another output file.
23//
24// - The image size must fit the frame buffer size.
25// - The block size in block device must be 512 bytes.
26// - The number of clusters must be a power of 2 no larger than 256.
27// - The number of processors per cluster must be a power of 2 no larger than 4.
28///////////////////////////////////////////////////////////////////////////////////////
29
30#include "stdio.h"
31#include "stdlib.h"
32#include "user_barrier.h"
33#include "malloc.h"
34
35#define BLOCK_SIZE 512 // block size on disk
36#define X_MAX 16 // max number of clusters in row
37#define Y_MAX 16 // max number of clusters in column
38#define PROCS_MAX 4 // max number of procs per cluster
39#define CLUSTER_MAX (X_MAX * Y_MAX) // max number of clusters
40#define IMAGE_SIZE 256 // default image size
41#define INPUT_FILE_PATH "/misc/lena_256.raw" // default input file pathname
42#define OUTPUT_FILE_PATH "/home/lena_transposed.raw" // default output file pathname
43#define INTERACTIVE 0 // interactive capture of filenames
44#define VERBOSE 1
45
46
47// macro to use a shared TTY
48#define printf(...); { lock_acquire( &tty_lock ); \
49 giet_tty_printf(__VA_ARGS__); \
50 lock_release( &tty_lock ); }
51
52///////////////////////////////////////////////////////
53// global variables stored in seg_data in cluster(0,0)
54///////////////////////////////////////////////////////
55
56// instrumentation counters for each processor in each cluster
57unsigned int LOAD_START[X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
58unsigned int LOAD_END [X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
59unsigned int TRSP_START[X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
60unsigned int TRSP_END [X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
61unsigned int DISP_START[X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
62unsigned int DISP_END [X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
63unsigned int STOR_START[X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
64unsigned int STOR_END [X_MAX][Y_MAX][PROCS_MAX] = {{{ 0 }}};
65
66// arrays of pointers on distributed buffers
67// one input buffer & one output buffer per cluster
68unsigned char* buf_in [CLUSTER_MAX];
69unsigned char* buf_out[CLUSTER_MAX];
70
71// checksum variables
72unsigned check_line_before[1024];
73unsigned check_line_after[1024];
74
75// lock protecting shared TTY
76user_lock_t tty_lock;
77
78// synchronisation barrier (all threads)
79giet_sqt_barrier_t barrier;
80
81// input & output files pathname and size
82char input_file_name[256];
83char output_file_name[256];
84unsigned int image_size;
85
86////////////////////////////////////////////
87__attribute__ ((constructor)) void execute()
88////////////////////////////////////////////
89{
90 unsigned int l; // line index for loops
91 unsigned int p; // pixel index for loops
92
93 // get processor identifiers
94 unsigned int x_id; // x cluster coordinate
95 unsigned int y_id; // y cluster coordinate
96 unsigned int p_id; // local processor index
97
98 giet_proc_xyp( &x_id, &y_id, &p_id);
99
100 // get & check plat-form parameters
101 unsigned int x_size; // number of clusters in a row
102 unsigned int y_size; // number of clusters in a column
103 unsigned int nprocs; // number of processors per cluster
104
105 giet_procs_number( &x_size , &y_size , &nprocs );
106
107 unsigned int nclusters = x_size * y_size; // number of clusters
108 unsigned int nthreads = x_size * y_size * nprocs; // number of threads
109 unsigned int npixels = image_size * image_size; // pixels per image
110 int fd_in = 0; // initial file descriptor
111 int fd_out = 0; // output file descriptor
112 unsigned int cluster_id = (x_id * y_size) + y_id; // "continuous" index
113 unsigned int thread_id = (cluster_id * nprocs) + p_id; // "continuous" thread index
114
115 // parallel load of image:
116 // allocate buf_in and buf_out distributed buffers (one buf_in & one buf_out per cluster).
117 // open input and output files, and load the relevant lines in local buf_in.
118 // only thread running on processor[x,y,0] does it.
119
120 LOAD_START[x_id][y_id][p_id] = giet_proctime();
121
122 if ( p_id == 0 )
123 {
124 buf_in[cluster_id] = remote_malloc( npixels/nclusters, x_id, y_id );
125 buf_out[cluster_id] = remote_malloc( npixels/nclusters, x_id, y_id );
126
127 if ( (x_id==0) && (y_id==0) )
128 {
129 printf("\n[TRANSPOSE] Proc [%d,%d,%d] completes buffer allocation at cycle %d\n",
130 x_id, y_id, p_id, giet_proctime() );
131 }
132
133 // open input file
134 fd_in = giet_fat_open( input_file_name , O_RDONLY ); // read_only
135 if ( fd_in < 0 )
136 {
137 printf("\n[TRANSPOSE ERROR] Proc [%d,%d,%d] cannot open file %s\n",
138 x_id , y_id , p_id , input_file_name );
139 giet_pthread_exit(" open() failure");
140 }
141 else if ( (x_id==0) && (y_id==0) )
142 {
143 printf("\n[TRANSPOSE] Proc [0,0,0] open file %s / fd = %d\n",
144 input_file_name , fd_in );
145 }
146
147 // open output file
148 fd_out = giet_fat_open( output_file_name , O_CREAT ); // create if required
149 if ( fd_out < 0 )
150 {
151 printf("\n[TRANSPOSE ERROR] Proc [%d,%d,%d] cannot open file %s\n",
152 x_id , y_id , p_id , output_file_name );
153 giet_pthread_exit(" open() failure");
154 }
155 else if ( (x_id==0) && (y_id==0) )
156 {
157 printf("\n[TRANSPOSE] Proc [0,0,0] open file %s / fd = %d\n",
158 output_file_name , fd_out );
159 }
160
161
162 unsigned int offset = ((npixels*cluster_id)/nclusters);
163 if ( giet_fat_lseek( fd_in,
164 offset,
165 SEEK_SET ) != offset )
166 {
167 printf("\n[TRANSPOSE ERROR] Proc [%d,%d,%d] cannot seek fd = %d\n",
168 x_id , y_id , p_id , fd_in );
169 giet_pthread_exit(" seek() failure");
170 }
171
172 unsigned int pixels = npixels / nclusters;
173 if ( giet_fat_read( fd_in,
174 buf_in[cluster_id],
175 pixels ) != pixels )
176 {
177 printf("\n[TRANSPOSE ERROR] Proc [%d,%d,%d] cannot read fd = %d\n",
178 x_id , y_id , p_id , fd_in );
179 giet_pthread_exit(" read() failure");
180 }
181
182 if ( (x_id==0) && (y_id==0) )
183 {
184 printf("\n[TRANSPOSE] Proc [%d,%d,%d] completes load at cycle %d\n",
185 x_id, y_id, p_id, giet_proctime() );
186 }
187 }
188
189 LOAD_END[x_id][y_id][p_id] = giet_proctime();
190
191 /////////////////////////////
192 sqt_barrier_wait( &barrier );
193 /////////////////////////////
194
195 // parallel transpose from buf_in to buf_out
196 // each thread makes the transposition for nlt lines (nlt = image_size/nthreads)
197 // from line [thread_id*nlt] to line [(thread_id + 1)*nlt - 1]
198 // (p,l) are the absolute pixel coordinates in the source image
199
200 TRSP_START[x_id][y_id][p_id] = giet_proctime();
201
202 unsigned int nlt = image_size / nthreads; // number of lines per thread
203 unsigned int nlc = image_size / nclusters; // number of lines per cluster
204
205 unsigned int src_cluster;
206 unsigned int src_index;
207 unsigned int dst_cluster;
208 unsigned int dst_index;
209
210 unsigned char byte;
211
212 unsigned int first = thread_id * nlt; // first line index for a given thread
213 unsigned int last = first + nlt; // last line index for a given thread
214
215 for ( l = first ; l < last ; l++ )
216 {
217 check_line_before[l] = 0;
218
219 // in each iteration we transfer one byte
220 for ( p = 0 ; p < image_size ; p++ )
221 {
222 // read one byte from local buf_in
223 src_cluster = l / nlc;
224 src_index = (l % nlc)*image_size + p;
225 byte = buf_in[src_cluster][src_index];
226
227 // compute checksum
228 check_line_before[l] = check_line_before[l] + byte;
229
230 // write one byte to remote buf_out
231 dst_cluster = p / nlc;
232 dst_index = (p % nlc)*image_size + l;
233 buf_out[dst_cluster][dst_index] = byte;
234 }
235 }
236
237 if ( (p_id == 0) && (x_id==0) && (y_id==0) )
238 {
239 printf("\n[TRANSPOSE] proc [%d,%d,%d] completes transpose at cycle %d\n",
240 x_id, y_id, p_id, giet_proctime() );
241 }
242
243 TRSP_END[x_id][y_id][p_id] = giet_proctime();
244
245 /////////////////////////////
246 sqt_barrier_wait( &barrier );
247 /////////////////////////////
248
249 // parallel display from local buf_out to frame buffer
250 // all threads contribute to display using memcpy...
251
252 DISP_START[x_id][y_id][p_id] = giet_proctime();
253
254 unsigned int npt = npixels / nthreads; // number of pixels per thread
255
256 giet_fbf_sync_write( npt * thread_id,
257 &buf_out[cluster_id][p_id*npt],
258 npt );
259
260 if ( (x_id==0) && (y_id==0) && (p_id==0) )
261 {
262 printf("\n[TRANSPOSE] Proc [%d,%d,%d] completes display at cycle %d\n",
263 x_id, y_id, p_id, giet_proctime() );
264 }
265
266 DISP_END[x_id][y_id][p_id] = giet_proctime();
267
268 /////////////////////////////
269 sqt_barrier_wait( &barrier );
270 /////////////////////////////
271
272 // parallel store : buf_out buffers to disk
273 // only thread running on processor(x,y,0) does it
274
275 STOR_START[x_id][y_id][p_id] = giet_proctime();
276
277 if ( p_id == 0 )
278 {
279 unsigned int offset = ((npixels*cluster_id)/nclusters);
280 if ( giet_fat_lseek( fd_out,
281 offset,
282 SEEK_SET ) != offset )
283 {
284 printf("\n[TRANSPOSE ERROR] Proc [%d,%d,%d] cannot seek fr = %d\n",
285 x_id , y_id , p_id , fd_out );
286 giet_pthread_exit(" seek() failure");
287 }
288
289 unsigned int pixels = npixels / nclusters;
290 if ( giet_fat_write( fd_out,
291 buf_out[cluster_id],
292 pixels ) != pixels )
293 {
294 printf("\n[TRANSPOSE ERROR] Proc [%d,%d,%d] cannot write fd = %d\n",
295 x_id , y_id , p_id , fd_out );
296 giet_pthread_exit(" write() failure");
297 }
298
299 if ( (x_id==0) && (y_id==0) )
300 {
301 printf("\n[TRANSPOSE] Proc [%d,%d,%d] completes store at cycle %d\n",
302 x_id, y_id, p_id, giet_proctime() );
303 }
304 }
305
306 STOR_END[x_id][y_id][p_id] = giet_proctime();
307
308 // In each cluster, only thread running on Processor[x,y,0] releases
309 // the distributed buffers and close the file descriptors.
310
311 if ( p_id==0 )
312 {
313 free( buf_in[cluster_id] );
314 free( buf_out[cluster_id] );
315
316 giet_fat_close( fd_in );
317 giet_fat_close( fd_out );
318 }
319
320 if ( (x_id != 0) || (y_id != 0) || (p_id != 0) )
321 giet_pthread_exit( "completed" );
322
323} // end execute()
324
325
326
327//////////////////////////////////////
328void instrument( unsigned int x_size,
329 unsigned int y_size,
330 unsigned int nprocs )
331//////////////////////////////////////
332{
333 unsigned int x, y, l;
334
335 unsigned int min_load_start = 0xFFFFFFFF;
336 unsigned int max_load_start = 0;
337 unsigned int min_load_ended = 0xFFFFFFFF;
338 unsigned int max_load_ended = 0;
339 unsigned int min_trsp_start = 0xFFFFFFFF;
340 unsigned int max_trsp_start = 0;
341 unsigned int min_trsp_ended = 0xFFFFFFFF;
342 unsigned int max_trsp_ended = 0;
343 unsigned int min_disp_start = 0xFFFFFFFF;
344 unsigned int max_disp_start = 0;
345 unsigned int min_disp_ended = 0xFFFFFFFF;
346 unsigned int max_disp_ended = 0;
347 unsigned int min_stor_start = 0xFFFFFFFF;
348 unsigned int max_stor_start = 0;
349 unsigned int min_stor_ended = 0xFFFFFFFF;
350 unsigned int max_stor_ended = 0;
351
352 for (x = 0; x < x_size; x++)
353 {
354 for (y = 0; y < y_size; y++)
355 {
356 for ( l = 0 ; l < nprocs ; l++ )
357 {
358 if (LOAD_START[x][y][l] < min_load_start) min_load_start = LOAD_START[x][y][l];
359 if (LOAD_START[x][y][l] > max_load_start) max_load_start = LOAD_START[x][y][l];
360 if (LOAD_END[x][y][l] < min_load_ended) min_load_ended = LOAD_END[x][y][l];
361 if (LOAD_END[x][y][l] > max_load_ended) max_load_ended = LOAD_END[x][y][l];
362 if (TRSP_START[x][y][l] < min_trsp_start) min_trsp_start = TRSP_START[x][y][l];
363 if (TRSP_START[x][y][l] > max_trsp_start) max_trsp_start = TRSP_START[x][y][l];
364 if (TRSP_END[x][y][l] < min_trsp_ended) min_trsp_ended = TRSP_END[x][y][l];
365 if (TRSP_END[x][y][l] > max_trsp_ended) max_trsp_ended = TRSP_END[x][y][l];
366 if (DISP_START[x][y][l] < min_disp_start) min_disp_start = DISP_START[x][y][l];
367 if (DISP_START[x][y][l] > max_disp_start) max_disp_start = DISP_START[x][y][l];
368 if (DISP_END[x][y][l] < min_disp_ended) min_disp_ended = DISP_END[x][y][l];
369 if (DISP_END[x][y][l] > max_disp_ended) max_disp_ended = DISP_END[x][y][l];
370 if (STOR_START[x][y][l] < min_stor_start) min_stor_start = STOR_START[x][y][l];
371 if (STOR_START[x][y][l] > max_stor_start) max_stor_start = STOR_START[x][y][l];
372 if (STOR_END[x][y][l] < min_stor_ended) min_stor_ended = STOR_END[x][y][l];
373 if (STOR_END[x][y][l] > max_stor_ended) max_stor_ended = STOR_END[x][y][l];
374 }
375 }
376 }
377
378 printf("\n ---------------- Instrumentation Results ---------------------\n");
379
380 printf(" - LOAD_START : min = %d / max = %d / med = %d / delta = %d\n",
381 min_load_start, max_load_start, (min_load_start+max_load_start)/2,
382 max_load_start-min_load_start);
383
384 printf(" - LOAD_END : min = %d / max = %d / med = %d / delta = %d\n",
385 min_load_ended, max_load_ended, (min_load_ended+max_load_ended)/2,
386 max_load_ended-min_load_ended);
387
388 printf(" - TRSP_START : min = %d / max = %d / med = %d / delta = %d\n",
389 min_trsp_start, max_trsp_start, (min_trsp_start+max_trsp_start)/2,
390 max_trsp_start-min_trsp_start);
391
392 printf(" - TRSP_END : min = %d / max = %d / med = %d / delta = %d\n",
393 min_trsp_ended, max_trsp_ended, (min_trsp_ended+max_trsp_ended)/2,
394 max_trsp_ended-min_trsp_ended);
395
396 printf(" - DISP_START : min = %d / max = %d / med = %d / delta = %d\n",
397 min_disp_start, max_disp_start, (min_disp_start+max_disp_start)/2,
398 max_disp_start-min_disp_start);
399
400 printf(" - DISP_END : min = %d / max = %d / med = %d / delta = %d\n",
401 min_disp_ended, max_disp_ended, (min_disp_ended+max_disp_ended)/2,
402 max_disp_ended-min_disp_ended);
403
404 printf(" - STOR_START : min = %d / max = %d / med = %d / delta = %d\n",
405 min_stor_start, max_stor_start, (min_stor_start+max_stor_start)/2,
406 max_stor_start-min_stor_start);
407
408 printf(" - STOR_END : min = %d / max = %d / med = %d / delta = %d\n",
409 min_stor_ended, max_stor_ended, (min_stor_ended+max_stor_ended)/2,
410 max_stor_ended-min_stor_ended);
411
412} // end instrument()
413
414
415
416//////////////////////////////////////////
417__attribute__ ((constructor)) void main()
418//////////////////////////////////////////
419{
420 // indexes for loops
421 unsigned int x , y , n;
422
423 // get identifiers for proc executing main
424 unsigned int x_id; // x cluster coordinate
425 unsigned int y_id; // y cluster coordinate
426 unsigned int p_id; // local processor index
427
428 giet_proc_xyp( &x_id , &y_id , &p_id );
429
430 // get & check plat-form parameters
431 unsigned int x_size; // number of clusters in a row
432 unsigned int y_size; // number of clusters in a column
433 unsigned int nprocs; // number of processors per cluster
434
435 giet_procs_number( &x_size , &y_size , &nprocs );
436
437 giet_pthread_assert( ((nprocs == 1) || (nprocs == 2) || (nprocs == 4)),
438 "[TRANSPOSE ERROR] number of procs per cluster must be 1, 2 or 4");
439
440 giet_pthread_assert( ((x_size == 1) || (x_size == 2) || (x_size == 4) ||
441 (x_size == 8) || (x_size == 16)),
442 "[TRANSPOSE ERROR] x_size must be 1,2,4,8,16");
443
444 giet_pthread_assert( ((y_size == 1) || (y_size == 2) || (y_size == 4) ||
445 (y_size == 8) || (y_size == 16)),
446 "[TRANSPOSE ERROR] y_size must be 1,2,4,8,16");
447
448 // compute number of threads
449 unsigned int nthreads = x_size * y_size * nprocs;
450
451 // shared TTY allocation
452 giet_tty_alloc( 1 );
453 lock_init( &tty_lock);
454
455 // get FBF ownership and FBF size
456 unsigned int width;
457 unsigned int height;
458 giet_fbf_alloc();
459 giet_fbf_size( &width , &height );
460
461 printf("\n[TRANSPOSE] start at cycle %d on %d cores / FBF = %d * %d pixels\n",
462 giet_proctime(), nthreads , width , height );
463
464 if ( INTERACTIVE ) // input_file_name, output_file_name, and size acquisition
465 {
466 printf("\n[TRANSPOSE] enter path for input file / default is : %s\n> ", INPUT_FILE_PATH );
467 giet_tty_gets( input_file_name , 256 );
468 printf("\n");
469 if ( strcmp( input_file_name , "" ) == 0 ) strcpy( input_file_name , INPUT_FILE_PATH );
470
471 printf("\n[TRANSPOSE] enter path for output file / default is : %s\n> ", OUTPUT_FILE_PATH );
472 giet_tty_gets( output_file_name , 256 );
473 printf("\n");
474 if ( strcmp( output_file_name , "" ) == 0 ) strcpy( output_file_name , OUTPUT_FILE_PATH );
475
476 printf("\n[TRANSPOSE] enter image size / default is : %d\n> ", IMAGE_SIZE );
477 giet_tty_getw( &image_size );
478 printf("\n");
479 if ( image_size == 0 ) image_size = IMAGE_SIZE;
480 }
481 else
482 {
483 strcpy( input_file_name , INPUT_FILE_PATH );
484 strcpy( output_file_name , OUTPUT_FILE_PATH );
485 image_size = IMAGE_SIZE;
486 }
487
488 // check image size / number of threads
489 giet_pthread_assert( (nprocs * x_size * y_size <= image_size ),
490 "[TRANSPOSE ERROR] number of threads larger than number of lines");
491
492 printf("\n[TRANSPOSE] input = %s / output = %s / size = %d\n",
493 input_file_name, output_file_name, image_size );
494
495 // distributed heap initialisation
496 for ( x = 0 ; x < x_size ; x++ )
497 {
498 for ( y = 0 ; y < y_size ; y++ )
499 {
500 heap_init( x , y );
501 }
502 }
503
504 // allocate thread[] array
505 pthread_t* thread = malloc( nthreads * sizeof(pthread_t) );
506
507 // barrier initialisation
508 sqt_barrier_init( &barrier, x_size , y_size , nprocs );
509
510 // Initialisation completed
511 printf("\n[TRANSPOSE] initialisation completed at cycle %d\n", giet_proctime() );
512
513 // launch other threads to run execute() function
514 for ( n = 1 ; n < nthreads ; n++ )
515 {
516 if ( giet_pthread_create( &thread[n],
517 NULL, // no attribute
518 &execute,
519 NULL ) ) // no argument
520 {
521 printf("\n[TRANSPOSE ERROR] creating thread %x\n", thread[n] );
522 giet_pthread_exit( NULL );
523 }
524 }
525
526 // run the execute() function
527 execute();
528
529 // wait other threads completion
530 for ( n = 1 ; n < nthreads ; n++ )
531 {
532 if ( giet_pthread_join( thread[n], NULL ) )
533 {
534 printf("\n[TRANSPOSE ERROR] joining thread %x\n", thread[n] );
535 giet_pthread_exit( NULL );
536 }
537 else
538 {
539 printf("\n[TRANSPOSE] thread %x joined at cycle %d\n",
540 thread[n] , giet_proctime() );
541 }
542 }
543
544 // call the instrument() function
545 instrument( x_size , y_size , nprocs );
546
547 giet_pthread_exit( "completed" );
548
549} // end main()
550
Note: See TracBrowser for help on using the repository browser.