Skip to content

Instantly share code, notes, and snippets.

@yuezato
Created December 14, 2020 10:56
Show Gist options
  • Save yuezato/92170f2868aa93cf25a0dc2a584f99ca to your computer and use it in GitHub Desktop.
Save yuezato/92170f2868aa93cf25a0dc2a584f99ca to your computer and use it in GitHub Desktop.
$ gcc -O3 -Wall -mavx2 xor_program.c -DPROGRAM1
$ ./a.out
elapsed = 55.105000
$ gcc -O3 -Wall -mavx2 xor_program.c -DPROGRAM2
$ ./a.out
elapsed = 31.889001
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <immintrin.h>
#include <time.h>
#include <string.h>
double milliDiff(struct timespec *start, struct timespec *end)
{
return
(( end->tv_sec * 1000) + ( end->tv_nsec * 0.000001)) -
((start->tv_sec * 1000) + (start->tv_nsec * 0.000001));
}
#define PAGESIZE 4096
// A <- B ^ C;
__attribute__((noinline))
void xor(uint8_t *A, uint8_t *B, uint8_t *C) {
for (int i = 0; i < PAGESIZE; i += 128) {
__m256i* p = (__m256i*)(A+i);
__m256i* q = (__m256i*)(B+i);
__m256i* r = (__m256i*)(C+i);
__m256i v1 = _mm256_load_si256(q+0);
__m256i v2 = _mm256_load_si256(q+1);
__m256i v3 = _mm256_load_si256(q+2);
__m256i v4 = _mm256_load_si256(q+3);
__m256i w1 = _mm256_load_si256(r+0);
__m256i w2 = _mm256_load_si256(r+1);
__m256i w3 = _mm256_load_si256(r+2);
__m256i w4 = _mm256_load_si256(r+3);
__m256i x1 = _mm256_xor_si256(v1, w1);
__m256i x2 = _mm256_xor_si256(v2, w2);
__m256i x3 = _mm256_xor_si256(v3, w3);
__m256i x4 = _mm256_xor_si256(v4, w4);
_mm256_store_si256(p+0, x1);
_mm256_store_si256(p+1, x2);
_mm256_store_si256(p+2, x3);
_mm256_store_si256(p+3, x4);
}
}
#define NUM 120
uint8_t program(uint8_t* data[NUM], uint8_t* store[NUM]) {
// 特に意味はないプログラム
// (0, 1); (2, 3); (4, 5); ...
for(int i = 0; i < NUM; i += 2) {
xor(store[i+0], data[i+0], data[i+1]);
}
// (0, 2); (1, 3);
// (4, 6); (5, 7);
// ...
for(int i = 0; i < NUM; i += 4) {
xor(store[i+0], data[i+0], data[i+2]);
xor(store[i+1], data[i+1], data[i+3]);
}
// (0, 3); (1, 4); (2, 5);
// (6, 9); (7, 10); (8, 11);
for(int i = 0; i < NUM; i += 6) {
xor(store[i+0], data[i+0], data[i+3]);
xor(store[i+1], data[i+1], data[i+4]);
xor(store[i+2], data[i+2], data[i+5]);
}
// (0, 4); (1, 5); (2, 6); (3, 7)
// (8, 12); (9, 13); (10, 14); (11, 15);
for(int i = 0; i < NUM; i += 8) {
xor(store[i+0], data[i+0], data[i+4]);
xor(store[i+1], data[i+1], data[i+5]);
xor(store[i+2], data[i+2], data[i+6]);
xor(store[i+3], data[i+3], data[i+7]);
}
uint8_t sum = 0;
for(int i = 0; i < NUM; ++i) {
for(int j = 0; j < 4096; ++j) {
sum += store[i][j];
}
}
return sum;
}
uint8_t program2(uint8_t* data[NUM], uint8_t* store[NUM]) {
/*
program1を最適化したもの
こっちでは
0..7 まで
8..15 まで
という形で 8個を1グループ として
グループごとに処理していく
*/
for(int i = 0; i < NUM; i += 8) {
xor(store[i+0], data[i+0], data[i+1]);
xor(store[i+1], data[i+1], data[i+3]);
xor(store[i+2], data[i+2], data[i+5]);
xor(store[i+3], data[i+3], data[i+7]);
xor(store[i+0], data[i+0], data[i+2]);
xor(store[i+1], data[i+1], data[i+4]);
xor(store[i+2], data[i+2], data[i+6]);
xor(store[i+0], data[i+0], data[i+3]);
xor(store[i+1], data[i+1], data[i+5]);
xor(store[i+0], data[i+0], data[i+4]);
}
uint8_t sum = 0;
for(int i = 0; i < NUM; ++i) {
for(int j = 0; j < 4096; ++j) {
sum += store[i][j];
}
}
return sum;
}
int main() {
struct timespec ts, te;
uint8_t *data[NUM];
uint8_t *store[NUM];
const int iter = 1000;
double total_elapsed = 0.0;
uint8_t total_sum = 0;
for(int i = 0; i < iter; ++i) {
for(int j=0; j<NUM; ++j) {
data[j] = malloc(4096);
store[j] = malloc(4096);
}
for(int j = 0; j < NUM; ++j) {
memcpy(store[j], data[j], 4096);
}
clock_gettime(CLOCK_MONOTONIC, &ts);
#ifdef PROGRAM1
total_sum += program(data, store);
#elif PROGRAM2
total_sum += program2(data, store);
#else
#error hoge
#endif
clock_gettime(CLOCK_MONOTONIC, &te);
double elapsed = milliDiff(&ts, &te);
total_elapsed += elapsed;
for(int j=0; j<NUM; ++j) {
free(data[j]);
free(store[j]);
}
}
printf("elapsed = %lf\n", total_elapsed);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment