hardware.c revision 256281
1130803Smarcel///////////////////////////////////////////////////////////////////////////////
2130803Smarcel//
3130803Smarcel/// \file       hardware.c
4130803Smarcel/// \brief      Detection of available hardware resources
5130803Smarcel//
6130803Smarcel//  Author:     Lasse Collin
7130803Smarcel//
8130803Smarcel//  This file has been put into the public domain.
9130803Smarcel//  You can do whatever you want with this file.
10130803Smarcel//
11130803Smarcel///////////////////////////////////////////////////////////////////////////////
12130803Smarcel
13130803Smarcel#include "private.h"
14130803Smarcel#include "tuklib_cpucores.h"
15130803Smarcel
16130803Smarcel
17130803Smarcel/// Maximum number of free *coder* threads. This can be set with
18130803Smarcel/// the --threads=NUM command line option.
19130803Smarcelstatic uint32_t threadlimit;
20130803Smarcel
21130803Smarcel/// Memory usage limit for compression
22130803Smarcelstatic uint64_t memlimit_compress;
23130803Smarcel
24130803Smarcel/// Memory usage limit for decompression
25130803Smarcelstatic uint64_t memlimit_decompress;
26130803Smarcel
27130803Smarcel/// Total amount of physical RAM
28130803Smarcelstatic uint64_t total_ram;
29130803Smarcel
30130803Smarcel
31130803Smarcelextern void
32130803Smarcelhardware_threadlimit_set(uint32_t new_threadlimit)
33130803Smarcel{
34130803Smarcel	if (new_threadlimit == 0) {
35130803Smarcel		// The default is the number of available CPU cores.
36130803Smarcel		threadlimit = tuklib_cpucores();
37130803Smarcel		if (threadlimit == 0)
38130803Smarcel			threadlimit = 1;
39130803Smarcel	} else {
40130803Smarcel		threadlimit = new_threadlimit;
41130803Smarcel	}
42130803Smarcel
43130803Smarcel	return;
44130803Smarcel}
45130803Smarcel
46130803Smarcel
47130803Smarcelextern uint32_t
48130803Smarcelhardware_threadlimit_get(void)
49130803Smarcel{
50130803Smarcel	return threadlimit;
51130803Smarcel}
52130803Smarcel
53130803Smarcel
54130803Smarcelextern void
55130803Smarcelhardware_memlimit_set(uint64_t new_memlimit,
56130803Smarcel		bool set_compress, bool set_decompress, bool is_percentage)
57130803Smarcel{
58130803Smarcel	if (is_percentage) {
59130803Smarcel		assert(new_memlimit > 0);
60130803Smarcel		assert(new_memlimit <= 100);
61130803Smarcel		new_memlimit = (uint32_t)new_memlimit * total_ram / 100;
62130803Smarcel	}
63130803Smarcel
64130803Smarcel	if (set_compress)
65130803Smarcel		memlimit_compress = new_memlimit;
66130803Smarcel
67130803Smarcel	if (set_decompress)
68130803Smarcel		memlimit_decompress = new_memlimit;
69130803Smarcel
70130803Smarcel	return;
71130803Smarcel}
72130803Smarcel
73130803Smarcel
74130803Smarcelextern uint64_t
75130803Smarcelhardware_memlimit_get(enum operation_mode mode)
76130803Smarcel{
77130803Smarcel	// Zero is a special value that indicates the default. Currently
78130803Smarcel	// the default simply disables the limit. Once there is threading
79130803Smarcel	// support, this might be a little more complex, because there will
80130803Smarcel	// probably be a special case where a user asks for "optimal" number
81130803Smarcel	// of threads instead of a specific number (this might even become
82130803Smarcel	// the default mode). Each thread may use a significant amount of
83130803Smarcel	// memory. When there are no memory usage limits set, we need some
84130803Smarcel	// default soft limit for calculating the "optimal" number of
85130803Smarcel	// threads.
86130803Smarcel	const uint64_t memlimit = mode == MODE_COMPRESS
87130803Smarcel			? memlimit_compress : memlimit_decompress;
88130803Smarcel	return memlimit != 0 ? memlimit : UINT64_MAX;
89130803Smarcel}
90130803Smarcel
91130803Smarcel
92130803Smarcel/// Helper for hardware_memlimit_show() to print one human-readable info line.
93130803Smarcelstatic void
94130803Smarcelmemlimit_show(const char *str, uint64_t value)
95130803Smarcel{
96130803Smarcel	// The memory usage limit is considered to be disabled if value
97130803Smarcel	// is 0 or UINT64_MAX. This might get a bit more complex once there
98130803Smarcel	// is threading support. See the comment in hardware_memlimit_get().
99130803Smarcel	if (value == 0 || value == UINT64_MAX)
100130803Smarcel		printf("%s %s\n", str, _("Disabled"));
101130803Smarcel	else
102130803Smarcel		printf("%s %s MiB (%s B)\n", str,
103130803Smarcel				uint64_to_str(round_up_to_mib(value), 0),
104130803Smarcel				uint64_to_str(value, 1));
105130803Smarcel
106130803Smarcel	return;
107130803Smarcel}
108130803Smarcel
109130803Smarcel
110130803Smarcelextern void
111130803Smarcelhardware_memlimit_show(void)
112130803Smarcel{
113130803Smarcel	if (opt_robot) {
114130803Smarcel		printf("%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\n", total_ram,
115130803Smarcel				memlimit_compress, memlimit_decompress);
116130803Smarcel	} else {
117130803Smarcel		// TRANSLATORS: Test with "xz --info-memory" to see if
118130803Smarcel		// the alignment looks nice.
119130803Smarcel		memlimit_show(_("Total amount of physical memory (RAM): "),
120130803Smarcel				total_ram);
121130803Smarcel		memlimit_show(_("Memory usage limit for compression:    "),
122130803Smarcel				memlimit_compress);
123130803Smarcel		memlimit_show(_("Memory usage limit for decompression:  "),
124				memlimit_decompress);
125	}
126
127	tuklib_exit(E_SUCCESS, E_ERROR, message_verbosity_get() != V_SILENT);
128}
129
130
131extern void
132hardware_init(void)
133{
134	// Get the amount of RAM. If we cannot determine it,
135	// use the assumption defined by the configure script.
136	total_ram = lzma_physmem();
137	if (total_ram == 0)
138		total_ram = (uint64_t)(ASSUME_RAM) * 1024 * 1024;
139
140	// Set the defaults.
141	hardware_memlimit_set(0, true, true, false);
142	hardware_threadlimit_set(0);
143	return;
144}
145