diff --git a/src/xz/coder.c b/src/xz/coder.c index 4786e375..e6ed3e55 100644 --- a/src/xz/coder.c +++ b/src/xz/coder.c @@ -244,15 +244,13 @@ coder_set_compression_settings(void) if (!preset_default) message(V_WARNING, _("Adjusted LZMA%c dictionary size " "from %s MiB to %s MiB to not exceed " - "the memory usage limit of %s"), + "the memory usage limit of %s MiB"), filters[i].id == LZMA_FILTER_LZMA2 ? '2' : '1', uint64_to_str(orig_dict_size >> 20, 0), uint64_to_str(opt->dict_size >> 20, 1), - uint64_to_nicestr(memory_limit, - NICESTR_B, - NICESTR_MIB, - false, 2)); + uint64_to_str(round_up_to_mib( + memory_limit), 2)); } /* diff --git a/src/xz/message.c b/src/xz/message.c index ef583fa8..b5244d44 100644 --- a/src/xz/message.c +++ b/src/xz/message.c @@ -852,14 +852,35 @@ message_mem_needed(enum message_verbosity v, uint64_t memusage) if (v > verbosity) return; - // NOTE: With bad luck, the rounded values may be the same, which - // can be confusing to the user when this function is called to - // tell that the memory usage limit was too low. - message(v, _("%s of memory is required. The limit is %s."), - uint64_to_nicestr(memusage, - NICESTR_B, NICESTR_MIB, false, 0), - uint64_to_nicestr(hardware_memlimit_get(), - NICESTR_B, NICESTR_MIB, false, 1)); + // Convert memusage to MiB, rounding up to the next full MiB. + // This way the user can always use the displayed usage as + // the new memory usage limit. (If we rounded to the nearest, + // the user might need to +1 MiB to get high enough limit.) + memusage = round_up_to_mib(memusage); + + // 2^64 with thousand separators + " MiB" suffix + '\0' = 26 + 4 + 1 + char memlimitstr[32]; + + // Show the memory usage limit as MiB unless it is less than 1 MiB. + // This way it's easy to notice errors where one has typed + // --memory=123 instead of --memory=123MiB. + uint64_t memlimit = hardware_memlimit_get(); + if (memlimit < (UINT32_C(1) << 20)) { + snprintf(memlimitstr, sizeof(memlimitstr), "%s B", + uint64_to_str(memlimit, 1)); + } else { + // Round up just like with memusage. If this function is + // called for informational purporse (to just show the + // current usage and limit), we will never show that + // the usage is higher than the limit, which would give + // a false impression that the memory usage limit isn't + // properly enforced. + snprintf(memlimitstr, sizeof(memlimitstr), "%s MiB", + uint64_to_str(round_up_to_mib(memlimit), 1)); + } + + message(v, _("%s MiB of memory is required. The limit is %s."), + uint64_to_str(memusage, 0), memlimitstr); return; } diff --git a/src/xz/util.c b/src/xz/util.c index 784f6d30..dd95fa7a 100644 --- a/src/xz/util.c +++ b/src/xz/util.c @@ -119,6 +119,13 @@ error: } +extern uint64_t +round_up_to_mib(uint64_t n) +{ + return (n >> 20) + ((n & ((UINT32_C(1) << 20) - 1)) != 0); +} + + extern const char * uint64_to_str(uint64_t value, uint32_t slot) { diff --git a/src/xz/util.h b/src/xz/util.h index 67bf3075..2e08b4a8 100644 --- a/src/xz/util.h +++ b/src/xz/util.h @@ -41,6 +41,12 @@ extern uint64_t str_to_uint64(const char *name, const char *value, uint64_t min, uint64_t max); +/// \brief Round an integer up to the next full MiB and convert to MiB +/// +/// This is used when printing memory usage and limit. +extern uint64_t round_up_to_mib(uint64_t n); + + /// \brief Convert uint64_t to a string /// /// Convert the given value to a string with locale-specific thousand