forked from CODARcode/MGARD
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathZstd.hpp
More file actions
152 lines (133 loc) · 5.76 KB
/
Copy pathZstd.hpp
File metadata and controls
152 lines (133 loc) · 5.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#ifndef MGARD_X_ZSTD_TEMPLATE_HPP
#define MGARD_X_ZSTD_TEMPLATE_HPP
#include <zstd.h>
namespace mgard_x {
#define CHECK(cond, ...) \
do { \
if (!(cond)) { \
fprintf(stderr, "%s:%d CHECK(%s) failed: ", __FILE__, __LINE__, #cond); \
fprintf(stderr, "" __VA_ARGS__); \
fprintf(stderr, "\n"); \
exit(1); \
} \
} while (0)
#define CHECK_ZSTD(fn, ...) \
do { \
size_t const err = (fn); \
CHECK(!ZSTD_isError(err), "%s", ZSTD_getErrorName(err)); \
} while (0)
template <typename DeviceType> class Zstd {
public:
Zstd() {}
Zstd(SIZE n, int compressionLevel) : compressionLevel(compressionLevel) {
Resize(n, compressionLevel, 0);
DeviceRuntime<DeviceType>::SyncQueue(0);
}
void Resize(SIZE buffer_size, int compressionLevel, int queue_idx) {
if (this->buffer_size < buffer_size) {
Release(queue_idx);
this->compressionLevel = compressionLevel;
size_t const estimated_out_size = ZSTD_compressBound(buffer_size);
MemoryManager<DeviceType>::MallocHost(
out_data, estimated_out_size + sizeof(size_t), queue_idx);
MemoryManager<DeviceType>::MallocHost(in_data, buffer_size, queue_idx);
this->buffer_size = buffer_size;
}
}
void Release(int queue_idx) {
if (out_data != nullptr) {
MemoryManager<DeviceType>::FreeHost(out_data, queue_idx);
out_data = nullptr;
}
if (in_data != nullptr) {
MemoryManager<DeviceType>::FreeHost(in_data, queue_idx);
in_data = nullptr;
}
}
~Zstd() {
Release(0);
DeviceRuntime<DeviceType>::SyncQueue(0);
}
static size_t EstimateMemoryFootprint(SIZE n) {
size_t size = 0;
return size;
}
void Compress(Array<1, Byte, DeviceType> &data, int queue_idx) {
Timer timer;
if (log::level & log::TIME)
timer.start();
Array<1, Byte, DeviceType> &input_data = data;
Array<1, Byte, DeviceType> &output_data = data;
size_t input_count = input_data.shape(0);
Resize(input_count, compressionLevel, queue_idx);
size_t const estimated_out_size = ZSTD_compressBound(input_count);
MemoryManager<DeviceType>::Copy1D(in_data, input_data.data(), input_count,
queue_idx);
DeviceRuntime<DeviceType>::SyncQueue(queue_idx);
size_t const actual_out_size =
ZSTD_compress(out_data + sizeof(size_t), estimated_out_size, in_data,
input_count, compressionLevel);
CHECK_ZSTD(actual_out_size);
*(size_t *)out_data = (size_t)input_count;
output_data.resize({(SIZE)(actual_out_size + sizeof(size_t))});
MemoryManager<DeviceType>::Copy1D(output_data.data(), out_data,
actual_out_size + sizeof(size_t),
queue_idx);
DeviceRuntime<DeviceType>::SyncQueue(queue_idx);
log::info("Zstd compression level: " + std::to_string(compressionLevel));
log::info("Zstd compress ratio: " +
std::to_string((double)(input_count) /
(actual_out_size + sizeof(size_t))));
if (log::level & log::TIME) {
timer.end();
timer.print("Zstd compress");
timer.print_throughput("Zstd compress", input_count);
timer.clear();
}
}
void Decompress(Array<1, Byte, DeviceType> &data, int queue_idx) {
Timer timer;
if (log::level & log::TIME)
timer.start();
Array<1, Byte, DeviceType> &input_data = data;
Array<1, Byte, DeviceType> &output_data = data;
size_t input_count = input_data.shape(0);
Resize(input_count, compressionLevel, queue_idx);
MemoryManager<DeviceType>::Copy1D(in_data, input_data.data(), input_count,
queue_idx);
DeviceRuntime<DeviceType>::SyncQueue(queue_idx);
uint32_t actual_out_count = 0;
actual_out_count = *reinterpret_cast<const size_t *>(in_data);
// FIX: Only resize out_data if needed, do not touch in_data which contains
// the compressed data we just copied. The original code called Resize()
// which would free and reallocate BOTH in_data and out_data, destroying
// the compressed data when actual_out_count > buffer_size.
if (this->buffer_size < actual_out_count) {
size_t const estimated_out_size = ZSTD_compressBound(actual_out_count);
if (out_data != nullptr) {
MemoryManager<DeviceType>::FreeHost(out_data, queue_idx);
}
MemoryManager<DeviceType>::MallocHost(
out_data, estimated_out_size + sizeof(size_t), queue_idx);
}
DeviceRuntime<DeviceType>::SyncQueue(queue_idx);
ZSTD_decompress(out_data, actual_out_count, in_data + sizeof(size_t),
input_count - sizeof(size_t));
output_data.resize({(SIZE)actual_out_count});
MemoryManager<DeviceType>::Copy1D(output_data.data(), out_data,
actual_out_count, queue_idx);
DeviceRuntime<DeviceType>::SyncQueue(queue_idx);
if (log::level & log::TIME) {
timer.end();
timer.print("Zstd decompress");
timer.print_throughput("Zstd decompress", actual_out_count);
timer.clear();
}
}
int compressionLevel;
SIZE buffer_size = 0;
Byte *in_data = nullptr;
Byte *out_data = nullptr;
};
} // namespace mgard_x
#endif