source: soft/giet_vm/applications/mjpeg/mjpeg.c

Last change on this file was 782, checked in by alain, 9 years ago

1) Introduce the string library.
2) Introduce a heap in the shell application.

File size: 19.4 KB
Line 
1/////////////////////////////////////////////////////////////////////////////////////////
2// File   : mjpeg.c   
3// Date   : octobre 2015
4// author : Alain Greiner
5/////////////////////////////////////////////////////////////////////////////////////////
6// This multi-threaded application illustrates "pipe-line" parallelism, and message
7// passing programming model, on top of the POSIX threads API.
8// It makes the parallel decompression of a MJPEG bitstream contained in a file.
9// The application is described as a TCG (Task and Communication Graph), and all
10// communications between threads uses MWMR channels,.
11// It uses the chained buffer DMA component to display the images on the graphic display.
12// It contains 5 types of threads, plus the "main" thread, that makes initialisation,
13// dispatch the byte stream to the various pipelines, and makes instrumentation.
14// and 7 types of MWMR communication channels:
15// - the main thread is only mapped in cluster[0,0], but all other threads
16//   (DEMUX, VLD, IQZZ, IDCT, LIBU) are replicated in all clusters.
17// - all MWMR channels are replicated in all clusters.
18// The number of cluster cannot be larger than 16*16.
19// The number of processors per cluster is not constrained.
20// The frame buffer size must fit the decompressed images size.
21// It uses one TTY terminal shared by all tasks.
22/////////////////////////////////////////////////////////////////////////////////////////
23
24#include <stdio.h>
25#include <mwmr_channel.h>
26#include <malloc.h>
27#include <stdlib.h>
28#include <string.h>
29#include "mjpeg.h"
30#include <mapping_info.h>     // for coprocessor types and modes
31
32
33// macro to use a shared TTY
34#define PRINTF(...)    do { lock_acquire( &tty_lock ); \
35                            giet_tty_printf(__VA_ARGS__);  \
36                            lock_release( &tty_lock ); } while(0);
37
38///////////////////////////////////////////////
39//       Global variables
40///////////////////////////////////////////////
41
42uint32_t         fd;    // file descriptor for the file containing the MJPEG stream
43
44// arrays of pointers on MWMR channels
45mwmr_channel_t*  main_2_demux[256];       // one per cluster
46mwmr_channel_t*  demux_2_vld_data[256];   // one per cluster
47mwmr_channel_t*  demux_2_vld_huff[256];   // one per cluster
48mwmr_channel_t*  demux_2_iqzz[256];       // one per cluster
49mwmr_channel_t*  vld_2_iqzz[256];         // one per cluster
50mwmr_channel_t*  iqzz_2_idct[256];        // one per cluster
51mwmr_channel_t*  idct_2_libu[256];        // one per cluster
52
53// thread trdid ( for pthread_create() and pthread_join() )
54pthread_t   trdid_demux[256];             // one per cluster
55pthread_t   trdid_vld[256];               // one per cluster
56pthread_t   trdid_iqzz[256];              // one per cluster
57pthread_t   trdid_idct[256];              // one per cluster
58pthread_t   trdid_libu[256];              // one per cluster
59
60user_lock_t      tty_lock;                // lock protecting shared TTY
61
62uint8_t*         cma_buf[256];            // CMA buffers (one per cluster)
63void*            cma_sts[256];            // CMA buffers status
64
65uint32_t         fbf_width;               // Frame Buffer width
66uint32_t         fbf_height;              // Frame Buffer height
67
68uint32_t         nblocks_h;               // number of blocks in a column
69uint32_t         nblocks_w;               // number of blocks in a row   
70
71uint32_t         date[MAX_IMAGES];        // date of libu completion
72
73////////////////////////////////////////////////
74// declare thread functions
75////////////////////////////////////////////////
76
77extern void demux( uint32_t index );
78extern void vld( uint32_t index );
79extern void iqzz( uint32_t index );
80extern void idct( uint32_t index );
81extern void libu( uint32_t index );
82
83/////////////////////////////////////////
84__attribute__ ((constructor)) void main()
85/////////////////////////////////////////
86{
87    // get platform parameters
88    uint32_t  x_size;
89    uint32_t  y_size;
90    uint32_t  nprocs;
91    giet_procs_number( &x_size , &y_size , &nprocs );
92
93    // shared TTY allocation
94    giet_tty_alloc( 1 );
95    lock_init( &tty_lock );
96
97    // check platform parameters
98    giet_pthread_assert( (nprocs <= 6),
99                         "[MJPEG ERROR] nprocs cannot be larger than 4");
100
101    giet_pthread_assert( (x_size <= 16),
102                         "[MJPEG ERROR] x_size cannot be larger than 16");
103
104    giet_pthread_assert( (y_size <= 16),
105                         "[MJPEG ERROR] y_size cannot be larger than 16");
106
107    giet_pthread_assert( (MAX_IMAGES >= (x_size*y_size)),
108                         "MJPEG ERROR] number of images smaller than x_size * y_size");
109
110    // check frame buffer size
111    giet_fbf_size( &fbf_width , &fbf_height );
112
113    giet_pthread_assert( ((fbf_width & 0x7) == 0) && ((fbf_height & 0x7) == 0) ,
114                         "[MJPEG ERROR] image width and height must be multiple of 8");
115
116    // request frame buffer and CMA channel allocation
117    giet_fbf_alloc();
118    giet_fbf_cma_alloc( x_size * y_size );
119
120    // file name and image size acquisition
121    char          file_pathname[256];
122    uint32_t      image_width;
123    uint32_t      image_height;
124    uint32_t      fd;                   // file descriptor
125
126    if ( INTERACTIVE_MODE )
127    {
128        PRINTF("\n[MJPEG] enter path for JPEG stream file (default is plan_48.mjpg)\n> ");
129        giet_tty_gets( file_pathname , 256 );
130
131        if ( file_pathname[0] == 0 )
132        {
133            strcpy( file_pathname , "/misc/plan_48.mjpg" );
134            image_width  = 48;
135            image_height = 48;
136        }
137        else
138        {
139            PRINTF("\n[MJPEG] enter image width\n> ");
140            giet_tty_getw( &image_width );
141            PRINTF("\n[MJPEG] enter image height\n> "); 
142            giet_tty_getw( &image_height );
143            PRINTF("\n");
144        }
145    }
146    else
147    {
148        strcpy( file_pathname , "/misc/plan_48.mjpg" );
149        image_width  = 48;
150        image_height = 48;
151    }
152   
153    giet_pthread_assert( (image_width == fbf_width) && (image_height == fbf_height) ,
154                         "[MJPEG ERROR] image size doesn't fit frame buffer size");
155 
156    if ( USE_DCT_COPROC )
157    {
158        PRINTF("\n\n[MJPEG] stream %s / %d clusters / %d cores / DCT COPROC\n\n",
159               file_pathname , x_size*y_size , nprocs );
160    }
161    else
162    { 
163        PRINTF("\n\n[MJPEG] stream %s / %d clusters / %d cores / NO DCT COPROC\n\n",
164               file_pathname , x_size*y_size , nprocs );
165    }
166
167    // compute nblocks_h & nblocks_w
168    nblocks_w = fbf_width / 8;
169    nblocks_h = fbf_height / 8;
170
171    // open file containing the MJPEG bit stream
172    fd = giet_fat_open( file_pathname , 0 );
173
174    giet_pthread_assert( (fd >= 0),
175                         "[MJPEG ERROR] cannot open MJPEG stream file");
176
177    // index for loops
178    uint32_t x;
179    uint32_t y;
180    uint32_t n;
181
182    uint32_t*  buffer; 
183
184    // initialise distributed heap,
185    // allocate MWMR channels
186    // allocate buffers for CMA
187    for ( x = 0 ; x < x_size ; x++ ) 
188    {
189        for ( y = 0 ; y < y_size ; y++ ) 
190        {
191            uint32_t index = x*y_size + y;
192
193            // initialise heap[x][y]
194            heap_init( x , y );
195
196            // allocate MWMR channels in cluster[x][y]
197            main_2_demux[index]     = remote_malloc( sizeof( mwmr_channel_t ) , x , y );
198            buffer                  = remote_malloc( 4 * MAIN_2_DEMUX_DEPTH , x , y );
199            mwmr_init( main_2_demux[index] , buffer , 1 , MAIN_2_DEMUX_DEPTH );
200
201            demux_2_vld_data[index] = remote_malloc( sizeof( mwmr_channel_t ) , x , y );
202            buffer                  = remote_malloc( 4 * DEMUX_2_VLD_DATA_DEPTH , x , y );
203            mwmr_init( demux_2_vld_data[index] , buffer , 1 , DEMUX_2_VLD_DATA_DEPTH );
204
205            demux_2_vld_huff[index] = remote_malloc( sizeof( mwmr_channel_t ) , x , y );
206            buffer                  = remote_malloc( 4 * DEMUX_2_VLD_HUFF_DEPTH , x , y );
207            mwmr_init( demux_2_vld_huff[index] , buffer , 1 , DEMUX_2_VLD_HUFF_DEPTH );
208
209            demux_2_iqzz[index]     = remote_malloc( sizeof( mwmr_channel_t ) , x , y );
210            buffer                  = remote_malloc( 4 * DEMUX_2_IQZZ_DEPTH , x , y );
211            mwmr_init( demux_2_iqzz[index] , buffer , 1 , DEMUX_2_IQZZ_DEPTH );
212
213            vld_2_iqzz[index]       = remote_malloc( sizeof( mwmr_channel_t ) , x , y );
214            buffer                  = remote_malloc( 4 * VLD_2_IQZZ_DEPTH , x , y );
215            mwmr_init( vld_2_iqzz[index] , buffer , 1 , VLD_2_IQZZ_DEPTH );
216
217            iqzz_2_idct[index]      = remote_malloc( sizeof( mwmr_channel_t ) , x , y );
218            buffer                  = remote_malloc( 4 * IQZZ_2_IDCT_DEPTH , x , y );
219            mwmr_init( iqzz_2_idct[index] , buffer , 1 , IQZZ_2_IDCT_DEPTH );
220
221            idct_2_libu[index]      = remote_malloc( sizeof( mwmr_channel_t ) , x , y );
222            buffer                  = remote_malloc( 4 * IDCT_2_LIBU_DEPTH , x , y );
223            mwmr_init( idct_2_libu[index] , buffer , 1 , IDCT_2_LIBU_DEPTH );
224
225            // allocate and register CMA buffers in cluster[x][y]
226            cma_buf[index] = remote_malloc( fbf_width * fbf_height , x , y );
227            cma_sts[index] = remote_malloc( 64 , x , y );
228            giet_fbf_cma_init_buf( index , cma_buf[index] , cma_sts[index] );
229        }
230    }
231
232    // start CMA channel
233    giet_fbf_cma_start();
234
235    mwmr_channel_t* pc;
236
237    for ( n = 0 ; n < x_size*y_size ; n++ )
238    {
239        pc = main_2_demux[n];
240        PRINTF(" - main_2_demux[%d]  = %x / &lock = %x / &buf = %x / size = %d\n",
241               n, pc, (uint32_t)&pc->lock, (uint32_t)pc->data, pc->depth<<2 );
242
243        pc = demux_2_vld_data[n];
244        PRINTF(" - demux_2_vld[%d] = %x / &lock = %x / &buf = %x / size = %d\n",
245               n, pc, (uint32_t)&pc->lock, (uint32_t)pc->data, pc->depth<<2 );
246
247        pc = vld_2_iqzz[n];
248        PRINTF(" - vld_2_iqzz[%d]  = %x / &lock = %x / &buf = %x / size = %d\n",
249               n, pc, (uint32_t)&pc->lock, (uint32_t)pc->data, pc->depth<<2 );
250
251        pc = iqzz_2_idct[n];
252        PRINTF(" - iqzz_2_idct[%d] = %x / &lock = %x / &buf = %x / size = %d\n",
253               n, pc, (uint32_t)&pc->lock, (uint32_t)pc->data, pc->depth<<2 );
254
255        pc = idct_2_libu[n];
256        PRINTF(" - idct_2_libu[%d] = %x / &lock = %x / &buf = %x / size = %d\n",
257               n, pc, (uint32_t)&pc->lock, (uint32_t)pc->data, pc->depth<<2 );
258    }
259
260    // launch all threads : precise mapping is defined in the mjpeg.py file
261    uint32_t index;
262
263    for ( x = 0 ; x < x_size ; x++ )
264    {
265        for ( y = 0 ; y < y_size ; y++ )
266        {
267            index = x * y_size + y;
268
269            // DEMUX 
270            if ( giet_pthread_create( &trdid_demux[index], NULL, &demux , (void*)index ) )
271            giet_pthread_exit( "error launching thread demux\n");
272
273            // VLD
274            if ( giet_pthread_create( &trdid_vld[index], NULL, &vld , (void*)index ) )
275            giet_pthread_exit( "error launching thread vld\n");
276
277            // IQZZ
278            if ( giet_pthread_create( &trdid_iqzz[index], NULL, &iqzz , (void*)index ) )
279            giet_pthread_exit( "error launching thread iqzz");
280
281            // IDCT
282            if ( USE_DCT_COPROC )  // allocate, initialise, and start hardware coprocessor
283            {
284                giet_coproc_channel_t in_channel;
285                giet_coproc_channel_t out_channel;
286                uint32_t  cluster_xy  = (x<<4) + y;
287                uint32_t  coproc_type = 2;
288                uint32_t  info;
289
290                // allocate DCT coprocessor
291                giet_coproc_alloc( cluster_xy , coproc_type , &info );
292
293                // initialize channels
294                in_channel.channel_mode = MODE_MWMR;
295                in_channel.buffer_size  = (iqzz_2_idct[index]->depth)<<2;
296                in_channel.buffer_vaddr = (uint32_t)(iqzz_2_idct[index]->data);
297                in_channel.status_vaddr = (uint32_t)(&iqzz_2_idct[index]->sts);
298                in_channel.lock_vaddr   = (uint32_t)(&iqzz_2_idct[index]->lock);
299   
300                giet_coproc_channel_init( cluster_xy , coproc_type , 0 , &in_channel );
301
302                out_channel.channel_mode = MODE_MWMR;
303                out_channel.buffer_size  = (idct_2_libu[index]->depth)<<2;
304                out_channel.buffer_vaddr = (uint32_t)(idct_2_libu[index]->data);
305                out_channel.status_vaddr = (uint32_t)(&idct_2_libu[index]->sts);
306                out_channel.lock_vaddr   = (uint32_t)(&idct_2_libu[index]->lock);
307
308                giet_coproc_channel_init( cluster_xy , coproc_type , 1 , &out_channel );
309
310                // start coprocessor
311                giet_coproc_run( cluster_xy , coproc_type );
312            }
313            else                   // launches a software thread
314            {
315                if ( giet_pthread_create( &trdid_idct[index], NULL, &idct , (void*)index ) )
316                giet_pthread_exit( "error launching thread idct\n");
317            }
318
319            // LIBU
320            if ( giet_pthread_create( &trdid_libu[index], NULL, &libu , (void*)index ) )
321            giet_pthread_exit( "error launching thread libu\n");
322        }
323    }
324
325    /////////////////////////////////////////////////////////////////////////////////////
326    // dispatch the byte stream to the demux threads, one compressed image per cluster.
327    // It transfer the stream from the file identified by the fd argument to a 1024
328    // bytes local buffer. It analyses the stream to detect the End_of_Image markers.
329    // All the bytes corresponding to a single image from the first byte, to the EOI
330    // marker included, are written in the main_2_demux[index] channel, in increasing
331    // order of the cluster index.
332    /////////////////////////////////////////////////////////////////////////////////////
333
334    // allocate input buffer : 1024 bytes
335    uint8_t        bufin[1024];
336
337    // allocate output bufio to access output MWMR channels : 64 bytes == 16 words
338    mwmr_bufio_t  bufio;
339    uint8_t       bufout[64]; 
340    mwmr_bufio_init( &bufio , bufout , 64 , 0 , main_2_demux[0] );
341
342    uint32_t  image;           // image index
343    uint32_t  cluster;         // cluster index / modulo x_size*y_size
344    uint32_t  ptr;             // byte pointer in input buffer
345    uint32_t  eoi_found;       // boolean : End-of-Image found
346    uint32_t  ff_found;        // boolean : 0xFF value found
347    uint32_t  bytes_count;     // mumber of bytes in compressed image
348       
349    // initialise image and cluster index, and bufin pointer
350    image   = 0;
351    cluster = 0;
352    ptr     = 0;
353
354    while( image < MAX_IMAGES )  // one compressed image per iteration
355    {
356        // initialise image specific variables
357        eoi_found   = 0;
358        ff_found    = 0;
359        bytes_count = 0; 
360       
361        // re-initialise the destination buffer for each image
362        bufio.mwmr = main_2_demux[cluster];
363
364        // scan bit stream until EOI found
365        // transfer one byte per iteration from input buffer to output bufio
366        while ( eoi_found == 0 )
367        {
368            // - tranfer 1024 bytes from file to input buffer when input buffer empty.
369            // - return to first byte in input file when EOF found,
370            //   to emulate an infinite stream of images.
371            if ( ptr == 0 )
372            {
373                uint32_t r = giet_fat_read( fd , bufin , 1024 );
374                if ( r < 1024 ) 
375                {
376                    giet_fat_lseek( fd , 0 , SEEK_SET );
377                    giet_fat_read( fd , bufin + r , 1024 - r );
378                }
379            }
380
381            // transfer one byte from input buffer to output bufio
382            mwmr_bufio_write_byte( &bufio , bufin[ptr] );
383
384            // analyse this byte to find EOI marker OxFFD8
385            // flush the output buffer when EOI found
386            if ( ff_found )  // possible End of Image
387            { 
388                ff_found = 0;
389                if ( bufin[ptr] == 0xD9 )   // End of Image found
390                {
391                    // exit current image
392                    eoi_found = 1;
393
394                    // flush output bufio
395                    mwmr_bufio_flush( &bufio );
396                }
397            }
398            else           // test if first byte of a marker
399            {
400                if ( bufin[ptr] == 0xFF )  ff_found = 1;
401            }       
402
403            // increment input buffer pointer modulo 1024
404            ptr++;
405            if ( ptr == 1024 ) ptr = 0;
406               
407            // increment bytes_count for current image
408            bytes_count++;
409
410        } // end while (eoi)
411 
412#if DEBUG_MAIN
413PRINTF("\nMAIN send image %d to cluster %d at cycle %d : %d bytes\n",
414       image , cluster , giet_proctime() , bytes_count );
415#endif
416        // increment image index
417        image++;
418
419        // increment cluster index modulo (x_size*y_size)   
420        cluster++; 
421        if (cluster == x_size * y_size) cluster = 0;   
422
423    } // end while on images
424
425    /////////////////////////////////////////////////////////////////////////////////////
426    // wait all threads completion
427    /////////////////////////////////////////////////////////////////////////////////////
428
429    for ( x = 0 ; x < x_size ; x++ )
430    {
431        for ( y = 0 ; y < y_size ; y++ )
432        {
433            index = x * y_size + y;
434
435            if ( giet_pthread_join( trdid_demux[index] , NULL ) )
436            PRINTF("\n[MJPEG ERROR] calling giet_pthread_join() for demux[%d]\n", index );
437
438            if ( giet_pthread_join( trdid_vld[index] , NULL ) )
439            PRINTF("\n[MJPEG ERROR] calling giet_pthread_join() for vld[%d]\n", index );
440
441            if ( giet_pthread_join( trdid_iqzz[index] , NULL ) )
442            PRINTF("\n[MJPEG ERROR] calling giet_pthread_join() for iqzz[%d]\n", index );
443
444            if ( USE_DCT_COPROC == 0 )
445            {
446                if ( giet_pthread_join( trdid_idct[index] , NULL ) )
447                PRINTF("\n[MJPEG ERROR] calling giet_pthread_join() for idct[%d]\n", index );
448            }
449
450            if ( giet_pthread_join( trdid_libu[index] , NULL ) )
451            PRINTF("\n[MJPEG ERROR] calling giet_pthread_join() for libu[%d]\n", index );
452
453            if ( USE_DCT_COPROC )
454            {
455                uint32_t  cluster_xy  = (x<<4) + y;
456                uint32_t  coproc_type = 2;
457                giet_coproc_release( cluster_xy , coproc_type );
458            }
459        }
460    }
461
462    /////////////////////////////////////////////////////////////////////////////////////
463    // makes instrumentation
464    /////////////////////////////////////////////////////////////////////////////////////
465
466    // display on TTY
467    PRINTF("\n[MJPEG] Instumentation Results\n" );
468    for ( image = 0 ; image < MAX_IMAGES ; image++ )
469    PRINTF(" - Image %d : completed at cycle %d\n", image , date[image]);
470
471    // save on disk
472    unsigned int fdout = giet_fat_open( "/home/mjpeg_instrumentation" , O_CREAT);
473    if ( fdout < 0 ) 
474    PRINTF("\n[MJPEG ERROR] cannot open file /home/mjpeg_instrumentation\n");
475
476    int ret = giet_fat_lseek( fdout, 0 , SEEK_END );
477    if( ret < 0 )
478    PRINTF("\n[MJPEG ERROR] cannot seek file /home/mjpeg_instrumentation\n");
479
480    if( USE_DCT_COPROC )
481    {
482        giet_fat_fprintf( fdout, "\n*** stream %s / %d clusters / %d cores / DCT COPROC\n",
483                          file_pathname , x_size*y_size , nprocs );
484    }
485    else
486    {
487        giet_fat_fprintf( fdout, "stream %s / %d clusters / %d cores / NO DCT COPROC\n\n",
488                          file_pathname , x_size*y_size , nprocs );
489    }
490    for ( image = 0 ; image < MAX_IMAGES ; image++ )
491    {
492        giet_fat_fprintf( fdout, " - Image %d : completed at cycle %d\n", 
493                          image , date[image]);
494    } 
495
496    // completed
497    giet_pthread_exit( "main completed" );
498   
499} // end main()
500
Note: See TracBrowser for help on using the repository browser.