#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_decode(const byte* const __restrict__ input, byte* const __restrict__ output, long long& outsize)
{
long long* const head_in = (long long*)input;
outsize = head_in[0];
const long long chunks = (outsize + CS - 1) / CS; unsigned short* const size_in = (unsigned short*)&head_in[1];
byte* const data_in = (byte*)&size_in[chunks];
long long* const start = new long long [chunks];
long long pfs = 0;
for (long long chunkID = 0; chunkID < chunks; chunkID++) {
start[chunkID] = pfs;
pfs += (long long)size_in[chunkID];
}
#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, outsize - base);
int csize = size_in[chunkID];
if (csize == osize) {
memcpy(&output[base], &data_in[start[chunkID]], osize);
} else {
memcpy(out, &data_in[start[chunkID]], csize);
std::swap(in, out);
h_iCLOG_2(csize, in, out);
if (csize != osize) {fprintf(stderr, "ERROR: csize %d does not match osize %d in chunk %lld\n\n", csize, osize, chunkID); throw std::runtime_error("LC error");}
memcpy(&output[base], out, csize);
}
}
delete [] start;
}
int main(int argc, char* argv [])
{
printf("Copyright 2024 Texas State University\n\n");
if (argc < 3) {printf("USAGE: %s compressed_file_name decompressed_file_name [performance_analysis (y)]\n\n", argv[0]); return -1;}
FILE* const fin = fopen(argv[1], "rb");
long long pre_size = 0;
const long long pre_val = fread(&pre_size, sizeof(pre_size), 1, fin); assert(pre_val == sizeof(pre_size));
fseek(fin, 0, SEEK_END);
const long long hencsize = ftell(fin); assert(hencsize > 0);
byte* const hencoded = new byte [std::max(pre_size, hencsize)];
fseek(fin, 0, SEEK_SET);
const long long insize = fread(hencoded, 1, hencsize, fin); assert(insize == hencsize);
fclose(fin);
printf("encoded 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");
}
byte* hdecoded = new byte [pre_size];
long long hdecsize = 0;
if (perf) {
byte* dummy = new byte [pre_size];
long long dummy_size = 0;
h_decode(hencoded, dummy, dummy_size);
delete [] dummy;
}
CPUTimer htimer;
htimer.start();
h_decode(hencoded, hdecoded, hdecsize);
double hruntime = htimer.stop();
printf("decoded size: %lld bytes\n", hdecsize);
const float CR = (100.0 * insize) / hdecsize;
printf("ratio: %6.2f%% %7.3fx\n", CR, 100.0 / CR);
if (perf) {
printf("decoding time: %.6f s\n", hruntime);
double hthroughput = hdecsize * 0.000000001 / hruntime;
printf("decoding throughput: %8.3f Gbytes/s\n", hthroughput);
}
FILE* const fout = fopen(argv[2], "wb");
fwrite(hdecoded, 1, hdecsize, fout);
fclose(fout);
delete [] hencoded;
delete [] hdecoded;
return 0;
}