aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/common/memory_usage.c
blob: b6f279576f888b48d30a8cabdfaee55c7c64f6b3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
///////////////////////////////////////////////////////////////////////////////
//
/// \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);
}