1 /* Test viterbi decoder speeds */
2 #include "config.h"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <time.h>
7 #include <math.h>
8 #include <memory.h>
9 #include <sys/time.h>
10 #include <sys/resource.h>
11 #ifdef HAVE_GETOPT_H
12 #include <getopt.h>
13 #endif
14 #include "fec.h"
15 
16 #if HAVE_GETOPT_LONG
17 struct option Options[] = {
18   {"frame-length",1,NULL,'l'},
19   {"frame-count",1,NULL,'n'},
20   {"ebn0",1,NULL,'e'},
21   {"gain",1,NULL,'g'},
22   {"verbose",0,NULL,'v'},
23   {"force-altivec",0,NULL,'a'},
24   {"force-port",0,NULL,'p'},
25   {"force-mmx",0,NULL,'m'},
26   {"force-sse",0,NULL,'s'},
27   {"force-sse2",0,NULL,'t'},
28   {NULL},
29 };
30 #endif
31 
32 #define RATE (1./6.)
33 #define MAXBYTES 10000
34 #define OFFSET (127.5)
35 #define CLIP 255
36 
37 double Gain = 24.0;
38 int Verbose = 0;
39 
main(int argc,char * argv[])40 int main(int argc,char *argv[]){
41   int i,d,tr;
42   int sr=0,trials = 10,errcnt,framebits=2048;
43   int tot_errs=0;
44   unsigned char bits[MAXBYTES];
45   unsigned char data[MAXBYTES];
46   unsigned char xordata[MAXBYTES];
47   unsigned char symbols[8*6*(MAXBYTES+14)];
48   void *vp;
49   extern char *optarg;
50   struct rusage start,finish;
51   double extime;
52   double gain,esn0,ebn0;
53   time_t t;
54   int badframes=0;
55 
56   time(&t);
57   srandom(t);
58   ebn0 = -100;
59 #if HAVE_GETOPT_LONG
60   while((d = getopt_long(argc,argv,"l:n:te:g:vapmst",Options,NULL)) != EOF){
61 #else
62   while((d = getopt(argc,argv,"l:n:te:g:vapmst")) != EOF){
63 #endif
64     switch(d){
65     case 'a':
66       Cpu_mode = ALTIVEC;
67       break;
68     case 'p':
69       Cpu_mode = PORT;
70       break;
71     case 'm':
72       Cpu_mode = MMX;
73       break;
74     case 's':
75       Cpu_mode = SSE;
76       break;
77     case 't':
78       Cpu_mode = SSE2;
79       break;
80     case 'l':
81       framebits = atoi(optarg);
82       break;
83     case 'n':
84       trials = atoi(optarg);
85       break;
86     case 'e':
87       ebn0 = atof(optarg);
88       break;
89     case 'g':
90       Gain = atof(optarg);
91       break;
92     case 'v':
93       Verbose++;
94       break;
95     }
96   }
97   if(framebits > 8*MAXBYTES){
98     fprintf(stderr,"Frame limited to %d bits\n",MAXBYTES*8);
99     framebits = MAXBYTES*8;
100   }
101   if((vp = create_viterbi615(framebits)) == NULL){
102     printf("create_viterbi615 failed\n");
103     exit(1);
104   }
105   if(ebn0 != -100){
106     esn0 = ebn0 + 10*log10((double)RATE); /* Es/No in dB */
107     /* Compute noise voltage. The 0.5 factor accounts for BPSK seeing
108      * only half the noise power, and the sqrt() converts power to
109      * voltage.
110      */
111     gain = 1./sqrt(0.5/pow(10.,esn0/10.));
112 
113     printf("nframes = %d framesize = %d ebn0 = %.2f dB gain = %g\n",trials,framebits,ebn0,Gain);
114 
115     for(tr=0;tr<trials;tr++){
116       /* Encode a frame of random data */
117       for(i=0;i<framebits+14;i++){
118 	int bit = (i < framebits) ? (random() & 1) : 0;
119 
120 	sr = (sr << 1) | bit;
121 	bits[i/8] = sr & 0xff;
122 	symbols[6*i+0] = addnoise(parity(sr & V615POLYA),gain,Gain,OFFSET,CLIP);
123 	symbols[6*i+1] = addnoise(parity(sr & V615POLYB),gain,Gain,OFFSET,CLIP);
124 	symbols[6*i+2] = addnoise(parity(sr & V615POLYC),gain,Gain,OFFSET,CLIP);
125 	symbols[6*i+3] = addnoise(parity(sr & V615POLYD),gain,Gain,OFFSET,CLIP);
126 	symbols[6*i+4] = addnoise(parity(sr & V615POLYE),gain,Gain,OFFSET,CLIP);
127 	symbols[6*i+5] = addnoise(parity(sr & V615POLYF),gain,Gain,OFFSET,CLIP);
128       }
129       /* Decode it and make sure we get the right answer */
130       /* Initialize Viterbi decoder */
131       init_viterbi615(vp,0);
132 
133       /* Decode block */
134       update_viterbi615_blk(vp,symbols,framebits+14);
135 
136       /* Do Viterbi chainback */
137       chainback_viterbi615(vp,data,framebits,0);
138       errcnt = 0;
139       for(i=0;i<framebits/8;i++){
140 	int e = Bitcnt[xordata[i] = data[i] ^ bits[i]];
141 	errcnt += e;
142 	tot_errs += e;
143       }
144       if(errcnt != 0)
145 	badframes++;
146       if(Verbose > 1 && errcnt != 0){
147 	printf("frame %d, %d errors: ",tr,errcnt);
148 	for(i=0;i<framebits/8;i++){
149 	  printf("%02x",xordata[i]);
150 	}
151 	printf("\n");
152       }
153       if(Verbose)
154 	printf("BER %d/%d (%10.3g) FER %d/%d (%10.3g)\r",
155 	       tot_errs,framebits*(tr+1),tot_errs/((double)framebits*(tr+1)),
156 	       badframes,(tr+1),(double)badframes/(tr+1));
157       fflush(stdout);
158 
159     }
160 
161     if(Verbose > 1)
162       printf("nframes = %d framesize = %d ebn0 = %.2f dB gain = %g\n",trials,framebits,ebn0,Gain);
163     else if(Verbose == 0)
164 	printf("BER %d/%d (%.3g) FER %d/%d (%.3g)\n",
165 	       tot_errs,framebits*(tr+1),tot_errs/((double)framebits*(tr+1)),
166 	       badframes,(tr+1),(double)badframes/(tr+1));
167     else
168       printf("\n");
169   } else {
170     /* Do time trials */
171     memset(symbols,127,sizeof(symbols));
172     printf("Starting time trials\n");
173     getrusage(RUSAGE_SELF,&start);
174     for(tr=0;tr < trials;tr++){
175       /* Initialize Viterbi decoder */
176       init_viterbi615(vp,0);
177 
178       /* Decode block */
179       update_viterbi615_blk(vp,symbols,framebits+14);
180 
181       /* Do Viterbi chainback */
182       chainback_viterbi615(vp,data,framebits,0);
183     }
184     getrusage(RUSAGE_SELF,&finish);
185     extime = finish.ru_utime.tv_sec - start.ru_utime.tv_sec + 1e-6*(finish.ru_utime.tv_usec - start.ru_utime.tv_usec);
186     printf("Execution time for %d %d-bit frames: %.2f sec\n",trials,
187 	   framebits,extime);
188     printf("decoder speed: %g bits/s\n",trials*framebits/extime);
189   }
190   exit(0);
191 }
192