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(&current);
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(&current);
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(&current);
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