1207753Smm///////////////////////////////////////////////////////////////////////////////
2207753Smm//
3207753Smm/// \file       hardware.c
4207753Smm/// \brief      Detection of available hardware resources
5207753Smm//
6207753Smm//  Author:     Lasse Collin
7207753Smm//
8207753Smm//  This file has been put into the public domain.
9207753Smm//  You can do whatever you want with this file.
10207753Smm//
11207753Smm///////////////////////////////////////////////////////////////////////////////
12207753Smm
13207753Smm#include "private.h"
14207753Smm
15207753Smm
16292588Sdelphij/// Maximum number of worker threads. This can be set with
17207753Smm/// the --threads=NUM command line option.
18292588Sdelphijstatic uint32_t threads_max = 1;
19207753Smm
20213700Smm/// Memory usage limit for compression
21213700Smmstatic uint64_t memlimit_compress;
22207753Smm
23213700Smm/// Memory usage limit for decompression
24213700Smmstatic uint64_t memlimit_decompress;
25213700Smm
26207753Smm/// Total amount of physical RAM
27207753Smmstatic uint64_t total_ram;
28207753Smm
29207753Smm
30207753Smmextern void
31292588Sdelphijhardware_threads_set(uint32_t n)
32207753Smm{
33292588Sdelphij	if (n == 0) {
34292588Sdelphij		// Automatic number of threads was requested.
35292588Sdelphij		// If threading support was enabled at build time,
36292588Sdelphij		// use the number of available CPU cores. Otherwise
37292588Sdelphij		// use one thread since disabling threading support
38292588Sdelphij		// omits lzma_cputhreads() from liblzma.
39292588Sdelphij#ifdef MYTHREAD_ENABLED
40292588Sdelphij		threads_max = lzma_cputhreads();
41292588Sdelphij		if (threads_max == 0)
42292588Sdelphij			threads_max = 1;
43292588Sdelphij#else
44292588Sdelphij		threads_max = 1;
45292588Sdelphij#endif
46207753Smm	} else {
47292588Sdelphij		threads_max = n;
48207753Smm	}
49207753Smm
50207753Smm	return;
51207753Smm}
52207753Smm
53207753Smm
54207753Smmextern uint32_t
55292588Sdelphijhardware_threads_get(void)
56207753Smm{
57292588Sdelphij	return threads_max;
58207753Smm}
59207753Smm
60207753Smm
61207753Smmextern void
62213700Smmhardware_memlimit_set(uint64_t new_memlimit,
63213700Smm		bool set_compress, bool set_decompress, bool is_percentage)
64207753Smm{
65213700Smm	if (is_percentage) {
66213700Smm		assert(new_memlimit > 0);
67213700Smm		assert(new_memlimit <= 100);
68213700Smm		new_memlimit = (uint32_t)new_memlimit * total_ram / 100;
69207753Smm	}
70207753Smm
71213700Smm	if (set_compress)
72213700Smm		memlimit_compress = new_memlimit;
73213700Smm
74213700Smm	if (set_decompress)
75213700Smm		memlimit_decompress = new_memlimit;
76213700Smm
77207753Smm	return;
78207753Smm}
79207753Smm
80207753Smm
81213700Smmextern uint64_t
82213700Smmhardware_memlimit_get(enum operation_mode mode)
83207753Smm{
84213700Smm	// Zero is a special value that indicates the default. Currently
85213700Smm	// the default simply disables the limit. Once there is threading
86213700Smm	// support, this might be a little more complex, because there will
87213700Smm	// probably be a special case where a user asks for "optimal" number
88213700Smm	// of threads instead of a specific number (this might even become
89213700Smm	// the default mode). Each thread may use a significant amount of
90213700Smm	// memory. When there are no memory usage limits set, we need some
91213700Smm	// default soft limit for calculating the "optimal" number of
92213700Smm	// threads.
93213700Smm	const uint64_t memlimit = mode == MODE_COMPRESS
94213700Smm			? memlimit_compress : memlimit_decompress;
95213700Smm	return memlimit != 0 ? memlimit : UINT64_MAX;
96213700Smm}
97207753Smm
98213700Smm
99213700Smm/// Helper for hardware_memlimit_show() to print one human-readable info line.
100213700Smmstatic void
101213700Smmmemlimit_show(const char *str, uint64_t value)
102213700Smm{
103213700Smm	// The memory usage limit is considered to be disabled if value
104213700Smm	// is 0 or UINT64_MAX. This might get a bit more complex once there
105213700Smm	// is threading support. See the comment in hardware_memlimit_get().
106213700Smm	if (value == 0 || value == UINT64_MAX)
107213700Smm		printf("%s %s\n", str, _("Disabled"));
108213700Smm	else
109213700Smm		printf("%s %s MiB (%s B)\n", str,
110213700Smm				uint64_to_str(round_up_to_mib(value), 0),
111213700Smm				uint64_to_str(value, 1));
112213700Smm
113207753Smm	return;
114207753Smm}
115207753Smm
116207753Smm
117213700Smmextern void
118213700Smmhardware_memlimit_show(void)
119207753Smm{
120213700Smm	if (opt_robot) {
121213700Smm		printf("%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\n", total_ram,
122213700Smm				memlimit_compress, memlimit_decompress);
123213700Smm	} else {
124213700Smm		// TRANSLATORS: Test with "xz --info-memory" to see if
125213700Smm		// the alignment looks nice.
126213700Smm		memlimit_show(_("Total amount of physical memory (RAM): "),
127213700Smm				total_ram);
128213700Smm		memlimit_show(_("Memory usage limit for compression:    "),
129213700Smm				memlimit_compress);
130213700Smm		memlimit_show(_("Memory usage limit for decompression:  "),
131213700Smm				memlimit_decompress);
132213700Smm	}
133213700Smm
134213700Smm	tuklib_exit(E_SUCCESS, E_ERROR, message_verbosity_get() != V_SILENT);
135207753Smm}
136207753Smm
137207753Smm
138207753Smmextern void
139207753Smmhardware_init(void)
140207753Smm{
141207753Smm	// Get the amount of RAM. If we cannot determine it,
142207753Smm	// use the assumption defined by the configure script.
143207753Smm	total_ram = lzma_physmem();
144207753Smm	if (total_ram == 0)
145207753Smm		total_ram = (uint64_t)(ASSUME_RAM) * 1024 * 1024;
146207753Smm
147207753Smm	// Set the defaults.
148213700Smm	hardware_memlimit_set(0, true, true, false);
149207753Smm	return;
150207753Smm}
151