2022-04-26 18:14:09 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <Compression/ICompressionCodec.h>
|
|
|
|
#include <qpl/qpl.h>
|
2022-07-07 14:04:17 +00:00
|
|
|
|
2022-04-26 18:14:09 +00:00
|
|
|
namespace Poco
|
|
|
|
{
|
|
|
|
class Logger;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
class DeflateJobHWPool
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DeflateJobHWPool();
|
|
|
|
~DeflateJobHWPool();
|
|
|
|
static DeflateJobHWPool & instance();
|
|
|
|
static constexpr auto jobPoolSize = 1024;
|
|
|
|
static constexpr qpl_path_t PATH = qpl_path_hardware;
|
|
|
|
static qpl_job * jobPool[jobPoolSize];
|
|
|
|
static std::atomic_bool jobLock[jobPoolSize];
|
2022-06-08 15:47:44 +00:00
|
|
|
bool jobPoolEnabled;
|
2022-04-26 18:14:09 +00:00
|
|
|
|
2022-06-08 15:47:44 +00:00
|
|
|
bool ALWAYS_INLINE jobPoolReady()
|
|
|
|
{
|
|
|
|
return jobPoolEnabled;
|
|
|
|
}
|
2022-04-26 18:14:09 +00:00
|
|
|
qpl_job * ALWAYS_INLINE acquireJob(uint32_t * job_id)
|
|
|
|
{
|
2022-06-08 15:47:44 +00:00
|
|
|
if (jobPoolEnabled)
|
2022-04-26 18:14:09 +00:00
|
|
|
{
|
2022-06-08 13:28:35 +00:00
|
|
|
uint32_t retry = 0;
|
|
|
|
auto index = random(jobPoolSize);
|
|
|
|
while (tryLockJob(index) == false)
|
2022-04-26 18:14:09 +00:00
|
|
|
{
|
2022-06-08 13:28:35 +00:00
|
|
|
index = random(jobPoolSize);
|
|
|
|
retry++;
|
|
|
|
if (retry > jobPoolSize)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
2022-04-26 18:14:09 +00:00
|
|
|
}
|
2022-06-08 13:28:35 +00:00
|
|
|
*job_id = jobPoolSize - index;
|
|
|
|
return jobPool[index];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return nullptr;
|
2022-04-26 18:14:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
qpl_job * ALWAYS_INLINE releaseJob(uint32_t job_id)
|
|
|
|
{
|
2022-06-08 15:47:44 +00:00
|
|
|
if (jobPoolEnabled)
|
2022-06-08 13:28:35 +00:00
|
|
|
{
|
|
|
|
uint32_t index = jobPoolSize - job_id;
|
|
|
|
ReleaseJobObjectGuard _(index);
|
|
|
|
return jobPool[index];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
2022-04-26 18:14:09 +00:00
|
|
|
}
|
|
|
|
qpl_job * ALWAYS_INLINE getJobPtr(uint32_t job_id)
|
|
|
|
{
|
2022-06-08 15:47:44 +00:00
|
|
|
if (jobPoolEnabled)
|
2022-06-08 13:28:35 +00:00
|
|
|
{
|
|
|
|
uint32_t index = jobPoolSize - job_id;
|
|
|
|
return jobPool[index];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
2022-04-26 18:14:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
size_t ALWAYS_INLINE random(uint32_t pool_size)
|
|
|
|
{
|
|
|
|
size_t tsc = 0;
|
|
|
|
unsigned lo, hi;
|
|
|
|
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi) : :);
|
|
|
|
tsc = (((static_cast<uint64_t>(hi)) << 32) | (static_cast<uint64_t>(lo)));
|
|
|
|
return (static_cast<size_t>((tsc * 44485709377909ULL) >> 4)) % pool_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t ALWAYS_INLINE get_job_size_helper()
|
|
|
|
{
|
|
|
|
static uint32_t size = 0;
|
|
|
|
if (size == 0)
|
|
|
|
{
|
|
|
|
const auto status = qpl_get_job_size(PATH, &size);
|
|
|
|
if (status != QPL_STS_OK)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t ALWAYS_INLINE init_job_helper(qpl_job * qpl_job_ptr)
|
|
|
|
{
|
|
|
|
if (qpl_job_ptr == nullptr)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
auto status = qpl_init_job(PATH, qpl_job_ptr);
|
|
|
|
if (status != QPL_STS_OK)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t ALWAYS_INLINE initJobPool()
|
|
|
|
{
|
|
|
|
static bool initialized = false;
|
|
|
|
|
|
|
|
if (initialized == false)
|
|
|
|
{
|
|
|
|
const int32_t size = get_job_size_helper();
|
|
|
|
if (size < 0)
|
|
|
|
return -1;
|
|
|
|
for (int i = 0; i < jobPoolSize; ++i)
|
|
|
|
{
|
|
|
|
jobPool[i] = nullptr;
|
|
|
|
qpl_job * qpl_job_ptr = reinterpret_cast<qpl_job *>(new uint8_t[size]);
|
|
|
|
if (init_job_helper(qpl_job_ptr) < 0)
|
|
|
|
return -1;
|
|
|
|
jobPool[i] = qpl_job_ptr;
|
|
|
|
jobLock[i].store(false);
|
|
|
|
}
|
|
|
|
initialized = true;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ALWAYS_INLINE tryLockJob(size_t index)
|
|
|
|
{
|
|
|
|
bool expected = false;
|
|
|
|
return jobLock[index].compare_exchange_strong(expected, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ALWAYS_INLINE destroyJobPool()
|
|
|
|
{
|
|
|
|
const uint32_t size = get_job_size_helper();
|
|
|
|
for (uint32_t i = 0; i < jobPoolSize && size > 0; ++i)
|
|
|
|
{
|
|
|
|
while (tryLockJob(i) == false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
if (jobPool[i])
|
|
|
|
{
|
|
|
|
qpl_fini_job(jobPool[i]);
|
|
|
|
delete[] jobPool[i];
|
|
|
|
}
|
|
|
|
jobPool[i] = nullptr;
|
|
|
|
jobLock[i].store(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ReleaseJobObjectGuard
|
|
|
|
{
|
|
|
|
uint32_t index;
|
|
|
|
ReleaseJobObjectGuard() = delete;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ALWAYS_INLINE ReleaseJobObjectGuard(const uint32_t i) : index(i)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
ALWAYS_INLINE ~ReleaseJobObjectGuard()
|
|
|
|
{
|
|
|
|
jobLock[index].store(false);
|
|
|
|
}
|
|
|
|
};
|
2022-06-08 15:47:44 +00:00
|
|
|
Poco::Logger * log;
|
|
|
|
};
|
|
|
|
class SoftwareCodecDeflate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SoftwareCodecDeflate();
|
|
|
|
~SoftwareCodecDeflate();
|
|
|
|
uint32_t doCompressData(const char * source, uint32_t source_size, char * dest, uint32_t dest_size);
|
|
|
|
void doDecompressData(const char * source, uint32_t source_size, char * dest, uint32_t uncompressed_size);
|
|
|
|
|
|
|
|
private:
|
|
|
|
qpl_job * jobSWPtr; //Software Job Codec Ptr
|
|
|
|
std::unique_ptr<uint8_t[]> jobSWbuffer;
|
|
|
|
qpl_job * getJobCodecPtr();
|
2022-04-26 18:14:09 +00:00
|
|
|
};
|
|
|
|
|
2022-06-08 15:47:44 +00:00
|
|
|
class HardwareCodecDeflate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
bool hwEnabled;
|
|
|
|
HardwareCodecDeflate();
|
|
|
|
~HardwareCodecDeflate();
|
|
|
|
uint32_t doCompressData(const char * source, uint32_t source_size, char * dest, uint32_t dest_size) const;
|
|
|
|
uint32_t doDecompressData(const char * source, uint32_t source_size, char * dest, uint32_t uncompressed_size) const;
|
|
|
|
uint32_t doDecompressDataReq(const char * source, uint32_t source_size, char * dest, uint32_t uncompressed_size);
|
2022-07-07 01:37:11 +00:00
|
|
|
void doFlushAsynchronousDecompressRequests();
|
2022-06-08 15:47:44 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
std::map<uint32_t, qpl_job *> jobDecompAsyncMap;
|
|
|
|
Poco::Logger * log;
|
|
|
|
};
|
2022-04-26 18:14:09 +00:00
|
|
|
class CompressionCodecDeflate : public ICompressionCodec
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CompressionCodecDeflate();
|
2022-06-08 15:47:44 +00:00
|
|
|
//~CompressionCodecDeflate() ;
|
2022-04-26 18:14:09 +00:00
|
|
|
uint8_t getMethodByte() const override;
|
|
|
|
void updateHash(SipHash & hash) const override;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
bool isCompression() const override
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool isGenericCompression() const override
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
uint32_t doCompressData(const char * source, uint32_t source_size, char * dest) const override;
|
|
|
|
uint32_t doCompressDataSW(const char * source, uint32_t source_size, char * dest) const;
|
|
|
|
void doDecompressData(const char * source, uint32_t source_size, char * dest, uint32_t uncompressed_size) const override;
|
2022-07-07 01:37:11 +00:00
|
|
|
void doFlushAsynchronousDecompressRequests() override;
|
2022-04-26 18:14:09 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
uint32_t getMaxCompressedDataSize(uint32_t uncompressed_size) const override;
|
2022-06-08 15:47:44 +00:00
|
|
|
std::unique_ptr<HardwareCodecDeflate> hwCodec;
|
|
|
|
std::unique_ptr<SoftwareCodecDeflate> swCodec;
|
2022-04-26 18:14:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|