Additions:
%%(c;decode.h)
#ifndef __DECODE__
#define __DECODE__
void decode(const char* key, int m, char* str);
%%(c;main.c)
#define STR "Tjit#lkbsdr{ jv hrfh uogwwcrf> {ov#ccn!uefitwrkbvwe\"iu#apd0rr\"mp" \
"gihy!lt\"uoget uke\"tfumu pi vhf#GPU!Oeusfu Ieohrcl!SudljfLkcfqsg " \
"bv rucoiuhfg dy!whg Gueg Trfvwbue\"Fpxnfaulop;!hivhfu xesviqn!5.3 " \
"pi vhf#Lkcfqsg,!rr\"(bw {ovu qpulop)!dn{ mdtgr!yetsjrn0"
// ---------------------------------------------------------------------
// decode_ok
// ---------------------------------------------------------------------
void decode_ok(const char* key, int m, char* str) {
for (i=0; i
// ---------------------------------------------------------------------
// main
// ---------------------------------------------------------------------
int main(int argc, char* argv[]) {
const char k1[] = { 0, 2, 0, 1, 3 };
char s1[] = STR;
char o1[] = STR;
decode(k1, 5, s1);
decode_ok(k1, 5, o1);
printf("------- Calcolato: \n%s\n", s1);
printf("------- Corretto: \n%s\n", o1);
printf("------- Esito: %s\n", strcmp(s1,o1)==0 ? "OK":"ERRORE");
%%(text;Makefile)
CC=gcc
CFLAGS=-Wall -O1 -g
LFLAGS=-msse2
decode: decode.c decode.h main.c
$(CC) $(CFLAGS) decode.c main.c -o decode $(LFLAGS)
.phony: clean
clean:
rm -f decode
Additions:
==Esempio 4==
Soluzione con vettorizzazione SSE dell'esercizio 2 compito A del 14 gennaio 2016:
%%(c;decode.c)
#include "decode.h"
#include
void decode(const char* key, int m, char* str) {
int i, n = strlen(str);
char keybuf[16] = { 0 };
memcpy(keybuf, key, m);
__m128i k = _mm_loadu_si128((__m128i*)keybuf);
for (i=0; i+16 < n; i += m) {
__m128i s = _mm_loadu_si128((__m128i*)(str+i));
s = _mm_sub_epi8(s,k);
_mm_storeu_si128((__m128i*)(str+i), s);
for (; i
Additions:
==Esempio 3==
Additions:
Compilazione versioni con piccola memory footprint (array di 1000 elementi):
> gcc vecsum.c -D VERSION=1 -o vecsum-sse -O1
> gcc vecsum.c -D VERSION=0 -o vecsum -O1
> time ./vecsum
0 0 0 0 0
real 0m0.047s
user 0m0.046s
sys 0m0.000s
> time ./vecsum-sse
0 0 0 0 0
real 0m0.016s
user 0m0.013s
sys 0m0.000s
Compilazione versioni con alta memory footprint (array di 100000000 elementi):
> gcc vecsum.c -D VERSION=1 -D N=100000000 -D M=1 -o vecsum-large-sse -O1
> gcc vecsum.c -D VERSION=0 -D N=100000000 -D M=1 -o vecsum-large -O1
> time ./vecsum-large
0 0 0 0 0
real 0m0.095s
user 0m0.074s
sys 0m0.021s
> time ./vecsum-large-sse
0 0 0 0 0
real 0m0.073s
user 0m0.031s
sys 0m0.040s
Si noti come in questo secondo caso lo speedup sia nettamente inferiore. La motivazione è che gli array sono grandi e il collo di bottiglia è il sistema di memoria e non il calcolo delle operazioni aritmetiche.
Deletions:
Compilazione versioni:
> gcc
Additions:
sum_sse(A+i,B+i,C+i); // versione SSE
Deletions:
sum_sse(A+i,B+i,C+i); // versione SSE
Additions:
Somma di array di ##int## di dimensione arbitraria usando vettorizzazione SSE:
%%(c;vecsum.c)
void sum_sse(int A[4], int B[4], int C[4]);
void vecsum(int* A, int* B, int* C, int n) {
int i;
#if VERSION == 1
sum_sse(A+i,B+i,C+i); // versione SSE
#else
C[i]=A[i]+B[i]; // versione sequenziale, con loop unrolling
C[i+1]=A[i+1]+B[i+1];
C[i+2]=A[i+2]+B[i+2];
C[i+3]=A[i+3]+B[i+3];
#endif
for (;i
void sum_sse(int A[4], int B[4], int C[4]) {
void init(int* v, int n) {
int i;
for (i=0; i
#ifndef N
#define N 1000
#endif
#ifndef M
#define M 100000
#endif
// provare anche con M=1 e N=100000000:
// array A, B, C da 100 milioni di int => 1.2 GB per 3 array di int
// (collo di bottiglia memoria vanifica parallelismo)
int j;
int* A = malloc(N*sizeof(int));
int* B = malloc(N*sizeof(int));
int* C = malloc(N*sizeof(int));
// ripete per rendere misurabili i tempi
for (j=0; j
printf("%d %d %d %d %d\n", C[0], C[1], C[2], C[3], C[4]);
Compilazione versioni:
> gcc
Additions:
===Giovedì 23 novembre 2017===
==Esempio 2==
Prodotto scalare di array di ##int## di dimensione arbitraria usando vettorizzazione SSE:
%%(c;scalprod.c)
void prod_sse(int A[4], int B[4], int C[4]);
int scalprod(int* A, int* B, int n) {
int i, s = 0, S[4] = { 0 }, P[4];
for (i=0; i+3
prod_sse(A+i,B+i,P);
somma_sse(P, S, S);
}
for (; i
__m128i a, b, c; // dich. variabili vettoriali
a = _mm_loadu_si128((const __m128i*)A); // copia primo vettore in a
b = _mm_loadu_si128((const __m128i*)B); // copia secondo vettore in b
c = _mm_add_epi32(a,b); // calcola la somma vett. di a e b
_mm_store_si128((__m128i*)C, c); // copia risultato c in C
void prod_sse(int A[4], int B[4], int C[4]) {
__m128i a, b, c; // dich. variabili vettoriali
a = _mm_loadu_si128((const __m128i*)A); // copia primo vettore in a
b = _mm_loadu_si128((const __m128i*)B); // copia secondo vettore in b
c = _mm_mullo_epi32(a,b); // calcola la somma vett. di a e b
_mm_store_si128((__m128i*)C, c); // copia risultato c in C
int B[] = { 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1 };
int s = scalprod(A, B, sizeof(A)/sizeof(int));
Additions:
==Esempio 1==
Somma degli elementi di un array di ##int## di dimensione arbitraria usando vettorizzazione SSE:
Additions:
__m128i a, b, c; // dich. variabili vettoriali
c = _mm_add_epi32(a,b); // calcola la somma vett. di a e b
_mm_store_si128((__m128i*)C, c); // copia risultato c in C
Deletions:
__m128i a, b, c; // dich. variabili vettoriali
c = _mm_add_epi32(a,b); // calcola la somma vett. di a e b
_mm_store_si128((__m128i*)C, c); // copia risultato c in C