xref: /netbsd-src/external/bsd/zstd/dist/contrib/linux-kernel/test/test.c (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
1*3117ece4Schristos /*
2*3117ece4Schristos  * Copyright (c) Meta Platforms, Inc. and affiliates.
3*3117ece4Schristos  * All rights reserved.
4*3117ece4Schristos  *
5*3117ece4Schristos  * This source code is licensed under both the BSD-style license (found in the
6*3117ece4Schristos  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*3117ece4Schristos  * in the COPYING file in the root directory of this source tree).
8*3117ece4Schristos  * You may select, at your option, one of the above-listed licenses.
9*3117ece4Schristos  */
10*3117ece4Schristos #include <stddef.h>
11*3117ece4Schristos #include <stdio.h>
12*3117ece4Schristos #include <stdlib.h>
13*3117ece4Schristos #include <string.h>
14*3117ece4Schristos 
15*3117ece4Schristos #include <linux/zstd.h>
16*3117ece4Schristos 
17*3117ece4Schristos #define CONTROL(x)                                                             \
18*3117ece4Schristos   do {                                                                         \
19*3117ece4Schristos     if (!(x)) {                                                                \
20*3117ece4Schristos       fprintf(stderr, "%s:%u: %s failed!\n", __FUNCTION__, __LINE__, #x);      \
21*3117ece4Schristos       abort();                                                                 \
22*3117ece4Schristos     }                                                                          \
23*3117ece4Schristos   } while (0)
24*3117ece4Schristos 
25*3117ece4Schristos typedef struct {
26*3117ece4Schristos   char *data;
27*3117ece4Schristos   char *data2;
28*3117ece4Schristos   size_t dataSize;
29*3117ece4Schristos   char *comp;
30*3117ece4Schristos   size_t compSize;
31*3117ece4Schristos } test_data_t;
32*3117ece4Schristos 
33*3117ece4Schristos static test_data_t create_test_data(void) {
34*3117ece4Schristos   test_data_t data;
35*3117ece4Schristos   data.dataSize = 128 * 1024;
36*3117ece4Schristos   data.data = (char*)malloc(data.dataSize);
37*3117ece4Schristos   CONTROL(data.data != NULL);
38*3117ece4Schristos   data.data2 = (char*)malloc(data.dataSize);
39*3117ece4Schristos   CONTROL(data.data2 != NULL);
40*3117ece4Schristos   data.compSize = zstd_compress_bound(data.dataSize);
41*3117ece4Schristos   data.comp = (char*)malloc(data.compSize);
42*3117ece4Schristos   CONTROL(data.comp != NULL);
43*3117ece4Schristos   memset(data.data, 0, data.dataSize);
44*3117ece4Schristos   return data;
45*3117ece4Schristos }
46*3117ece4Schristos 
47*3117ece4Schristos static void free_test_data(test_data_t const *data) {
48*3117ece4Schristos   free(data->data);
49*3117ece4Schristos   free(data->data2);
50*3117ece4Schristos   free(data->comp);
51*3117ece4Schristos }
52*3117ece4Schristos 
53*3117ece4Schristos #define MIN(a, b) ((a) < (b) ? (a) : (b))
54*3117ece4Schristos #define MAX(a, b) ((a) > (b) ? (a) : (b))
55*3117ece4Schristos 
56*3117ece4Schristos static void test_btrfs(test_data_t const *data) {
57*3117ece4Schristos   size_t const size = MIN(data->dataSize, 128 * 1024);
58*3117ece4Schristos   fprintf(stderr, "testing btrfs use cases... ");
59*3117ece4Schristos   for (int level = -1; level < 16; ++level) {
60*3117ece4Schristos     zstd_parameters params = zstd_get_params(level, size);
61*3117ece4Schristos     size_t const workspaceSize =
62*3117ece4Schristos         MAX(zstd_cstream_workspace_bound(&params.cParams),
63*3117ece4Schristos             zstd_dstream_workspace_bound(size));
64*3117ece4Schristos     void *workspace = malloc(workspaceSize);
65*3117ece4Schristos 
66*3117ece4Schristos     char const *ip = data->data;
67*3117ece4Schristos     char const *iend = ip + size;
68*3117ece4Schristos     char *op = data->comp;
69*3117ece4Schristos     char *oend = op + data->compSize;
70*3117ece4Schristos 
71*3117ece4Schristos     CONTROL(params.cParams.windowLog <= 17);
72*3117ece4Schristos     CONTROL(workspace != NULL);
73*3117ece4Schristos     {
74*3117ece4Schristos       zstd_cstream *cctx = zstd_init_cstream(&params, size, workspace, workspaceSize);
75*3117ece4Schristos       zstd_out_buffer out = {NULL, 0, 0};
76*3117ece4Schristos       zstd_in_buffer in = {NULL, 0, 0};
77*3117ece4Schristos       CONTROL(cctx != NULL);
78*3117ece4Schristos       for (;;) {
79*3117ece4Schristos         if (in.pos == in.size) {
80*3117ece4Schristos           in.src = ip;
81*3117ece4Schristos           in.size = MIN(4096, iend - ip);
82*3117ece4Schristos           in.pos = 0;
83*3117ece4Schristos           ip += in.size;
84*3117ece4Schristos         }
85*3117ece4Schristos 
86*3117ece4Schristos         if (out.pos == out.size) {
87*3117ece4Schristos           out.dst = op;
88*3117ece4Schristos           out.size = MIN(4096, oend - op);
89*3117ece4Schristos           out.pos = 0;
90*3117ece4Schristos           op += out.size;
91*3117ece4Schristos         }
92*3117ece4Schristos 
93*3117ece4Schristos         if (ip != iend || in.pos < in.size) {
94*3117ece4Schristos           CONTROL(!zstd_is_error(zstd_compress_stream(cctx, &out, &in)));
95*3117ece4Schristos         } else {
96*3117ece4Schristos           size_t const ret = zstd_end_stream(cctx, &out);
97*3117ece4Schristos           CONTROL(!zstd_is_error(ret));
98*3117ece4Schristos           if (ret == 0) {
99*3117ece4Schristos             break;
100*3117ece4Schristos           }
101*3117ece4Schristos         }
102*3117ece4Schristos       }
103*3117ece4Schristos       op += out.pos;
104*3117ece4Schristos     }
105*3117ece4Schristos 
106*3117ece4Schristos     ip = data->comp;
107*3117ece4Schristos     iend = op;
108*3117ece4Schristos     op = data->data2;
109*3117ece4Schristos     oend = op + size;
110*3117ece4Schristos     {
111*3117ece4Schristos       zstd_dstream *dctx = zstd_init_dstream(1ULL << params.cParams.windowLog, workspace, workspaceSize);
112*3117ece4Schristos       zstd_out_buffer out = {NULL, 0, 0};
113*3117ece4Schristos       zstd_in_buffer in = {NULL, 0, 0};
114*3117ece4Schristos       CONTROL(dctx != NULL);
115*3117ece4Schristos       for (;;) {
116*3117ece4Schristos         if (in.pos == in.size) {
117*3117ece4Schristos           in.src = ip;
118*3117ece4Schristos           in.size = MIN(4096, iend - ip);
119*3117ece4Schristos           in.pos = 0;
120*3117ece4Schristos           ip += in.size;
121*3117ece4Schristos         }
122*3117ece4Schristos 
123*3117ece4Schristos         if (out.pos == out.size) {
124*3117ece4Schristos           out.dst = op;
125*3117ece4Schristos           out.size = MIN(4096, oend - op);
126*3117ece4Schristos           out.pos = 0;
127*3117ece4Schristos           op += out.size;
128*3117ece4Schristos         }
129*3117ece4Schristos         {
130*3117ece4Schristos           size_t const ret = zstd_decompress_stream(dctx, &out, &in);
131*3117ece4Schristos           CONTROL(!zstd_is_error(ret));
132*3117ece4Schristos           if (ret == 0) {
133*3117ece4Schristos             break;
134*3117ece4Schristos           }
135*3117ece4Schristos         }
136*3117ece4Schristos       }
137*3117ece4Schristos     }
138*3117ece4Schristos     CONTROL((size_t)(op - data->data2) == data->dataSize);
139*3117ece4Schristos     CONTROL(!memcmp(data->data, data->data2, data->dataSize));
140*3117ece4Schristos     free(workspace);
141*3117ece4Schristos   }
142*3117ece4Schristos   fprintf(stderr, "Ok\n");
143*3117ece4Schristos }
144*3117ece4Schristos 
145*3117ece4Schristos static void test_decompress_unzstd(test_data_t const *data) {
146*3117ece4Schristos     size_t cSize;
147*3117ece4Schristos     fprintf(stderr, "Testing decompress unzstd... ");
148*3117ece4Schristos     {
149*3117ece4Schristos         zstd_parameters params = zstd_get_params(19, 0);
150*3117ece4Schristos         size_t const wkspSize = zstd_cctx_workspace_bound(&params.cParams);
151*3117ece4Schristos         void* wksp = malloc(wkspSize);
152*3117ece4Schristos         zstd_cctx* cctx = zstd_init_cctx(wksp, wkspSize);
153*3117ece4Schristos         CONTROL(wksp != NULL);
154*3117ece4Schristos         CONTROL(cctx != NULL);
155*3117ece4Schristos         cSize = zstd_compress_cctx(cctx, data->comp, data->compSize, data->data, data->dataSize, &params);
156*3117ece4Schristos         CONTROL(!zstd_is_error(cSize));
157*3117ece4Schristos         free(wksp);
158*3117ece4Schristos     }
159*3117ece4Schristos     {
160*3117ece4Schristos         size_t const wkspSize = zstd_dctx_workspace_bound();
161*3117ece4Schristos         void* wksp = malloc(wkspSize);
162*3117ece4Schristos         zstd_dctx* dctx = zstd_init_dctx(wksp, wkspSize);
163*3117ece4Schristos         CONTROL(wksp != NULL);
164*3117ece4Schristos         CONTROL(dctx != NULL);
165*3117ece4Schristos         {
166*3117ece4Schristos           size_t const dSize = zstd_decompress_dctx(dctx, data->data2, data->dataSize, data->comp, cSize);
167*3117ece4Schristos           CONTROL(!zstd_is_error(dSize));
168*3117ece4Schristos           CONTROL(dSize == data->dataSize);
169*3117ece4Schristos         }
170*3117ece4Schristos         CONTROL(!memcmp(data->data, data->data2, data->dataSize));
171*3117ece4Schristos         free(wksp);
172*3117ece4Schristos     }
173*3117ece4Schristos     fprintf(stderr, "Ok\n");
174*3117ece4Schristos }
175*3117ece4Schristos 
176*3117ece4Schristos static void test_f2fs(void) {
177*3117ece4Schristos   fprintf(stderr, "testing f2fs uses... ");
178*3117ece4Schristos   CONTROL(zstd_min_clevel() < 0);
179*3117ece4Schristos   CONTROL(zstd_max_clevel() == 22);
180*3117ece4Schristos   fprintf(stderr, "Ok\n");
181*3117ece4Schristos }
182*3117ece4Schristos 
183*3117ece4Schristos static char *g_stack = NULL;
184*3117ece4Schristos 
185*3117ece4Schristos static void __attribute__((noinline)) use(void *x) {
186*3117ece4Schristos   asm volatile("" : "+r"(x));
187*3117ece4Schristos }
188*3117ece4Schristos 
189*3117ece4Schristos static void __attribute__((noinline)) fill_stack(void) {
190*3117ece4Schristos   memset(g_stack, 0x33, 8192);
191*3117ece4Schristos }
192*3117ece4Schristos 
193*3117ece4Schristos static void __attribute__((noinline)) set_stack(void) {
194*3117ece4Schristos 
195*3117ece4Schristos   char stack[8192];
196*3117ece4Schristos   g_stack = stack;
197*3117ece4Schristos   use(g_stack);
198*3117ece4Schristos }
199*3117ece4Schristos 
200*3117ece4Schristos static void __attribute__((noinline)) check_stack(void) {
201*3117ece4Schristos   size_t cleanStack = 0;
202*3117ece4Schristos   while (cleanStack < 8192 && g_stack[cleanStack] == 0x33) {
203*3117ece4Schristos     ++cleanStack;
204*3117ece4Schristos   }
205*3117ece4Schristos   {
206*3117ece4Schristos     size_t const stackSize = 8192 - cleanStack;
207*3117ece4Schristos     fprintf(stderr, "Maximum stack size: %zu\n", stackSize);
208*3117ece4Schristos     CONTROL(stackSize <= 2048 + 512);
209*3117ece4Schristos   }
210*3117ece4Schristos }
211*3117ece4Schristos 
212*3117ece4Schristos static void test_stack_usage(test_data_t const *data) {
213*3117ece4Schristos   set_stack();
214*3117ece4Schristos   fill_stack();
215*3117ece4Schristos   test_f2fs();
216*3117ece4Schristos   test_btrfs(data);
217*3117ece4Schristos   test_decompress_unzstd(data);
218*3117ece4Schristos   check_stack();
219*3117ece4Schristos }
220*3117ece4Schristos 
221*3117ece4Schristos int main(void) {
222*3117ece4Schristos   test_data_t data = create_test_data();
223*3117ece4Schristos   test_f2fs();
224*3117ece4Schristos   test_btrfs(&data);
225*3117ece4Schristos   test_decompress_unzstd(&data);
226*3117ece4Schristos   test_stack_usage(&data);
227*3117ece4Schristos   free_test_data(&data);
228*3117ece4Schristos   return 0;
229*3117ece4Schristos }
230