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 for testing sframe vs frame.
7   For usage instructions of this benchmark, please see:
8     https://www.blosc.org/pages/synthetic-benchmarks/
9   We are collecting speeds for different machines, so the output of your
10   benchmarks and your processor specifications are welcome!
11 
12   See LICENSE.txt for details about copyright and rights to use.
13 **********************************************************************/
14 
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <blosc2.h>
19 #include <assert.h>
20 #include <inttypes.h>
21 
22 #define KB  1024
23 #define MB  (1024*KB)
24 #define GB  (1024*MB)
25 
26 #define NCHUNKS 1000       /* number of chunks */
27 #define CHUNKSIZE (200 * 1000)
28 
29 int nchunks = NCHUNKS;
30 int iterations = 5;
31 
32 #if defined(_WIN32) && !defined(__MINGW32__)
33 #include <time.h>
34   #include "win32/stdint-windows.h"
35 #else
36 #include <stdint.h>
37 #include <sys/time.h>
38 #endif
39 
40 #if defined(_WIN32)
41 #include <malloc.h>
42 
43 #endif  /* defined(_WIN32) && !defined(__MINGW32__) */
44 
45 
test_update(blosc2_schunk * schunk_sframe,blosc2_schunk * schunk_cframe)46 void test_update(blosc2_schunk* schunk_sframe, blosc2_schunk* schunk_cframe) {
47   blosc_timestamp_t last, current;
48   double cframe_update_time, sframe_update_time;
49 
50   size_t isize = CHUNKSIZE * sizeof(int32_t);
51   int32_t* data = malloc(isize);
52 
53   // Random update list
54   int32_t* update_chunks = malloc(sizeof(int32_t) * iterations);
55   srand(time(NULL));
56   for (int i = 0; i < iterations; i++) {
57     update_chunks[i] = rand() % schunk_sframe->nchunks;
58   }
59 
60   printf("*******************************************************\n");
61   printf("******************* Updating %d chunks ******************\n", iterations);
62   printf("*******************************************************\n");
63 
64   // Update the sframe chunks
65   sframe_update_time = 0.0;
66   cframe_update_time = 0.0;
67   int32_t datasize = sizeof(int32_t) * CHUNKSIZE;
68   int32_t chunksize = sizeof(int32_t) * CHUNKSIZE + BLOSC_MAX_OVERHEAD;
69   uint8_t* chunk;
70   int csize;
71   int _nchunks;
72   for (int i = 0; i < iterations; i++) {
73     // Generate data
74     for (int j = 0; j < CHUNKSIZE; j++) {
75       data[j] = i * CHUNKSIZE;
76     }
77     chunk = malloc(chunksize);
78     csize = blosc2_compress_ctx(schunk_sframe->cctx, data, datasize, chunk, chunksize);
79     if (csize < 0) {
80       printf("ERROR: chunk cannot be compressed\n");
81     }
82     // Sframe
83     blosc_set_timestamp(&current);
84     _nchunks = blosc2_schunk_update_chunk(schunk_sframe, update_chunks[i], chunk, true);
85     blosc_set_timestamp(&last);
86     if (_nchunks < 0){
87       printf("ERROR: chunk cannot be updated correctly\n");
88     }
89     sframe_update_time += blosc_elapsed_secs(current, last);
90 
91     // Frame
92     blosc_set_timestamp(&current);
93     _nchunks = blosc2_schunk_update_chunk(schunk_cframe, update_chunks[i], chunk, true);
94     blosc_set_timestamp(&last);
95     free(chunk);
96     if (_nchunks <= 0){
97       printf("ERROR: chunk cannot be updated correctly\n");
98     }
99     cframe_update_time += blosc_elapsed_secs(current, last);
100   }
101 
102   printf("[Sframe Update] Elapsed time:\t %6.3f s. Total sframe size: %.3" PRId64 " bytes\n",
103          sframe_update_time, schunk_sframe->cbytes);
104   printf("[Cframe Update] Elapsed time:\t %6.3f s. Total cframe size: %.3" PRId64 " bytes\n",
105          cframe_update_time, schunk_cframe->cbytes);
106 
107   /* Free resources */
108   free(update_chunks);
109   free(data);
110 }
111 
test_insert(blosc2_schunk * schunk_sframe,blosc2_schunk * schunk_cframe)112 void test_insert(blosc2_schunk* schunk_sframe, blosc2_schunk* schunk_cframe) {
113   blosc_timestamp_t last, current;
114   double cframe_insert_time, sframe_insert_time;
115 
116   size_t isize = CHUNKSIZE * sizeof(int32_t);
117   int32_t* data = malloc(isize);
118 
119   // Random insert list
120   int32_t* insert_chunks = malloc(sizeof(int32_t) * iterations);
121   srand(time(NULL));
122   for (int i = 0; i < iterations; i++) {
123     insert_chunks[i] = rand() % schunk_sframe->nchunks;
124   }
125 
126   printf("*******************************************************\n");
127   printf("****************** Inserting %d chunks *****************\n", iterations);
128   printf("*******************************************************\n");
129 
130   // Update the sframe chunks
131   sframe_insert_time = 0.0;
132   cframe_insert_time = 0.0;
133   int32_t datasize = sizeof(int32_t) * CHUNKSIZE;
134   int32_t chunksize = sizeof(int32_t) * CHUNKSIZE + BLOSC_MAX_OVERHEAD;
135   uint8_t* chunk;
136   int csize;
137   int _nchunks;
138   for (int i = 0; i < iterations; i++) {
139     // Generate data
140     for (int j = 0; j < CHUNKSIZE; j++) {
141       data[j] = j + i * CHUNKSIZE;
142     }
143     chunk = malloc(chunksize);
144     csize = blosc2_compress_ctx(schunk_sframe->cctx, data, datasize, chunk, chunksize);
145     if (csize < 0) {
146       printf("ERROR: chunk cannot be compressed\n");
147     }
148     // Sframe
149     blosc_set_timestamp(&current);
150     _nchunks = blosc2_schunk_insert_chunk(schunk_sframe, insert_chunks[i], chunk, true);
151     blosc_set_timestamp(&last);
152     if (_nchunks < 0){
153       printf("ERROR: chunk cannot be updated correctly\n");
154     }
155     sframe_insert_time += blosc_elapsed_secs(current, last);
156 
157     // Frame
158     blosc_set_timestamp(&current);
159     _nchunks = blosc2_schunk_update_chunk(schunk_cframe, insert_chunks[i], chunk, true);
160     blosc_set_timestamp(&last);
161     free(chunk);
162     if (_nchunks <= 0){
163       printf("ERROR: chunk cannot be updated correctly\n");
164     }
165     cframe_insert_time += blosc_elapsed_secs(current, last);
166   }
167 
168   printf("[Sframe Insert] Elapsed time:\t %6.3f s.  Total sframe size: %.3" PRId64 " bytes \n",
169          sframe_insert_time, schunk_sframe->cbytes);
170   printf("[Cframe Insert] Elapsed time:\t %6.3f s.  Total cframe size: %.3" PRId64 " bytes \n",
171          cframe_insert_time, schunk_cframe->cbytes);
172 
173 
174   /* Free resources */
175   free(insert_chunks);
176   free(data);
177 }
178 
test_reorder(blosc2_schunk * schunk_sframe,blosc2_schunk * schunk_cframe)179 void test_reorder(blosc2_schunk* schunk_sframe, blosc2_schunk* schunk_cframe) {
180   blosc_timestamp_t last, current;
181   double cframe_reorder_time, sframe_reorder_time;
182 
183   // Reorder list
184   int *offsets_order = malloc(sizeof(int) * schunk_sframe->nchunks);
185   for (int i = 0; i < schunk_sframe->nchunks; ++i) {
186     offsets_order[i] = (i + 3) % schunk_sframe->nchunks;
187   }
188 
189   printf("*******************************************************\n");
190   printf("****************** Reordering chunks ******************\n");
191   printf("*******************************************************\n");
192 
193   // Reorder sframe
194   blosc_set_timestamp(&current);
195   int err = blosc2_schunk_reorder_offsets(schunk_sframe, offsets_order);
196   blosc_set_timestamp(&last);
197   if (err < 0) {
198     printf("ERROR: cannot reorder chunks\n");
199   }
200   sframe_reorder_time = blosc_elapsed_secs(current, last);
201 
202   // Reorder frame
203   blosc_set_timestamp(&current);
204   err = blosc2_schunk_reorder_offsets(schunk_cframe, offsets_order);
205   blosc_set_timestamp(&last);
206   if (err < 0) {
207     printf("ERROR: cannot reorder chunks\n");
208   }
209   cframe_reorder_time = blosc_elapsed_secs(current, last);
210 
211   printf("[Sframe Update] Elapsed time:\t %f s.  Total sframe size: %.3" PRId64 " bytes \n",
212          sframe_reorder_time, schunk_sframe->cbytes);
213   printf("[Cframe Update] Elapsed time:\t %f s.  Total cframe size: %.3" PRId64 " bytes \n",
214          cframe_reorder_time, schunk_cframe->cbytes);
215 
216   /* Free resources */
217   free(offsets_order);
218 }
219 
test_create_sframe_frame(char * operation)220 void test_create_sframe_frame(char* operation) {
221   blosc_timestamp_t last, current;
222   double cframe_append_time, sframe_append_time, cframe_decompress_time, sframe_decompress_time;
223 
224   int64_t nbytes, cbytes;
225   size_t isize = CHUNKSIZE * sizeof(int32_t);
226   int dsize;
227   float totalsize = (float)(isize * nchunks);
228   int32_t* data = malloc(isize);
229   int32_t* data_dest = malloc(isize);
230 
231   blosc2_cparams cparams = BLOSC2_CPARAMS_DEFAULTS;
232   blosc2_dparams dparams = BLOSC2_DPARAMS_DEFAULTS;
233 
234   blosc2_schunk* schunk_sframe;
235   blosc2_schunk* schunk_cframe;
236 
237   /* Initialize the Blosc compressor */
238   blosc_init();
239   printf("*******************************************************\n");
240   printf("***** Creating the frame and sframe with %d chunks ****\n", nchunks);
241   printf("*******************************************************\n");
242   /* Create a frame container */
243   cparams.typesize = sizeof(int32_t);
244 
245   cparams.nthreads = 2;
246   dparams.nthreads = 2;
247 
248   blosc2_storage storage = {.contiguous=false, .urlpath="dir.b2frame", .cparams=&cparams, .dparams=&dparams};
249   blosc2_remove_urlpath(storage.urlpath);
250   schunk_sframe = blosc2_schunk_new(&storage);
251 
252   blosc2_storage storage2 = {.contiguous=true, .urlpath="test_cframe.b2frame", .cparams=&cparams, .dparams=&dparams};
253   blosc2_remove_urlpath(storage2.urlpath);
254   schunk_cframe = blosc2_schunk_new(&storage2);
255 
256   printf("Test comparation frame vs sframe with %d chunks.\n", nchunks);
257 
258   // Feed it with data
259   sframe_append_time=0.0;
260   cframe_append_time=0.0;
261   blosc_set_timestamp(&current);
262   for (int nchunk = 0; nchunk < nchunks; nchunk++) {
263     for (int i = 0; i < CHUNKSIZE; i++) {
264       data[i] = i + nchunk * CHUNKSIZE;
265     }
266     blosc_set_timestamp(&current);
267     blosc2_schunk_append_buffer(schunk_sframe, data, isize);
268     blosc_set_timestamp(&last);
269     sframe_append_time += blosc_elapsed_secs(current, last);
270 
271     blosc_set_timestamp(&current);
272     blosc2_schunk_append_buffer(schunk_cframe, data, isize);
273     blosc_set_timestamp(&last);
274     cframe_append_time += blosc_elapsed_secs(current, last);
275   }
276   printf("[Sframe Compr] Elapsed time:\t %6.3f s.  Processed data: %.3f GB (%.3f GB/s)\n",
277          sframe_append_time, totalsize / GB, totalsize / (GB * sframe_append_time));
278   printf("[Cframe Compr] Elapsed time:\t %6.3f s.  Processed data: %.3f GB (%.3f GB/s)\n",
279          cframe_append_time, totalsize / GB, totalsize / (GB * cframe_append_time));
280 
281   /* Gather some info */
282   nbytes = schunk_sframe->nbytes;
283   cbytes = schunk_sframe->cbytes;
284   printf("Compression super-chunk-sframe: %ld -> %ld (%.1fx)\n",
285          (long)nbytes, (long)cbytes, (1. * nbytes) / cbytes);
286   nbytes = schunk_cframe->nbytes;
287   cbytes = schunk_cframe->cbytes;
288   printf("Compression super-chunk-cframe: %ld -> %ld (%.1fx)\n",
289          (long)nbytes, (long)cbytes, (1. * nbytes) / cbytes);
290 
291   // Decompress the data
292   sframe_decompress_time = 0;
293   cframe_decompress_time = 0;
294   for (int nchunk = 0; nchunk < nchunks; nchunk++) {
295     // Sframe
296     blosc_set_timestamp(&current);
297     dsize = blosc2_schunk_decompress_chunk(schunk_sframe, nchunk, (void *) data_dest, isize);
298     blosc_set_timestamp(&last);
299     if (dsize < 0) {
300       printf("Decompression error sframe.  Error code: %d\n", dsize);
301     }
302     assert (dsize == (int)isize);
303     sframe_decompress_time += blosc_elapsed_secs(current, last);
304     // Frame
305     blosc_set_timestamp(&current);
306     dsize = blosc2_schunk_decompress_chunk(schunk_cframe, nchunk, (void *) data_dest, isize);
307     blosc_set_timestamp(&last);
308     if (dsize < 0) {
309       printf("Decompression error cframe.  Error code: %d\n", dsize);
310     }
311     assert (dsize == (int)isize);
312     cframe_decompress_time += blosc_elapsed_secs(current, last);
313   }
314 
315   printf("[Sframe Decompr] Elapsed time:\t %6.3f s.  Processed data: %.3f GB (%.3f GB/s)\n",
316          sframe_decompress_time, totalsize / GB, totalsize / (GB * sframe_decompress_time));
317   printf("[Cframe Decompr] Elapsed time:\t %6.3f s.  Processed data: %.3f GB (%.3f GB/s)\n",
318          cframe_decompress_time, totalsize / GB, totalsize / (GB * cframe_decompress_time));
319 
320   printf("Decompression successful!\n");
321 
322   printf("Successful roundtrip!\n");
323 
324   /* Free resources */
325   free(data_dest);
326   free(data);
327 
328 if (operation != NULL) {
329     if (strcmp(operation, "insert") == 0) {
330         test_insert(schunk_sframe, schunk_cframe);
331     }
332     else if (strcmp(operation, "update") == 0) {
333         test_update(schunk_sframe, schunk_cframe);
334     }
335     else if (strcmp(operation, "reorder") == 0) {
336         test_reorder(schunk_sframe, schunk_cframe);
337     }
338 }
339 
340 
341   blosc2_remove_urlpath(schunk_sframe->storage->urlpath);
342   blosc2_remove_urlpath(schunk_cframe->storage->urlpath);
343   blosc2_schunk_free(schunk_sframe);
344   blosc2_schunk_free(schunk_cframe);
345   /* Destroy the Blosc environment */
346   blosc_destroy();
347 
348 }
349 
main(int argc,char * argv[])350 int main(int argc, char* argv[]) {
351   char* operation;
352 
353   if (argc >= 5) {
354     printf("Usage: ./sframe_bench [nchunks] [insert | update | reorder] [num operations]\n");
355     exit(1);
356   }
357   else if (argc >= 2) {
358     nchunks = (int)strtol(argv[1], NULL, 10);
359   }
360   if (argc >= 3) {
361     operation = argv[2];
362   }
363   if (argc == 4) {
364     iterations = (int)strtol(argv[3], NULL, 10);
365   }
366 
367   test_create_sframe_frame(operation);
368 
369   return 0;
370 }
371