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   Simple benchmark for frame creation.
7 
8   To run:
9 
10   $ ./create_frame
11 
12    ***  Creating unitialized   ***
13    ***  Using fill method!   ***
14 
15 *** Creating *contiguous* super-chunk for *blosclz*
16 Compression ratio: 186.26 GB -> 0.17 KB (1162790697.7x)
17 Compression time: 8.5e-06 s, 21399.9 TB/s
18 Decompression time: 0.0628 s, 2965.1 GB/s
19 
20 *** Creating *sparse* super-chunk for *blosclz*
21 Compression ratio: 186.26 GB -> 3906.29 KB (49999.5x)
22 Compression time: 0.00294 s, 61.8 TB/s
23 Decompression time: 0.00424 s, 43959.2 GB/s
24 
25 *** Creating *contiguous* super-chunk for *lz4*
26 Compression ratio: 186.26 GB -> 0.17 KB (1162790697.7x)
27 Compression time: 4.71e-06 s, 38636.1 TB/s
28 Decompression time: 0.0701 s, 2656.7 GB/s
29 
30 *** Creating *sparse* super-chunk for *lz4*
31 Compression ratio: 186.26 GB -> 3906.29 KB (49999.5x)
32 Compression time: 0.00311 s, 58.5 TB/s
33 Decompression time: 0.0101 s, 18516.4 GB/s
34 
35 Process finished with exit code 0
36 
37  */
38 
39 #include <stdio.h>
40 #include <blosc2.h>
41 
42 #define KB  (1024.)
43 #define MB  (1024 * KB)
44 #define GB  (1024 * MB)
45 #define TB  (1024 * GB)
46 
47 #define CHUNKSHAPE (500 * 1000)
48 #define NCHUNKS 100000
49 #define NTHREADS 1  // curiously, using 1 single thread is better for the uninitialized values
50 
51 // For exercising the optimized chunk creators (un)comment the lines below as you please
52 //#define CREATE_ZEROS
53 #define CREATE_FILL
54 //#define CREATE_LOOP
55 
create_cframe(const char * compname,bool contiguous)56 int create_cframe(const char* compname, bool contiguous) {
57   int32_t isize = CHUNKSHAPE * sizeof(int32_t);
58   int32_t* data = malloc(isize);
59   int32_t* data_dest = malloc(isize);
60   int32_t* data_dest2 = malloc(isize);
61   int64_t nbytes, cbytes;
62   int nchunk;
63   blosc_timestamp_t last, current;
64   double ttotal;
65   int compcode = blosc_compname_to_compcode(compname);
66   printf("\n*** Creating *%s* super-chunk for *%s*\n",
67          contiguous ? "contiguous" : "sparse", compname);
68 
69   /* Create a super-chunk container */
70   blosc2_cparams cparams = BLOSC2_CPARAMS_DEFAULTS;
71   cparams.typesize = sizeof(int32_t);
72   cparams.compcode = compcode;
73   cparams.clevel = 9;
74   cparams.nthreads = NTHREADS;
75   //cparams.blocksize = 1024;
76   blosc2_dparams dparams = BLOSC2_DPARAMS_DEFAULTS;
77   dparams.nthreads = NTHREADS;
78   char filename[64];
79   sprintf(filename, "frame_simple-%s.b2frame", compname);
80   blosc2_storage storage = {.cparams=&cparams, .dparams=&dparams,
81                             .urlpath=NULL, .contiguous=contiguous};
82   blosc2_schunk* schunk = blosc2_schunk_new(&storage);
83 
84 #ifdef CREATE_ZEROS
85   // Precompute chunk of zeros
86   int ret = blosc2_chunk_zeros(cparams, isize, data_dest, isize);
87 #else
88   int ret = blosc2_chunk_uninit(cparams, isize, data_dest, isize);
89 #endif
90   if (ret < 0) {
91     printf("Creation error in special chunk.  Error code: %d\n", ret);
92     return ret;
93   }
94 
95   // Add some data
96   blosc_set_timestamp(&last);
97 
98   int64_t nitems;
99 #ifdef CREATE_FILL
100   // Make nitems a non-divisible number of CHUNKSHAPE
101   nitems = (int64_t)NCHUNKS * CHUNKSHAPE + 1;
102 #ifdef CREATE_ZEROS
103   // Precompute chunk of zeros
104   int special_value = BLOSC2_SPECIAL_ZERO;
105 #else
106   int special_value = BLOSC2_SPECIAL_UNINIT;
107 #endif
108   int rc = blosc2_schunk_fill_special(schunk, nitems, special_value, isize);
109   if (rc < 0) {
110     printf("Error in fill special.  Error code: %d\n", rc);
111     return rc;
112   }
113 #else
114   // In these methods, nitems can only be an actual multiple of CHUNKSHAPE
115   nitems = (int64_t)NCHUNKS * CHUNKSHAPE;
116   for (nchunk = 0; nchunk < NCHUNKS; nchunk++) {
117 #ifdef CREATE_LOOP
118     int nchunks = blosc2_schunk_append_chunk(schunk, (uint8_t *) data_dest, true);
119     if (nchunks != nchunk + 1) {
120       printf("Compression error in append chunk.  Error code: %d\n", nchunks);
121       return nchunk;
122     }
123 #else
124     for (int i = 0; i < CHUNKSHAPE; i++) {
125       // Different data patterns
126       // data[i] = i * nchunk;
127       // data[i] = nchunk;
128       data[i] = 0;
129     }
130     int nchunks = blosc2_schunk_append_buffer(schunk, data, isize);
131     if (nchunks != nchunk + 1) {
132       printf("Compression error appending in schunk.  Error code: %d\n", nchunks);
133       return nchunk;
134     }
135 #endif
136   }
137 #endif
138   blosc_set_timestamp(&current);
139 
140   /* Gather some info */
141   nbytes = schunk->nbytes;
142   cbytes = blosc2_schunk_frame_len(schunk);
143   ttotal = blosc_elapsed_secs(last, current);
144   printf("Compression ratio: %.2f GB -> %.2f KB (%4.1fx)\n",
145          (double)nbytes / GB, (double)cbytes / KB, (double)nbytes / (double)cbytes);
146   printf("Compression time: %.3g s, %.1f TB/s\n",
147          ttotal, (double)nbytes / (ttotal * TB));
148 
149   /* Retrieve and decompress the chunks from the super-chunks and compare values */
150   blosc_set_timestamp(&last);
151   int32_t leftover_bytes = (int32_t)((nitems % CHUNKSHAPE) * sizeof(int32_t));
152   int32_t nchunks = leftover_bytes ? NCHUNKS + 1 : NCHUNKS;
153   for (nchunk = 0; nchunk < nchunks; nchunk++) {
154     int32_t dsize = blosc2_schunk_decompress_chunk(schunk, nchunk, data_dest, isize);
155     if (dsize < 0) {
156       printf("Decompression error in schunk.  Error code: %d\n", dsize);
157       return dsize;
158     }
159     if ((nchunk == nchunks - 1) && (leftover_bytes > 0)) {
160       if (dsize != leftover_bytes) {
161         printf("Wrong size for last chunk.  It is %d and should be: %d\n", dsize, leftover_bytes);
162         return dsize;
163       }
164     }
165   }
166   blosc_set_timestamp(&current);
167   ttotal = blosc_elapsed_secs(last, current);
168   printf("Decompression time: %.3g s, %.1f GB/s\n",
169          ttotal, (double)nbytes / (ttotal * GB));
170 
171   /* Free resources */
172   blosc2_schunk_free(schunk);
173   free(data);
174   free(data_dest);
175   free(data_dest2);
176 
177   return 0;
178 }
179 
180 
main(void)181 int main(void) {
182 #ifdef CREATE_ZEROS
183   printf("\n   ***  Creating zeros   ***\n");
184 #else
185   printf("\n   ***  Creating unitialized   ***\n");
186 #endif
187 #ifdef CREATE_FILL
188   printf("   ***  Using fill method!   ***\n");
189 #elif defined(CREATE_LOOP)
190   printf("   ***  Using loop method!   ***\n");
191 #else
192   printf("   ***  Using not optimized method!   ***\n");
193 #endif
194 
195   create_cframe("blosclz", true);
196   create_cframe("blosclz", false);
197   create_cframe("lz4", true);
198   create_cframe("lz4", false);
199 }
200