| /////////////////////////////////////////////////////////////////////////////// |
| // |
| /// \file memory_usage.c |
| /// \brief Calculate rough amount of memory required by filters |
| // |
| // Copyright (C) 2007 Lasse Collin |
| // |
| // This library is free software; you can redistribute it and/or |
| // modify it under the terms of the GNU Lesser General Public |
| // License as published by the Free Software Foundation; either |
| // version 2.1 of the License, or (at your option) any later version. |
| // |
| // This library is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| // Lesser General Public License for more details. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #include "common.h" |
| #include "lz_encoder.h" |
| #include "lzma_literal.h" |
| |
| |
| static uint64_t |
| get_usage(const lzma_options_filter *filter, bool is_encoder) |
| { |
| uint64_t ret; |
| |
| switch (filter->id) { |
| case LZMA_FILTER_COPY: |
| case LZMA_FILTER_X86: |
| case LZMA_FILTER_POWERPC: |
| case LZMA_FILTER_IA64: |
| case LZMA_FILTER_ARM: |
| case LZMA_FILTER_ARMTHUMB: |
| case LZMA_FILTER_SPARC: |
| case LZMA_FILTER_DELTA: |
| // These don't require any significant amount of memory. |
| ret = 0; |
| break; |
| |
| case LZMA_FILTER_SUBBLOCK: |
| if (is_encoder) { |
| const lzma_options_subblock *options = filter->options; |
| ret = options->subblock_data_size; |
| } else { |
| ret = 0; |
| } |
| break; |
| |
| #ifdef HAVE_FILTER_LZMA |
| case LZMA_FILTER_LZMA: { |
| const lzma_options_lzma *options = filter->options; |
| |
| // Literal coder - this can be signficant if both values are |
| // big, or if sizeof(probability) is big. |
| ret = literal_states(options->literal_context_bits, |
| options->literal_pos_bits) * LIT_SIZE |
| * sizeof(probability); |
| |
| // Dictionary base size |
| ret += options->dictionary_size; |
| |
| if (is_encoder) { |
| # ifdef HAVE_ENCODER |
| // This is rough, but should be accurate enough |
| // in practice. |
| ret += options->dictionary_size / 2; |
| |
| uint32_t dummy1; |
| uint32_t dummy2; |
| uint32_t num_items; |
| if (lzma_lz_encoder_hash_properties( |
| options->match_finder, |
| options->dictionary_size, |
| &dummy1, &dummy2, &num_items)) |
| return UINT64_MAX; |
| |
| ret += (uint64_t)(num_items) * sizeof(uint32_t); |
| # else |
| return UINT64_MAX; |
| # endif |
| } |
| |
| break; |
| } |
| #endif |
| |
| default: |
| return UINT64_MAX; |
| } |
| |
| return ret; |
| } |
| |
| |
| extern LZMA_API uint32_t |
| lzma_memory_usage(const lzma_options_filter *filters, lzma_bool is_encoder) |
| { |
| uint64_t usage = 0; |
| |
| for (size_t i = 0; filters[i].id != UINT64_MAX; ++i) { |
| const uint64_t ret = get_usage(filters + i, is_encoder); |
| if (ret == UINT64_MAX) |
| return UINT32_MAX; |
| |
| usage += ret; |
| } |
| |
| // Convert to mebibytes with rounding. |
| return usage / (1024 * 1024) + (usage % (1024 * 1024) >= 512 ? 1 : 0); |
| } |