#define NDEBUG
using byte = unsigned char;
static const int CS = 1024 * 16; static const int TPB = 512; #if defined(__AMDGCN_WAVEFRONT_SIZE) && (__AMDGCN_WAVEFRONT_SIZE == 64)
#define WS 64
#else
#define WS 32
#endif
#include <limits>
#include <cmath>
#include <cassert>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <stdexcept>
#include <sys/time.h>
#include "include/macros.h"
struct CPUTimer
{
timeval beg, end;
CPUTimer() {}
~CPUTimer() {}
void start() {gettimeofday(&beg, NULL);}
double stop() {gettimeofday(&end, NULL); return end.tv_sec - beg.tv_sec + (end.tv_usec - beg.tv_usec) / 1000000.0;}
};
static void h_encode(const byte* const __restrict__ input, const long long insize, byte* const __restrict__ output, long long& outsize)
{
const long long chunks = (insize + CS - 1) / CS; long long* const head_out = (long long*)output;
unsigned short* const size_out = (unsigned short*)&head_out[1];
byte* const data_out = (byte*)&size_out[chunks];
long long* const carry = new long long [chunks];
memset(carry, 0, chunks * sizeof(long long));
#pragma omp parallel for schedule(dynamic, 1)
for (long long chunkID = 0; chunkID < chunks; chunkID++) {
long long chunk1 [CS / sizeof(long long)];
long long chunk2 [CS / sizeof(long long)];
byte* in = (byte*)chunk1;
byte* out = (byte*)chunk2;
const long long base = chunkID * CS;
const int osize = (int)std::min((long long)CS, insize - base);
memcpy(out, &input[base], osize);
int csize = osize;
bool good = true;
if (good) {
std::swap(in, out);
good = h_CLOG_2(csize, in, out);
}
long long offs = 0LL;
if (chunkID > 0) {
do {
#pragma omp atomic read
offs = carry[chunkID - 1];
} while (offs == 0);
#pragma omp flush
}
if (good && (csize < osize)) {
#pragma omp atomic write
carry[chunkID] = (offs + (long long)csize);
size_out[chunkID] = csize;
memcpy(&data_out[offs], out, csize);
} else {
#pragma omp atomic write
carry[chunkID] = (offs + (long long)osize);
size_out[chunkID] = osize;
memcpy(&data_out[offs], &input[base], osize);
}
}
head_out[0] = insize;
outsize = &data_out[carry[chunks - 1]] - output;
delete [] carry;
}
int main(int argc, char* argv [])
{
printf("Copyright 2024 Texas State University\n\n");
if (argc < 3) {printf("USAGE: %s input_file_name compressed_file_name [performance_analysis(y)]\n\n", argv[0]); return -1;}
FILE* const fin = fopen(argv[1], "rb");
fseek(fin, 0, SEEK_END);
const long long fsize = ftell(fin);
if (fsize <= 0) {fprintf(stderr, "ERROR: input file too small\n\n"); throw std::runtime_error("LC error");}
byte* const input = new byte [fsize];
fseek(fin, 0, SEEK_SET);
const long long insize = fread(input, 1, fsize, fin); assert(insize == fsize);
fclose(fin);
printf("original size: %lld bytes\n", insize);
char* perf_str = argv[3];
bool perf = false;
if (perf_str != nullptr && strcmp(perf_str, "y") == 0) {
perf = true;
} else if (perf_str != nullptr && strcmp(perf_str, "y") != 0) {
fprintf(stderr, "ERROR: Invalid argument. Use 'y' or nothing.\n");
throw std::runtime_error("LC error");
}
const long long chunks = (insize + CS - 1) / CS; const long long maxsize = 2 * sizeof(long long) + chunks * sizeof(short) + chunks * CS;
byte* const hencoded = new byte [maxsize];
long long hencsize = 0;
byte* hpreencdata = new byte [insize];
std::copy(input, input + insize, hpreencdata);
long long hpreencsize = insize;
if (perf) {
byte* dummy = new byte [insize];
std::copy(input, input + insize, dummy);
long long dummy_size = 0;
h_encode(dummy, dummy_size, hencoded, hencsize);
delete [] dummy;
}
CPUTimer htimer;
htimer.start();
h_encode(hpreencdata, hpreencsize, hencoded, hencsize);
double hruntime = htimer.stop();
printf("encoded size: %lld bytes\n", hencsize);
const float CR = (100.0 * hencsize) / insize;
printf("ratio: %6.2f%% %7.3fx\n", CR, 100.0 / CR);
if (perf) {
printf("encoding time: %.6f s\n", hruntime);
double hthroughput = insize * 0.000000001 / hruntime;
printf("encoding throughput: %8.3f Gbytes/s\n", hthroughput);
}
FILE* const fout = fopen(argv[2], "wb");
fwrite(hencoded, 1, hencsize, fout);
fclose(fout);
delete [] input;
delete [] hencoded;
return 0;
}