xz: Changes to --memlimit-compress and --no-adjust.

In single-threaded mode, --memlimit-compress can make xz scale down
the LZMA2 dictionary size to meet the memory usage limit. This
obviously affects the compressed output. However, if xz was in
threaded mode, --memlimit-compress could make xz reduce the number
of threads but it wouldn't make xz switch from multithreaded mode
to single-threaded mode or scale down the LZMA2 dictionary size.
This seemed illogical and there was even a "FIXME?" about it.

Now --memlimit-compress can make xz switch to single-threaded
mode if one thread in multithreaded mode uses too much memory.
If memory usage is still too high, then the LZMA2 dictionary
size can be scaled down too.

The option --no-adjust was also changed so that it no longer
prevents xz from scaling down the number of threads as that
doesn't affect compressed output (only performance). After
this commit --no-adjust only prevents adjustments that affect
compressed output, that is, with --no-adjust xz won't switch
from multithreaded mode to single-threaded mode and won't
scale down the LZMA2 dictionary size.

The man page wasn't updated yet.
This commit is contained in:
Lasse Collin 2022-04-14 12:38:00 +03:00
parent cad299008c
commit 898faa9728
1 changed files with 43 additions and 20 deletions

View File

@ -269,10 +269,9 @@ coder_set_compression_settings(void)
if (memory_usage <= memory_limit) if (memory_usage <= memory_limit)
return; return;
// If --no-adjust was used or we didn't find LZMA1 or // With --format=raw settings are never adjusted to meet
// LZMA2 as the last filter, give an error immediately. // the memory usage limit.
// --format=raw implies --no-adjust. if (opt_format == FORMAT_RAW)
if (!opt_auto_adjust || opt_format == FORMAT_RAW)
memlimit_too_small(memory_usage); memlimit_too_small(memory_usage);
assert(opt_mode == MODE_COMPRESS); assert(opt_mode == MODE_COMPRESS);
@ -282,34 +281,58 @@ coder_set_compression_settings(void)
if (opt_format == FORMAT_XZ && mt_options.threads > 1) { if (opt_format == FORMAT_XZ && mt_options.threads > 1) {
// Try to reduce the number of threads before // Try to reduce the number of threads before
// adjusting the compression settings down. // adjusting the compression settings down.
do { while (mt_options.threads > 1) {
// FIXME? The real single-threaded mode has // Reduce the number of threads by one and check
// lower memory usage, but it's not comparable // the memory usage.
// because it doesn't write the size info --mt_options.threads;
// into Block Headers.
if (--mt_options.threads == 0)
memlimit_too_small(memory_usage);
memory_usage = lzma_stream_encoder_mt_memusage( memory_usage = lzma_stream_encoder_mt_memusage(
&mt_options); &mt_options);
if (memory_usage == UINT64_MAX) if (memory_usage == UINT64_MAX)
message_bug(); message_bug();
} while (memory_usage > memory_limit); if (memory_usage <= memory_limit) {
// The memory usage is now low enough.
message(V_WARNING, _("Adjusted the number of threads " message(V_WARNING, _("Reduced the number of "
"from %s to %s to not exceed " "threads from %s to %s to not exceed "
"the memory usage limit of %s MiB"), "the memory usage limit of %s MiB"),
uint64_to_str(hardware_threads_get(), 0), uint64_to_str(
hardware_threads_get(), 0),
uint64_to_str(mt_options.threads, 1), uint64_to_str(mt_options.threads, 1),
uint64_to_str(round_up_to_mib( uint64_to_str(round_up_to_mib(
memory_limit), 2)); memory_limit), 2));
return;
}
}
// If --no-adjust was used, we cannot drop to single-threaded
// mode since it produces different compressed output.
//
// NOTE: In xz 5.2.x, --no-adjust also prevented reducing
// the number of threads. This changed in 5.3.3alpha.
if (!opt_auto_adjust)
memlimit_too_small(memory_usage);
// Switch to single-threaded mode. It uses
// less memory than using one thread in
// the multithreaded mode but the output
// is also different.
hardware_threads_set(1);
memory_usage = lzma_raw_encoder_memusage(filters);
message(V_WARNING, _("Switching to single-threaded mode "
"to not exceed the memory usage limit of %s MiB"),
uint64_to_str(round_up_to_mib(memory_limit), 0));
} }
# endif # endif
if (memory_usage <= memory_limit) if (memory_usage <= memory_limit)
return; return;
// Don't adjust LZMA2 or LZMA1 dictionary size if --no-adjust
// was specified as that would change the compressed output.
if (!opt_auto_adjust)
memlimit_too_small(memory_usage);
// Look for the last filter if it is LZMA2 or LZMA1, so we can make // Look for the last filter if it is LZMA2 or LZMA1, so we can make
// it use less RAM. With other filters we don't know what to do. // it use less RAM. With other filters we don't know what to do.
size_t i = 0; size_t i = 0;