1 /*
2 Copyright (C) 2021 The Blosc Developers <blosc@blosc.org>
3 https://blosc.org
4 License: BSD 3-Clause (see LICENSE.txt)
5
6 Benchmark showing Blosc zero detection capabilities via run-length.
7
8 */
9
10 #include <stdio.h>
11 #include <stdint.h>
12 #include <assert.h>
13 #include <math.h>
14
15 #include "blosc2.h"
16
17
18 #define KB 1024
19 #define MB (1024*KB)
20 #define GB (1024*MB)
21
22 #define NCHUNKS (2000)
23 #define CHUNKSIZE (500 * 1000) // > NCHUNKS for the bench purposes
24 #define NTHREADS 8
25
26 enum {
27 ZERO_DETECTION = 0,
28 CHECK_ZEROS = 1,
29 CHECK_NANS = 2,
30 CHECK_VALUES = 3,
31 CHECK_UNINIT = 4,
32 };
33 #define REPEATED_VALUE 1
34
35
check_special_values(int svalue)36 int check_special_values(int svalue) {
37 blosc2_schunk *schunk;
38 int32_t isize = CHUNKSIZE * sizeof(int32_t);
39 int32_t osize = CHUNKSIZE * sizeof(int32_t) + BLOSC_MAX_OVERHEAD;
40 int dsize, csize;
41 int64_t nbytes, frame_len;
42 int nchunk, nchunks = 0;
43 int rc;
44 int32_t value = REPEATED_VALUE;
45 float fvalue;
46 blosc_timestamp_t last, current;
47 double totaltime;
48 double totalsize = (double)isize * NCHUNKS;
49 int32_t *data_buffer = malloc(CHUNKSIZE * sizeof(int32_t));
50 int32_t *rec_buffer = malloc(CHUNKSIZE * sizeof(int32_t));
51
52 /* Initialize the Blosc compressor */
53 blosc_init();
54
55 /* Create a super-chunk container */
56 blosc2_cparams cparams = BLOSC2_CPARAMS_DEFAULTS;
57 cparams.typesize = sizeof(int32_t);
58 cparams.compcode = BLOSC_BLOSCLZ;
59 cparams.clevel = 9;
60 cparams.nthreads = NTHREADS;
61 blosc2_storage storage = {.cparams=&cparams, .contiguous=false};
62 schunk = blosc2_schunk_new(&storage);
63
64 void* chunk = malloc(BLOSC_EXTENDED_HEADER_LENGTH + isize);
65
66 // Cache the special chunks
67 switch (svalue) {
68 case ZERO_DETECTION:
69 memset(data_buffer, 0, isize);
70 csize = blosc2_compress(5, 1, sizeof(int32_t), data_buffer, isize, chunk, osize);
71 break;
72 case CHECK_ZEROS:
73 csize = blosc2_chunk_zeros(cparams, isize, chunk, BLOSC_EXTENDED_HEADER_LENGTH);
74 break;
75 case CHECK_UNINIT:
76 csize = blosc2_chunk_uninit(cparams, isize, chunk, BLOSC_EXTENDED_HEADER_LENGTH);
77 break;
78 case CHECK_NANS:
79 csize = blosc2_chunk_nans(cparams, isize, chunk, BLOSC_EXTENDED_HEADER_LENGTH);
80 break;
81 case CHECK_VALUES:
82 csize = blosc2_chunk_repeatval(cparams, isize, chunk,
83 BLOSC_EXTENDED_HEADER_LENGTH + sizeof(int32_t), &value);
84 break;
85 default:
86 printf("Unknown case\n");
87 exit(1);
88 }
89 if (csize < 0) {
90 printf("Error creating chunk: %d\n", csize);
91 exit(1);
92 }
93
94 /* Append the chunks */
95 blosc_set_timestamp(&last);
96 for (nchunk = 0; nchunk < NCHUNKS; nchunk++) {
97 nchunks = blosc2_schunk_append_chunk(schunk, chunk, true);
98 if (nchunks < 0) {
99 printf("Error appending chunk: %d\n", nchunks);
100 exit(1);
101 }
102 }
103 blosc_set_timestamp(¤t);
104 free(chunk);
105 totaltime = blosc_elapsed_secs(last, current);
106 printf("\n[Compr] Elapsed time:\t %6.3f s."
107 " Processed data: %.3f GB (%.3f GB/s)\n",
108 totaltime, totalsize / GB, totalsize / (GB * totaltime));
109
110 /* Gather some info */
111 nbytes = schunk->nbytes;
112 frame_len = blosc2_schunk_frame_len(schunk);
113 printf("Compression super-chunk: %ld -> %ld (%.1fx)\n",
114 (long)nbytes, (long)frame_len, (1. * nbytes) / frame_len);
115
116 /* Retrieve and decompress the chunks */
117 blosc_set_timestamp(&last);
118 for (nchunk = 0; nchunk < NCHUNKS; nchunk++) {
119 dsize = blosc2_schunk_decompress_chunk(schunk, nchunk, rec_buffer, isize);
120 if (dsize < 0) {
121 printf("Decompression error. Error code: %d\n", dsize);
122 exit(dsize);
123 }
124 assert (dsize == (int)isize);
125 }
126 blosc_set_timestamp(¤t);
127 totaltime = blosc_elapsed_secs(last, current);
128 totalsize = (double)(isize) * nchunks;
129 printf("[Decompr] Elapsed time:\t %6.3f s."
130 " Processed data: %.3f GB (%.3f GB/s)\n",
131 totaltime, totalsize / GB, totalsize / (GB * totaltime));
132
133 /* Exercise the getitem */
134 blosc_set_timestamp(&last);
135 for (nchunk = 0; nchunk < NCHUNKS; nchunk++) {
136 bool needs_free;
137 uint8_t* chunk_;
138 csize = blosc2_schunk_get_chunk(schunk, nchunk, &chunk_, &needs_free);
139 if (csize < 0) {
140 printf("blosc2_schunk_get_chunk error. Error code: %d\n", dsize);
141 return csize;
142 }
143 switch (svalue) {
144 case CHECK_VALUES:
145 rc = blosc_getitem(chunk_, nchunk, 1, &value);
146 if (rc < 0) {
147 printf("Error in getitem of a special value\n");
148 return rc;
149 }
150 if (value != REPEATED_VALUE) {
151 printf("Wrong value!");
152 exit(1);
153 }
154 break;
155 case CHECK_NANS:
156 rc = blosc_getitem(chunk_, nchunk, 1, &fvalue);
157 if (rc < 0) {
158 printf("Error in getitem of a special value\n");
159 return rc;
160 }
161 if (!isnan(fvalue)) {
162 printf("Wrong value!");
163 exit(1);
164 }
165 break;
166 case CHECK_ZEROS:
167 rc = blosc_getitem(chunk_, nchunk, 1, &value);
168 if (rc < 0) {
169 printf("Error in getitem of zeros value\n");
170 return rc;
171 }
172 if (value != 0) {
173 printf("Wrong value!");
174 exit(1);
175 }
176 break;
177 default:
178 // It can only be non-initialized
179 rc = blosc_getitem(chunk_, nchunk, 1, &value);
180 if (rc < 0) {
181 printf("Error in getitem of an non-initialized value\n");
182 return rc;
183 }
184 }
185 if (needs_free) {
186 free(chunk_);
187 }
188 }
189 blosc_set_timestamp(¤t);
190 totaltime = blosc_elapsed_secs(last, current);
191 printf("[getitem] Elapsed time:\t %6.3f s.\n", totaltime);
192
193 // /* Check that all the values have a good roundtrip */
194 // blosc_set_timestamp(&last);
195 // for (nchunk = 0; nchunk < NCHUNKS; nchunk++) {
196 // dsize = blosc2_schunk_decompress_chunk(schunk, nchunk, (void *) rec_buffer, isize);
197 // if (dsize < 0) {
198 // printf("Decompression error. Error code: %d\n", dsize);
199 // return dsize;
200 // }
201 // assert (dsize == (int)isize);
202 // if (CHECK_VALUE) {
203 // int32_t* buffer = (int32_t*)rec_buffer;
204 // for (int i = 0; i < CHUNKSIZE; i++) {
205 // if (buffer[i] != REPEATED_VALUE) {
206 // printf("Value is not correct in chunk %d, position: %d\n", nchunk, i);
207 // return -1;
208 // }
209 // }
210 // }
211 // else if (CHECK_NAN) {
212 // float* buffer = (float*)rec_buffer;
213 // for (int i = 0; i < CHUNKSIZE; i++) {
214 // if (!isnan(buffer[i])) {
215 // printf("Value is not correct in chunk %d, position: %d\n", nchunk, i);
216 // return -1;
217 // }
218 // }
219 // }
220 // else {
221 // int32_t* buffer = (int32_t*)rec_buffer;
222 // for (int i = 0; i < CHUNKSIZE; i++) {
223 // if (buffer[i] != 0) {
224 // printf("Value is not correct in chunk %d, position: %d\n", nchunk, i);
225 // return -1;
226 // }
227 // }
228 // }
229 // }
230 // printf("All data did a good roundtrip!\n");
231
232 /* Free resources */
233 free(data_buffer);
234 free(rec_buffer);
235 /* Destroy the super-chunk */
236 blosc2_schunk_free(schunk);
237 /* Destroy the Blosc environment */
238 blosc_destroy();
239
240 return 0;
241 }
242
243
main(void)244 int main(void) {
245 int rc;
246 printf("*** Testing special zeros...");
247 rc = check_special_values(CHECK_ZEROS);
248 if (rc < 0) {
249 return rc;
250 }
251 printf("*** Testing NaNs...");
252 rc = check_special_values(CHECK_NANS);
253 if (rc < 0) {
254 return rc;
255 }
256 printf("*** Testing repeated values...");
257 rc = check_special_values(CHECK_VALUES);
258 if (rc < 0) {
259 return rc;
260 }
261 printf("*** Testing non-initialized values...");
262 rc = check_special_values(CHECK_UNINIT);
263 if (rc < 0) {
264 return rc;
265 }
266 printf("Testing zero detection...");
267 rc = check_special_values(ZERO_DETECTION);
268 if (rc < 0) {
269 return rc;
270 }
271 }
272