utils/meminfo.cpp

utils/meminfo.cpp

utils/meminfo.cpp

Functions

Name
long longget_entry(const char * name, const char * buf)
long longget_entry_fatal(const char * name, const char * buf)
long longavailable_guesstimate(const char * buf)
MemInforeadMemInfo()

Functions Documentation

function get_entry

static long long get_entry(
    const char * name,
    const char * buf
)

function get_entry_fatal

static long long get_entry_fatal(
    const char * name,
    const char * buf
)

function available_guesstimate

static long long available_guesstimate(
    const char * buf
)

function readMemInfo

MemInfo readMemInfo()

Read some data from meminfo that is relevant to Syntalos.

Source code

/*
 * Copyright (C) 2014 Jakob Unterwurzacher
 * Copyright (C) 2019-2024 Matthias Klumpp <matthias@tenstral.net>
 *
 * SPDX-License-Identifier: MIT or LGPL-3.0-or-later
 *
 * Licensed under the GNU Lesser General Public License Version 3
 *
 * This program 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 3 of the license, or
 * (at your option) any later version.
 *
 * This software 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.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software.  If not, see <http://www.gnu.org/licenses/>.
 *
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "meminfo.h"

#include <QDebug>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

/* Parse the contents of /proc/meminfo (in buf), return value of "name"
 * (example: MemTotal)
 * Returns -errno if the entry cannot be found. */
static long long get_entry(const char *name, const char *buf)
{
    const char *hit = strstr(buf, name);
    if (hit == NULL) {
        return -ENODATA;
    }

    errno = 0;
    const long long val = strtoll(hit + strlen(name), NULL, 10);
    if (errno != 0) {
        int strtoll_errno = errno;
        perror("get_entry: strtol() failed");
        return -strtoll_errno;
    }
    return val;
}

/* Like get_entry(), but exit if the value cannot be found */
static long long get_entry_fatal(const char *name, const char *buf)
{
    const long long val = get_entry(name, buf);
    if (val < 0) {
        qFatal("could not find entry '%s' in /proc/meminfo: %s", name, strerror((int)-val));
    }
    return val;
}

/* If the kernel does not provide MemAvailable (introduced in Linux 3.14),
 * approximate it using other data we can get */
static long long available_guesstimate(const char *buf)
{
    long long Cached = get_entry_fatal("Cached:", buf);
    long long MemFree = get_entry_fatal("MemFree:", buf);
    long long Buffers = get_entry_fatal("Buffers:", buf);
    long long Shmem = get_entry_fatal("Shmem:", buf);

    return MemFree + Cached + Buffers - Shmem;
}

MemInfo readMemInfo()
{
    // Note that we do not need to close static FDs that we ensure to
    // `fopen()` maximally once.
    static FILE *fd;

    // On Linux 5.3, "wc -c /proc/meminfo" counts 1391 bytes.
    // 8192 should be enough for the foreseeable future.
    char buf[8192] = {0};
    MemInfo m = {0, 0, 0};

    if (fd == NULL)
        fd = fopen("/proc/meminfo", "r");
    if (fd == NULL) {
        qFatal("could not open /proc/meminfo: %s", strerror(errno));
    }
    rewind(fd);

    size_t len = fread(buf, 1, sizeof(buf) - 1, fd);
    if (ferror(fd)) {
        qFatal("could not read /proc/meminfo: %s", strerror(errno));
    }
    if (len == 0) {
        qFatal("could not read /proc/meminfo: 0 bytes returned");
    }

    m.memTotalKiB = get_entry_fatal("MemTotal:", buf);
    long long MemAvailable = get_entry("MemAvailable:", buf);
    if (MemAvailable < 0) {
        // kernel was too old
        MemAvailable = available_guesstimate(buf);
    }

    // Calculate percentages
    m.memAvailablePercent = (double)MemAvailable * 100 / (double)m.memTotalKiB;

    // Convert kiB to MiB
    m.memAvailableMiB = MemAvailable / 1024;

    return m;
}

Updated on 2025-07-10 at 23:28:57 +0000