UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
ldgm-session-cpu.cpp
Go to the documentation of this file.
1/*
2 * =====================================================================================
3 *
4 * Filename: ldgm-session-cpu.cpp
5 *
6 * Description: CPU implementation of LDGM coding
7 *
8 * Version: 1.0
9 * Created: 04/12/2012 01:21:07 PM
10 * Revision: none
11 * Compiler: gcc
12 *
13 * Author: Milan Kabat (), kabat@ics.muni.cz
14 * Organization:
15 *
16 * =====================================================================================
17 */
18
19#include <assert.h>
20#include <stdlib.h>
21#include <stdio.h>
22#if defined __SSE2__ || _M_IX86_FP == 2
23#include <emmintrin.h>
24#endif
25#include <string.h>
26#include <time.h>
27
28#include "ldgm-session-cpu.h"
29#include "timer-util.h"
30
31using namespace std;
32
33#ifdef _WIN32
34#define aligned_malloc _aligned_malloc
35#define aligned_free _aligned_free
36#else
37#include <errno.h>
38static inline void *aligned_malloc(size_t size, size_t alignment)
39{
40 void *ptr = NULL;
41 int ret;
42 ret = posix_memalign(&ptr, alignment, size);
43 if(ret) {
44 errno = ret;
45 }
46
47 if(ret == 0) {
48 return ptr;
49 } else {
50 return NULL;
51 }
52}
53#define aligned_free free
54#endif
55
56
57static char*
58xor_using_sse (char* source, char* dest, int packet_size)
59{
60 // int a = 0;
61 // int II = packet_size % 16;
62 // a=II*16;
63 // // uint64_t* p1 = (uint64_t*) (source);
64 // // uint64_t* p2 = (uint64_t*) (dest);
65
66 // __int128* p1 = (__int128*) (source);
67 // __int128* p2 = (__int128*) (dest);
68
69 // for(int i=0; i<II; i++){
70 // *p2 ^= *p1;
71 // p2++;
72 // p1++;
73 // }
74 // while(a<packet_size){
75 // *(dest + a) ^= *(source+a);
76 // a++;
77 // }
78 //First, do as many 128-bit XORs as possible
79 int iter_bytes_16 = 0;
80 int iter_bytes_4 = 0;
81 int iter_bytes_1 = 0;
82#if defined __SSE2__ || _M_IX86_FP == 2
83 iter_bytes_16 = (packet_size/16)*16;
84
85 if ( iter_bytes_16 > 0)
86 {
87
88 // printf ( "iter_bytes: %d\n", iter_bytes );
89 __m128i* wrd_ptr = (__m128i *)(void *) source;
90 __m128i* wrd_end = (__m128i *)(void *) (source + iter_bytes_16);
91 __m128i* dst_ptr = (__m128i *)(void *) dest;
92
93 // printf ( "wrd_ptr address: %p\n", wrd_ptr );
94 do
95 {
96 __m128i xmm1 = _mm_loadu_si128(wrd_ptr);
97 __m128i xmm2 = _mm_loadu_si128(dst_ptr);
98
99 xmm1 = _mm_xor_si128(xmm1, xmm2); // XOR 4 32-bit words
100 _mm_storeu_si128(dst_ptr, xmm1);
101 ++wrd_ptr;
102 ++dst_ptr;
103
104 } while (wrd_ptr < wrd_end);
105 }
106#endif
107 //Check, whether further XORing is necessary
108 if ( iter_bytes_16 < packet_size )
109 {
110 char *mark_source = source + iter_bytes_16;
111 char *mark_dest = dest + iter_bytes_16;
112
113 iter_bytes_4 = ((packet_size - iter_bytes_16)/4)*4;
114
115 for ( int i = 0; i < (packet_size - iter_bytes_16)/4; i++)
116 {
117 int *s = ((int*)(void *) mark_source) + i;
118 int *d = ((int*)(void *) mark_dest) + i;
119 *d ^= *s;
120 }
121
122 mark_source += iter_bytes_4;
123 mark_dest += iter_bytes_4;
124
125 iter_bytes_1 = packet_size - iter_bytes_16 - iter_bytes_4;
126
127 for ( int i = 0; i < iter_bytes_1; i++)
128 {
129 *(mark_dest + i) ^= *(mark_source+i);
130 }
131 }
132
133// printf ( "XORed: %d bytes using SSE, %d bytes as ints and %d bytes byte-per-byte.\n",iter_bytes_16, iter_bytes_4, iter_bytes_1);
134
135 return dest;
136}
137
138void *
140{
141 void *out_buf = aligned_malloc(buf_size, 16);
142 if (!out_buf)
143 {
144 printf ( "Unable to allocate aligned memory\n" );
145
146 }
147 return out_buf;
148
149}
150
151void
152LDGM_session_cpu::encode ( char* data_ptr, char* parity_ptr )
153{
154// start encoding
155 // printf ( "packet_size: %d\n", this->packet_size );
156
157 char *parity_packet;
158
159 parity_packet = (char *) aligned_malloc(packet_size, 16);
160 if (!parity_packet)
161 {
162 printf ( "Error while using posix_memalign\n" );
163 return;
164 }
165 memset(parity_packet, 0, packet_size);
166
167 for ( int m = 0; m < param_m; ++m) {
168// printf ( "m: %d\n", m );
169
170// printf ( "max w: %d\n", max_row_weight );
171 //Find out which packets to XOR
172 for ( int k = 0; k < max_row_weight+2; ++k) {
173 int idx = pcm[m*(max_row_weight+2) + k];
174// printf ( "adept: %d\n", idx );
175 if (idx > -1 && idx < param_k) {
176// printf ( "xoring idx: %d\n", idx );
177 char *ptr = data_ptr + idx*packet_size;
178 parity_packet = xor_using_sse(ptr, parity_packet, packet_size);
179 }
180 }
181
182 //Add the new parity packet to overall parity
183 memcpy ( parity_ptr + m*packet_size, parity_packet, packet_size );
184 }
185
186 aligned_free(parity_packet);
187
188 return ;
189} /* ----- end of method LDGM_session_cpu::encode ----- */
190
191void
193{
194 if ( buf != NULL )
195 aligned_free(buf);
196}
197void
198LDGM_session_cpu::encode_naive ( char* data_ptr, char* parity_ptr )
199{
200// start encoding
201
202 void *ppacket;
203 char *parity_packet;
204
205 for ( int m = 0; m < param_m; ++m) {
206
207 ppacket = aligned_malloc(packet_size, 16);
208 if (!ppacket)
209 {
210 printf ( "Error while using posix_memalign\n" );
211 return;
212 }
213 memset(ppacket, 0, packet_size);
214 parity_packet = (char*)ppacket;
215
216 //Find out which packets to XOR
217 for ( int k = 0; k < max_row_weight+2; ++k) {
218 int idx = pcm[m*(max_row_weight+2) + k];
219 if (idx > -1 && idx < param_k) {
220 char *ptr = data_ptr + idx*packet_size;
221// parity_packet = xor_using_sse(ptr, parity_packet, packet_size);
222 for ( int i = 0; i < packet_size; i++)
223 parity_packet[i] ^= *(ptr+i);
224 }
225 }
226
227 //Apply inverted staircase matrix
228 if( m > 0) {
229 char *prev_parity = parity_ptr + (m-1)*packet_size;
230// parity_packet = xor_using_sse(prev_parity, parity_packet, packet_size);
231 for ( int i = 0; i < packet_size; i++)
232 parity_packet[i] ^= *(prev_parity+i);
233 }
234
235
236 //Add the new parity packet to overall parity
237 memcpy ( parity_ptr + m*packet_size, parity_packet, packet_size );
238 aligned_free(ppacket);
239
240 }
241 return ;
242} /* ----- end of method LDGM_session_cpu::encode ----- */
243
245
246char*
247LDGM_session_cpu::decode_frame ( char* received, int buf_size, int* frame_size,
248 std::map<int, int> valid_data )
249{
250// printf ( "buf_size: %d\n", buf_size );
251
252 Timer_util interval;
253 interval.start();
254
255
256 Tanner_graph graph;
257
258 int p_size = buf_size/(param_m+param_k);
259 this->packet_size = p_size;
260// printf ( "p_size %d\n", p_size );
261 graph.set_data_size(p_size);
262
263 //Timer_util timer;
264
265 int i;
266 int index = 0;
267
268
269// while ( i < (param_k + param_m)*p_size)
270// {
271// printf ( "%2d|", (unsigned char)received[i++] );
272// }
273
274 //one variable node per each data packet in block K
275 for ( i = 0; i < param_k; ++i )
276 graph.add_node(Node::variable_node, index++, received + i*p_size);
277
278 //one variable node per each parity packet in block M
279 for ( i = 0; i < param_m; ++i)
280 graph.add_node(Node::variable_node, index++, received + (i + param_k)*p_size);
281
282 //one constraint node per each row of generation matrix
283 for ( i = 0; i < param_m; ++i)
284 graph.add_node(Node::constraint_node, index++, NULL);
285
286 create_edges(&graph);
287
288// printf("Graph created in: %.3f s\n", t);
289
290 /* printf ( "graf\n" );
291 * for(map<int, Node>::iterator it = graph.nodes.begin(); it != graph.nodes.end(); ++it) {
292 * Node n = it->second;
293 * for ( int i = 0; i < p_size; ++i)
294 * printf("%2d|", *(unsigned char *)(n.getDataPtr() + i));
295 * printf ( "---\n" );
296 * }
297 */
298
299 /* for(map<int, Node>::iterator it = graph.nodes.begin(); it != graph.nodes.end(); ++it) {
300 * Node n = it->second;
301 * printf ( "neigbours of %d (count %lu): ", it->first, (it->second).neighbours.size() );
302 * for(vector<int>::iterator itr = n.neighbours.begin(); itr != n.neighbours.end(); ++itr)
303 * printf ( "%d ", *itr );
304 * printf ( "\n" );
305 * }
306 */
307
308 //We need to merge intervals in the valid data vector
309 map <int, int> merged_intervals;
310 map<int,int>::iterator map_it;
311
312 if ( valid_data.size() != 0 )
313 {
314 for ( map_it = valid_data.begin(); map_it != valid_data.end(); )
315 {
316 int start = map_it->first;
317 int length = map_it->second;
318 while ( start + length == (++map_it)->first )
319 length += map_it->second;
320 merged_intervals.insert ( pair<int, int> (start, length) );
321 }
322 }
323 /* printf ( "Valid data: \n" );
324 * for ( map_it = valid_data.begin(); map_it != valid_data.end(); ++map_it)
325 * {
326 * printf ( "|%d-%d| ", map_it->first, map_it->second );
327 * }
328 * printf ( "\n" );
329 *
330 * printf ( "Merged intervals: \n" );
331 * for ( map_it = merged_intervals.begin(); map_it != merged_intervals.end(); ++map_it)
332 * {
333 * printf ( "|%d-%d| ", map_it->first, map_it->second );
334 * }
335 * printf ( "\n" );
336 *
337 */
338
339
340
341 map<int, Node>::iterator it;
342 if ( merged_intervals.size() != 0)
343 {
344 it = graph.nodes.find(0);
345 const auto variable_node_end_it = graph.nodes.find(param_k+param_m); // == 1st constraint node
346 assert(variable_node_end_it != graph.nodes.end());
347 while (it != variable_node_end_it) {
348 (*it).second.setDone(false);
349 int node_offset = (*it).second.getDataPtr() - received;
350// printf ( "offset: %d\n", node_offset );
351
352 map_it = merged_intervals.begin();
353 //Find the offset in valid data which is equal, or the first offset which is
354 //lower than node offset
355 bool found = false;
356 while ( (map_it->first <= node_offset) && map_it != merged_intervals.end() )
357 {
358 map_it++;
359 found = true;
360 }
361 if ( found )
362 map_it--;
363
364 //Next, find out if some interval covers this symbol
365 if ( found && (map_it->first + map_it->second) >=
366 (node_offset + p_size) )
367 {
368 (*it).second.setDone(true);
369// printf ( "setting node %d with offset %d and size %d as done\n", it->first,
370// node_offset, p_size);
371 }
372
373 ++it;
374 }
375 }
376
377 //int not_done = 0;
378 for ( it = graph.nodes.begin(); it != graph.nodes.find(param_k); it++)
379 {
380 if ( !it->second.isDone())
381 {
382 memset(it->second.getDataPtr(), 0, p_size);
383// printf ( "resetting node: %d\n", it->first );
384 //not_done++;
385 }
386 }
387// printf ( "not done: %d\n", not_done );
388 /* srand(time(NULL));
389 * for ( int j = 0; j < 100; j++)
390 * {
391 * it = graph.nodes.find(rand()%(param_k+param_m));
392 * (*it).second.setDone(false);
393 * }
394 */
395 int iter = 0;
396
397 while ( needs_decoding(&graph) && iter < 4) {
398// printf ( "iteratin\n" );
399 iterate(&graph);
400 iter++;
401 }
402
403// printf("decoding process: %.3f s\n", t);
404
405 //printf ( "iterations: %d\n", iter );
406
407 int undecoded = 0;
408 it = graph.nodes.find(0);
409 while ( it != graph.nodes.find(param_k) ) {
410 if (!(*it).second.isDone())
411 undecoded++;
412 ++it;
413 }
414// printf ( "Number of not recovered data packets: %d\n", undecoded );
415
416 // printf("rest: %.3f s\n", t);
417
418 if ( undecoded == 0 )
419 {
420 union int_bytes {
421 unsigned int number;
422 unsigned char bytes[4];
423 };
424 union int_bytes fs;
425 memcpy(&(fs.bytes), received, 4);
426 *frame_size = fs.number;
427 }
428 else
429 *frame_size = 0;
430
431
432 interval.end();
433 //printf("time: %e\n",elapsed/1000.0 );
434 this->elapsed_sum2 += interval.elapsed_time_ms();
435 this->no_frames2++;
436
437 if(this->no_frames==150){
438 //printf("TIME: %f ms\n",this->elapsed_sum/(double)this->no_frames );
439 }
440
441 return received + LDGM_session::HEADER_SIZE;
442} /* ----- end ofmethod LDGM_session_cpu::decode ----- */
443
444
445void
447{
448 map<int, Node>::iterator it_c;
449 vector<int> vec;
450
451 //static int recovered = 0;
452
453 //select the first constraint node
454 it_c = graph->nodes.find ( param_k + param_m );
455
456 //iterate through constraint nodes
457 while ( it_c != graph->nodes.end() ) {
458 //iterate the node's neighbours to find out how many of them are not decoded
459 for(vector<int>::iterator j = it_c->second.neighbours.begin();
460 j != it_c->second.neighbours.end(); ++j) {
461 const auto it_v = graph->nodes.find(*j);
462 if ( !it_v->second.isDone() )
463 vec.push_back(*j);
464 }
465// printf ( "node %d has %d undecoded neighbours\n", it_c->first, vec.size() );
466
467 //we can restore the missing packet
468 if ( vec.size() == 1)
469 {
470 int r_index = vec.front();
471
472// if ( r_index == 0 )
473// {
474// printf ( "repairing first block\n" );
475// }
476 auto &node = graph->nodes.at(r_index);
477 memset(node.getDataPtr(), 0, packet_size);
478 char *r_data = node.getDataPtr();
479 //find other nodes connected to this constraint node and XOR their values
480 int count = 0;
481 for(vector<int>::iterator j = it_c->second.neighbours.begin();
482 j != it_c->second.neighbours.end(); ++j)
483 {
484 if ( *j != r_index )
485 {
486// printf ( "decode, packet_size: %d\n", packet_size );
487 char *g_data = (graph->nodes.find(*j))->second.getDataPtr();
488 //XOR
489 xor_using_sse(g_data, r_data, packet_size);
490 count++;
491 }
492 }
493 /* //validate recovered packet
494 * for ( int i = 0; i < param_k; ++i) {
495 * if(!memcmp(r_data, lost_ptr + i*packet_size, packet_size)) {
496 * printf ( "packet ok\n" );
497 * break;
498 * }
499 * }
500 */
501 if ( count > 0 )
502 node.setDone(true);
503 //recovered++;
504 /* printf ( "restored data: \n" );
505 * for ( int i = 0; i < packet_size; ++i)
506 * printf ( "%2d|", (unsigned char)(*(it_v->second.getDataPtr() + i)) );
507 * printf ( "---\n" );
508 */
509
510
511 }
512 vec.clear();
513
514 ++it_c;
515 }
516// printf ( "recovered: %d\n", recovered );
517
518 return;
519
520}
521
char * decode_frame(char *received_data, int buf_size, int *frame_size, std::map< int, int > valid_data)
void iterate(Tanner_graph *graph)
void free_out_buf(char *buf)
void * alloc_buf(int size)
void encode(char *, char *)
void encode_naive(char *, char *)
static const int HEADER_SIZE
unsigned short param_m
double elapsed_sum2
bool needs_decoding(Tanner_graph *tanner_graph)
unsigned short max_row_weight
unsigned short param_k
unsigned short packet_size
void create_edges(Tanner_graph *g)
@ variable_node
Definition tanner.h:40
@ constraint_node
Definition tanner.h:41
std::map< int, Node > nodes
Definition tanner.h:145
void set_data_size(int size)
Definition tanner.cpp:70
void add_node(Node::Node_type t, int index, char *data)
Definition tanner.cpp:74
This class implements timer utils.
Definition timer-util.h:26
void end()
Definition timer-util.h:36
double elapsed_time_ms() const
Definition timer-util.h:52
void start()
Definition timer-util.h:32
int count
Definition hd-rum.c:44
static void * aligned_malloc(size_t size, size_t alignment)
static char * xor_using_sse(char *source, char *dest, int packet_size)
#define aligned_free
void iterate(Tanner_graph *g)
struct _source source
codec_t first
Definition sdl2.c:423
static void start()
Definition sdp.c:202
Definition rtp.c:206