1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file 04_compress_easy_mt.c
4 /// \brief Compress in multi-call mode using LZMA2 in multi-threaded mode
6 /// Usage: ./04_compress_easy_mt < INFILE > OUTFILE
8 /// Example: ./04_compress_easy_mt < foo > foo.xz
10 // Author: Lasse Collin
12 // This file has been put into the public domain.
13 // You can do whatever you want with this file.
15 ///////////////////////////////////////////////////////////////////////////////
26 init_encoder(lzma_stream
*strm
)
28 // The threaded encoder takes the options as pointer to
29 // a lzma_mt structure.
31 // No flags are needed.
34 // Let liblzma determine a sane block size.
37 // Use no timeout for lzma_code() calls by setting timeout
38 // to zero. That is, sometimes lzma_code() might block for
39 // a long time (from several seconds to even minutes).
40 // If this is not OK, for example due to progress indicator
41 // needing updates, specify a timeout in milliseconds here.
42 // See the documentation of lzma_mt in lzma/container.h for
43 // information how to choose a reasonable timeout.
46 // Use the default preset (6) for LZMA2.
47 // To use a preset, filters must be set to NULL.
48 .preset
= LZMA_PRESET_DEFAULT
,
51 // Use CRC64 for integrity checking. See also
52 // 01_compress_easy.c about choosing the integrity check.
53 .check
= LZMA_CHECK_CRC64
,
56 // Detect how many threads the CPU supports.
57 mt
.threads
= lzma_cputhreads();
59 // If the number of CPU cores/threads cannot be detected,
60 // use one thread. Note that this isn't the same as the normal
61 // single-threaded mode as this will still split the data into
62 // blocks and use more RAM than the normal single-threaded mode.
63 // You may want to consider using lzma_easy_encoder() or
64 // lzma_stream_encoder() instead of lzma_stream_encoder_mt() if
65 // lzma_cputhreads() returns 0 or 1.
69 // If the number of CPU cores/threads exceeds threads_max,
70 // limit the number of threads to keep memory usage lower.
71 // The number 8 is arbitrarily chosen and may be too low or
72 // high depending on the compression preset and the computer
75 // FIXME: A better way could be to check the amount of RAM
76 // (or available RAM) and use lzma_stream_encoder_mt_memusage()
77 // to determine if the number of threads should be reduced.
78 const uint32_t threads_max
= 8;
79 if (mt
.threads
> threads_max
)
80 mt
.threads
= threads_max
;
82 // Initialize the threaded encoder.
83 lzma_ret ret
= lzma_stream_encoder_mt(strm
, &mt
);
91 msg
= "Memory allocation failed";
94 case LZMA_OPTIONS_ERROR
:
95 // We are no longer using a plain preset so this error
96 // message has been edited accordingly compared to
97 // 01_compress_easy.c.
98 msg
= "Specified filter chain is not supported";
101 case LZMA_UNSUPPORTED_CHECK
:
102 msg
= "Specified integrity check is not supported";
106 msg
= "Unknown error, possibly a bug";
110 fprintf(stderr
, "Error initializing the encoder: %s (error code %u)\n",
116 // This function is identical to the one in 01_compress_easy.c.
118 compress(lzma_stream
*strm
, FILE *infile
, FILE *outfile
)
120 lzma_action action
= LZMA_RUN
;
122 uint8_t inbuf
[BUFSIZ
];
123 uint8_t outbuf
[BUFSIZ
];
125 strm
->next_in
= NULL
;
127 strm
->next_out
= outbuf
;
128 strm
->avail_out
= sizeof(outbuf
);
131 if (strm
->avail_in
== 0 && !feof(infile
)) {
132 strm
->next_in
= inbuf
;
133 strm
->avail_in
= fread(inbuf
, 1, sizeof(inbuf
),
136 if (ferror(infile
)) {
137 fprintf(stderr
, "Read error: %s\n",
143 action
= LZMA_FINISH
;
146 lzma_ret ret
= lzma_code(strm
, action
);
148 if (strm
->avail_out
== 0 || ret
== LZMA_STREAM_END
) {
149 size_t write_size
= sizeof(outbuf
) - strm
->avail_out
;
151 if (fwrite(outbuf
, 1, write_size
, outfile
)
153 fprintf(stderr
, "Write error: %s\n",
158 strm
->next_out
= outbuf
;
159 strm
->avail_out
= sizeof(outbuf
);
162 if (ret
!= LZMA_OK
) {
163 if (ret
== LZMA_STREAM_END
)
169 msg
= "Memory allocation failed";
172 case LZMA_DATA_ERROR
:
173 msg
= "File size limits exceeded";
177 msg
= "Unknown error, possibly a bug";
181 fprintf(stderr
, "Encoder error: %s (error code %u)\n",
192 lzma_stream strm
= LZMA_STREAM_INIT
;
194 bool success
= init_encoder(&strm
);
196 success
= compress(&strm
, stdin
, stdout
);
200 if (fclose(stdout
)) {
201 fprintf(stderr
, "Write error: %s\n", strerror(errno
));
205 return success
? EXIT_SUCCESS
: EXIT_FAILURE
;