aboutsummaryrefslogtreecommitdiff
path: root/src/xz/hardware.c
blob: a4733c27e1180e1eb1d2e0070e0e94a51e2ce2a3 (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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
///////////////////////////////////////////////////////////////////////////////
//
/// \file       hardware.c
/// \brief      Detection of available hardware resources
//
//  Author:     Lasse Collin
//
//  This file has been put into the public domain.
//  You can do whatever you want with this file.
//
///////////////////////////////////////////////////////////////////////////////

#include "private.h"
#include "tuklib_cpucores.h"


/// Maximum number of free *coder* threads. This can be set with
/// the --threads=NUM command line option.
static uint32_t threadlimit;

/// Memory usage limit for compression
static uint64_t memlimit_compress;

/// Memory usage limit for decompression
static uint64_t memlimit_decompress;

/// Total amount of physical RAM
static uint64_t total_ram;


extern void
hardware_threadlimit_set(uint32_t new_threadlimit)
{
	if (new_threadlimit == 0) {
		// The default is the number of available CPU cores.
		threadlimit = tuklib_cpucores();
		if (threadlimit == 0)
			threadlimit = 1;
	} else {
		threadlimit = new_threadlimit;
	}

	return;
}


extern uint32_t
hardware_threadlimit_get(void)
{
	return threadlimit;
}


extern void
hardware_memlimit_set(uint64_t new_memlimit,
		bool set_compress, bool set_decompress, bool is_percentage)
{
	if (is_percentage) {
		assert(new_memlimit > 0);
		assert(new_memlimit <= 100);
		new_memlimit = (uint32_t)new_memlimit * total_ram / 100;
	}

	if (set_compress)
		memlimit_compress = new_memlimit;

	if (set_decompress)
		memlimit_decompress = new_memlimit;

	return;
}


extern uint64_t
hardware_memlimit_get(enum operation_mode mode)
{
	// Zero is a special value that indicates the default. Currently
	// the default simply disables the limit. Once there is threading
	// support, this might be a little more complex, because there will
	// probably be a special case where a user asks for "optimal" number
	// of threads instead of a specific number (this might even become
	// the default mode). Each thread may use a significant amount of
	// memory. When there are no memory usage limits set, we need some
	// default soft limit for calculating the "optimal" number of
	// threads.
	const uint64_t memlimit = mode == MODE_COMPRESS
			? memlimit_compress : memlimit_decompress;
	return memlimit != 0 ? memlimit : UINT64_MAX;
}


/// Helper for hardware_memlimit_show() to print one human-readable info line.
static void
memlimit_show(const char *str, uint64_t value)
{
	// The memory usage limit is considered to be disabled if value
	// is 0 or UINT64_MAX. This might get a bit more complex once there
	// is threading support. See the comment in hardware_memlimit_get().
	if (value == 0 || value == UINT64_MAX)
		printf("%s %s\n", str, _("Disabled"));
	else
		printf("%s %s MiB (%s B)\n", str,
				uint64_to_str(round_up_to_mib(value), 0),
				uint64_to_str(value, 1));

	return;
}


extern void
hardware_memlimit_show(void)
{
	if (opt_robot) {
		printf("%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\n", total_ram,
				memlimit_compress, memlimit_decompress);
	} else {
		// TRANSLATORS: Test with "xz --info-memory" to see if
		// the alignment looks nice.
		memlimit_show(_("Total amount of physical memory (RAM): "),
				total_ram);
		memlimit_show(_("Memory usage limit for compression:    "),
				memlimit_compress);
		memlimit_show(_("Memory usage limit for decompression:  "),
				memlimit_decompress);
	}

	tuklib_exit(E_SUCCESS, E_ERROR, message_verbosity_get() != V_SILENT);
}


extern void
hardware_init(void)
{
	// Get the amount of RAM. If we cannot determine it,
	// use the assumption defined by the configure script.
	total_ram = lzma_physmem();
	if (total_ram == 0)
		total_ram = (uint64_t)(ASSUME_RAM) * 1024 * 1024;

	// Set the defaults.
	hardware_memlimit_set(0, true, true, false);
	hardware_threadlimit_set(0);
	return;
}