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   Example program demonstrating use of the Blosc filter from C code.
7 
8   To compile this program:
9 
10   $ gcc frame_simple.c -o frame_simple -lblosc2
11 
12   To run:
13 
14   $ ./frame_simple
15   Blosc version info: 2.0.0a6.dev ($Date:: 2018-05-18 #$)
16   Compression ratio: 381.5 MB -> 9.5 MB (40.2x)
17   Compression time: 0.705 s, 541.0 MB/s
18   Time for schunk -> frame: 0.00796 s, 47905.3 MB/s
19   Frame length in memory: 9940344 bytes
20   Frame length on disk: 9940344 bytes
21   Time for frame -> fileframe (frame_simple.b2frame): 0.0108 s, 35159.6 MB/s
22   Time for fileframe (frame_simple.b2frame) -> frame : 0.000254 s, 1.5e+06 MB/s
23   Time for frame -> schunk: 1.1e-05 s, 3.48e+07 MB/s
24   Time for fileframe -> schunk: 1.25e-05 s, 3.05e+07 MB/s
25   Successful roundtrip schunk <-> frame <-> fileframe !
26 
27  */
28 
29 #include <stdio.h>
30 #include <assert.h>
31 #include <blosc2.h>
32 
33 #define KB  1024.
34 #define MB  (1024*KB)
35 #define GB  (1024*MB)
36 
37 #define CHUNKSIZE (200 * 1000)
38 #define NCHUNKS 100
39 #define NTHREADS 4
40 
41 
main(void)42 int main(void) {
43 
44   blosc_init();
45 
46   static int32_t data[CHUNKSIZE];
47   static int32_t data_dest[CHUNKSIZE];
48   static int32_t data_dest2[CHUNKSIZE];
49   size_t isize = CHUNKSIZE * sizeof(int32_t);
50   int64_t nbytes, cbytes;
51   int i, nchunk;
52   int nchunks;
53   blosc_timestamp_t last, current;
54   double ttotal;
55 
56   printf("Blosc version info: %s (%s)\n",
57          BLOSC_VERSION_STRING, BLOSC_VERSION_DATE);
58 
59   /* Create a super-chunk container */
60   blosc2_cparams cparams = BLOSC2_CPARAMS_DEFAULTS;
61   cparams.typesize = sizeof(int32_t);
62   cparams.compcode = BLOSC_LZ4;
63   cparams.clevel = 9;
64   cparams.nthreads = NTHREADS;
65   blosc2_dparams dparams = BLOSC2_DPARAMS_DEFAULTS;
66   dparams.nthreads = NTHREADS;
67   blosc2_storage storage = {.cparams=&cparams, .dparams=&dparams};
68   blosc2_schunk* schunk = blosc2_schunk_new(&storage);
69 
70   // Add some data
71   blosc_set_timestamp(&last);
72   for (nchunk = 0; nchunk < NCHUNKS; nchunk++) {
73     for (i = 0; i < CHUNKSIZE; i++) {
74       data[i] = i * nchunk;
75     }
76     nchunks = blosc2_schunk_append_buffer(schunk, data, isize);
77     assert(nchunks == nchunk + 1);
78   }
79 
80   // Add some vlmetalayers data
81   uint32_t content_len = 10;
82   uint8_t *content = malloc(content_len);
83   for (uint32_t j = 0; j < content_len; ++j) {
84     content[j] = (uint8_t) j;
85   }
86   int umlen = blosc2_vlmeta_add(schunk, "vlmetalayer", content, content_len, NULL);
87   free(content);
88   if (umlen < 0) {
89     printf("Cannot write vlmetalayers chunk");
90     return umlen;
91   }
92 
93   /* Gather some info */
94   nbytes = schunk->nbytes;
95   cbytes = schunk->cbytes;
96   blosc_set_timestamp(&current);
97   ttotal = blosc_elapsed_secs(last, current);
98   printf("Compression ratio: %.1f MB -> %.1f MB (%.1fx)\n",
99          nbytes / MB, cbytes / MB, (1. * nbytes) / cbytes);
100   printf("Compression time: %.3g s, %.1f MB/s\n",
101          ttotal, nbytes / (ttotal * MB));
102   uint8_t* vlmetalayer;
103 
104   blosc2_vlmeta_get(schunk, "vlmetalayer", &vlmetalayer, &content_len);
105   printf("Variable-length metalayer length: %d\n", content_len);
106   for (int j = 0; j < content_len; ++j) {
107     printf("%3d", vlmetalayer[j]);
108   }
109   printf("\n");
110   free(vlmetalayer);
111 
112   // Start different conversions between schunks, frames and fileframes
113 
114   // super-chunk -> cframe (contiguous frame, or buffer)
115   blosc_set_timestamp(&last);
116   uint8_t* cframe;
117   bool cframe_needs_free;
118   int64_t frame_len = blosc2_schunk_to_buffer(schunk, &cframe, &cframe_needs_free);
119   if (frame_len < 0) {
120     return frame_len;
121   }
122   blosc_set_timestamp(&current);
123   ttotal = blosc_elapsed_secs(last, current);
124   printf("Time for schunk -> frame: %.3g s, %.1f MB/s\n",
125          ttotal, nbytes / (ttotal * MB));
126   printf("Frame length in memory: %ld bytes\n", (long)frame_len);
127 
128   // super-chunk -> fileframe (contiguous frame, on-disk)
129   remove("frame_simple.b2frame");
130   blosc_set_timestamp(&last);
131   frame_len = blosc2_schunk_to_file(schunk, "frame_simple.b2frame");
132   if (frame_len < 0) {
133     return frame_len;
134   }
135   printf("Frame length on disk: %ld bytes\n", (long)frame_len);
136   blosc_set_timestamp(&current);
137   ttotal = blosc_elapsed_secs(last, current);
138   printf("Time for frame -> fileframe (frame_simple.b2frame): %.3g s, %.1f GB/s\n",
139          ttotal, nbytes / (ttotal * GB));
140 
141   // fileframe (file) -> schunk2 (on-disk contiguous, super-chunk)
142   blosc_set_timestamp(&last);
143   blosc2_schunk* schunk2 = blosc2_schunk_open("file:///frame_simple.b2frame");
144   blosc_set_timestamp(&current);
145   ttotal = blosc_elapsed_secs(last, current);
146   printf("Time for fileframe (%s) -> frame : %.3g s, %.1f GB/s\n",
147          schunk2->storage->urlpath, ttotal, nbytes / (ttotal * GB));
148 
149   // frame1 (in-memory) -> schunk
150   blosc_set_timestamp(&last);
151   // The next creates a schunk from the in-memory frame
152   blosc2_schunk* schunk1 = blosc2_schunk_from_buffer(cframe, frame_len, false);
153   if (schunk1 == NULL) {
154     printf("Bad conversion frame1 -> schunk1!\n");
155     return -1;
156   }
157   blosc_set_timestamp(&current);
158   ttotal = blosc_elapsed_secs(last, current);
159   printf("Time for frame -> schunk: %.3g s, %.1f GB/s\n",
160          ttotal, nbytes / (ttotal * GB));
161 
162 
163   /* Retrieve and decompress the chunks from the super-chunks and compare values */
164   for (nchunk = 0; nchunk < NCHUNKS; nchunk++) {
165     int32_t dsize = blosc2_schunk_decompress_chunk(schunk1, nchunk, data_dest, isize);
166     if (dsize < 0) {
167       printf("Decompression error in schunk1.  Error code: %d\n", dsize);
168       return dsize;
169     }
170     dsize = blosc2_schunk_decompress_chunk(schunk2, nchunk, data_dest2, isize);
171     if (dsize < 0) {
172       printf("Decompression error in schunk2.  Error code: %d\n", dsize);
173       return dsize;
174     }
175     /* Check integrity of this chunk */
176     for (i = 0; i < CHUNKSIZE; i++) {
177       assert (data_dest[i] == i * nchunk);
178       assert (data_dest2[i] == i * nchunk);
179     }
180   }
181   printf("Successful roundtrip schunk <-> frame <-> fileframe !\n");
182 
183   blosc2_vlmeta_get(schunk1, "vlmetalayer", &vlmetalayer, &content_len);
184   for (int j = 0; j < content_len; ++j) {
185     printf("%3d", vlmetalayer[j]);
186   }
187   printf("\n");
188   free(vlmetalayer);
189   blosc2_vlmeta_get(schunk2, "vlmetalayer", &vlmetalayer, &content_len);
190   for (int j = 0; j < content_len; ++j) {
191     printf("%3d", vlmetalayer[j]);
192   }
193   printf("\n");
194   free(vlmetalayer);
195 
196   /* Free resources */
197   blosc2_schunk_free(schunk);
198   blosc2_schunk_free(schunk1);
199   blosc2_schunk_free(schunk2);
200   if (cframe_needs_free) {
201     free(cframe);
202   }
203   blosc_destroy();
204 
205   return 0;
206 }
207