Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(systemMemorySizeMb): Improve system memory detection on BSD systems #60489

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

lbartoletti
Copy link
Member

Description

  • Added support for detecting total system memory on FreeBSD, OpenBSD, and NetBSD using sysctl.
  • Updated systemMemorySizeMb() to use unsigned long instead of int for better accuracy, especially on systems with large amounts of RAM.
  • Introduced a constexpr unsigned long megabyte to improve readability and avoid redundant calculations.
  • Unified memory detection logic for BSD systems, using HW_PHYSMEM64 when available for better precision.

Fixes incorrect memory reporting on BSD platforms where it previously returned -1.

cc @landryb @gdt

@lbartoletti lbartoletti added API API improvement only, no visible user interface changes BSD For *BSD (FreeBSD, OpenBSD, NetBSD) labels Feb 6, 2025
@github-actions github-actions bot added this to the 3.42.0 milestone Feb 6, 2025
- Added support for detecting total system memory on FreeBSD, OpenBSD, and NetBSD using `sysctl`.
- Updated `systemMemorySizeMb()` to use `unsigned long` instead of `int` for better accuracy, especially on systems with large amounts of RAM.
- Introduced a `constexpr unsigned long megabyte` to improve readability and avoid redundant calculations.
- Unified memory detection logic for BSD systems, using `HW_PHYSMEM64` when available for better precision.

Fixes incorrect memory reporting on BSD platforms where it previously returned `-1`.
@lbartoletti lbartoletti self-assigned this Feb 6, 2025
Copy link

github-actions bot commented Feb 6, 2025

🪟 Windows builds

Download Windows builds of this PR for testing.
Debug symbols for this build are available here.
(Built from commit 3e8ade5)

🪟 Windows Qt6 builds

Download Windows Qt6 builds of this PR for testing.
(Built from commit 3e8ade5)

#elif defined(Q_OS_NETBSD)
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) || defined(Q_OS_NETBSD)
unsigned long physmem;
size_t size = sizeof( physmem );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On NetBSD, sysctl(7) says that hw.physmem64 is a "64-bit integer'. That type would be int64_t, not unsigned long.
And hy.physmem is a "32-bit integer", so "int32_t".

// For FreeBSD
int mib[2] = {CTL_HW, HW_PHYSMEM};
#endif

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On FreeBSD, sysctl(2) will be called with size=8, but it wants 4. On a big-endian machine, this will get the wrong answer. I realize this is messy, but it seems best to ask for oldp/oldsize as int32_t/sizeof(int32_t) or int64_t/sizeof(int64_t) and not try to alias types. I'd just move the sysctl into the if.

@@ -475,7 +475,7 @@ class CORE_EXPORT QgsApplication : public QApplication
*
* \since QGIS 3.26
*/
static int systemMemorySizeMb();
static unsigned long systemMemorySizeMb();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixing the problem that "int", assuming int is at least 32 bits (qgis won't build on a PDP-11 last I checked :-), can only represent 2^31 * 2*20 = 2^51 bytes of RAM? Which is 2T? That seems fair, as such RAM is now merely expensive and hard to find a motherboard for. I would lean to using uint64_t, but that's aesthetics. I might add a comment that a 32-bit signed variable could only represent memory < 2T.

@@ -475,7 +475,7 @@ class CORE_EXPORT QgsApplication : public QApplication
*
* \since QGIS 3.26
*/
static int systemMemorySizeMb();
static unsigned long systemMemorySizeMb();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this exposed in a shared library?

@@ -102,7 +102,7 @@ QgsImageCache::QgsImageCache( QObject *parent )
}
else
{
const int sysMemory = QgsApplication::systemMemorySizeMb();
const unsigned long sysMemory = QgsApplication::systemMemorySizeMb();
if ( sysMemory > 0 )
{
if ( sysMemory >= 32000 ) // 32 gb RAM (or more) = 500mb cache size
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably doesn't belong in this PR but the units are wrong. MB, not mb which is millibits :-)
Also, the comment and the code don't match, as 32 GB of ram is 32768 MB.

Perhaps more seriously, this is checking for >= 32 GB, but a machine with 32 GB will have physmem64 being less, presumably due to memory stolen by the BIOS for frame bufffer, or the kernel.

On NetBSD 10 amd64 with 32 GB of actual RAM and no virtualization involved.

$ sysctl hw.physmem; sysctl hw.physmem64
hw.physmem = -1
hw.physmem64 = 34159534080

which is 32577.07 MB, 190.9 MB short of 32G. That matches the kernel's available memory from boot:

total memory = 32577 MB
avail memory = 31474 MB

So checking for "32GB" probably should be "> 30 GB".

@gdt
Copy link
Contributor

gdt commented Feb 6, 2025

I get what's going on, but it's not clear how to test that the fix is working (assuming I try the commit on 3.34.x).

@rouault
Copy link
Contributor

rouault commented Feb 6, 2025

@lbartoletti If you are looking for a GDAL contribution, we have a CPLGetPhysicalRAM() in port/cpl_vsisimple.cpp . As GDAL is a required dependency of QGIS, it could perhaps make sense for QGIS to delegate to GDAL's CPLGetPhysicalRAM() ? GDAL's version has quite a lot of tuning on Linux to take into account the cgroup mechanism used by containers to further restrict actual usable RAM.

@landryb
Copy link
Contributor

landryb commented Feb 7, 2025

on OpenBSD:

QgsApplication.systemMemorySizeMb()
>>> 8045
$sysctl hw.physmem 
hw.physmem=8436838400

works for me, thanks :)

and if that can go in GDAL, that's even better !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API API improvement only, no visible user interface changes BSD For *BSD (FreeBSD, OpenBSD, NetBSD)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants