Real-Time System Monitoring on ARM-Linux Boards

Real-Time System Monitoring on ARM-Linux Boards

Monitoring real-time system data on ARM-Linux development boards is crucial for debugging, performance evaluation, and ensuring optimal operation. This guide demonstrates how to retrieve key metrics such as uptime, CPU usage, temperature, memory utilization, disk space, and network IP addresses using the OrangePi ZERO 2 as an example.

1. Retrieving System Uptime

The system uptime indicates how long the board has been running. While the uptime command provides a quick overview, programmatic access is often needed. The /proc/uptime file contains the raw data.

The file contains two values: total uptime in seconds and idle time in seconds. We'll focus on the first value.

#include <stdio.h>
#include <stdlib.h>

#define SECONDS_IN_MINUTE 60
#define MINUTES_IN_HOUR   60
#define HOURS_IN_DAY      24
#define SECONDS_IN_DAY (SECONDS_IN_MINUTE * MINUTES_IN_HOUR * HOURS_IN_DAY)
#define SECONDS_IN_HOUR (SECONDS_IN_MINUTE * SECONDS_IN_MINUTE)

double fetchUptimeSeconds(void) {
    FILE *uptimeFile = fopen("/proc/uptime", "r");
    if (uptimeFile == NULL) {
        perror("Failed to open uptime file");
        exit(EXIT_FAILURE);
    }

    double uptime_seconds;
    if (fscanf(uptimeFile, "%lf", &uptime_seconds) != 1) {
        perror("Failed to read uptime");
        fclose(uptimeFile);
        exit(EXIT_FAILURE);
    }
    fclose(uptimeFile);
    return uptime_seconds;
}

void formatUptime(double total_seconds, int *days, int *hours, int *minutes, int *seconds) {
    *days = (int)(total_seconds / SECONDS_IN_DAY);
    total_seconds -= *days * SECONDS_IN_DAY;

    *hours = (int)(total_seconds / SECONDS_IN_HOUR);
    total_seconds -= *hours * SECONDS_IN_HOUR;

    *minutes = (int)(total_seconds / SECONDS_IN_MINUTE);
    total_seconds -= *minutes * SECONDS_IN_MINUTE;

    *seconds = (int)total_seconds;
}

int main(void) {
    double total_seconds = fetchUptimeSeconds();
    int days, hours, minutes, secs;
    formatUptime(total_seconds, &days, &hours, &minutes, &secs);

    printf("System Uptime: %d days, %02d:%02d:%02d\n", days, hours, minutes, secs);
    return 0;
}

2. Monitoring CPU Usage

CPU usage is a critical metric for performance analysis. The /proc/stat file provides detailed CPU time statistics. The first line represents the aggregate CPU usage.

To calculate the CPU usage percentage, we sum the time spent in non-idle states (user, nice, system, iowait, irq, softirq) and divide by the total CPU time (including idle).

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

float calculateCpuUsage(void) {
    FILE *statFile = fopen("/proc/stat", "r");
    if (statFile == NULL) {
        perror("Failed to open /proc/stat");
        exit(EXIT_FAILURE);
    }

    char line[256];
    if (fgets(line, sizeof(line), statFile) == NULL) {
        perror("Failed to read from /proc/stat");
        fclose(statFile);
        exit(EXIT_FAILURE);
    }
    fclose(statFile);

    unsigned long user, nice, system, idle, iowait, irq, softirq;
    if (sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu", &user, &nice, &system, &idle, &iowait, &irq, &softirq) != 7) {
        fprintf(stderr, "Failed to parse CPU stats\n");
        exit(EXIT_FAILURE);
    }

    unsigned long total_time = user + nice + system + idle + iowait + irq + softirq;
    unsigned long non_idle_time = total_time - idle;

    return (float)non_idle_time / total_time * 100.0f;
}

int main(void) {
    float cpu_load = calculateCpuUsage();
    printf("CPU Load: %.2f%%\n", cpu_load);
    return 0;
}

3. Reading CPU Temperature

Monitoring CPU temperature is vital for thermal management and preventing overheating. The temperature data is typically found in the /sys/class/thermal/thermal_zone0/temp file, measured in millidegrees Celsius.

#include <stdio.h>
#include <stdlib.h>

float readCpuTemperature(void) {
    FILE *tempFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r");
    if (tempFile == NULL) {
        perror("Failed to open temperature file");
        exit(EXIT_FAILURE);
    }

    int millidegrees;
    if (fscanf(tempFile, "%d", &millidegrees) != 1) {
        perror("Failed to read temperature");
        fclose(tempFile);
        exit(EXIT_FAILURE);
    }
    fclose(tempFile);

    return (float)millidegrees / 1000.0f;
}

int main(void) {
    float temp_celsius = readCpuTemperature();
    printf("CPU Temperature: %.1f°C\n", temp_celsius);
    return 0;
}

4. Checking Memory Usage

Memory usage helps identify potential bottlenecks or leaks. The free command provides a summary, and we can parse its output to get the used and total memory in megabytes.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void getMemoryUsage(char *output_buffer, size_t buffer_size) {
    FILE *mem_info = popen("free -m | awk 'NR==2{printf \"%dMB/%dMB %.2f%%\", $3, $2, $3*100/$2}'", "r");
    if (mem_info == NULL) {
        perror("Failed to execute memory command");
        exit(EXIT_FAILURE);
    }

    if (fgets(output_buffer, buffer_size, mem_info) == NULL) {
        perror("Failed to read memory usage");
        pclose(mem_info);
        exit(EXIT_FAILURE);
    }
    pclose(mem_info);
}

int main(void) {
    char mem_usage[64];
    getMemoryUsage(mem_usage, sizeof(mem_usage));
    printf("Memory Usage: %s\n", mem_usage);
    return 0;
}

5. Determining Disk Usage

Disk space monitoring is essential for preventing storage exhaustion. The df command, combined with awk, can provide a concise summary of the root filesystem's usage.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void getDiskUsage(char *output_buffer, size_t buffer_size) {
    FILE *disk_info = popen("df -h / | awk '$NF==\"/\"{printf \"%sB/%sB %s\", $3, $2, $5}'", "r");
    if (disk_info == NULL) {
        perror("Failed to execute disk command");
        exit(EXIT_FAILURE);
    }

    if (fgets(output_buffer, buffer_size, disk_info) == NULL) {
        perror("Failed to read disk usage");
        pclose(disk_info);
        exit(EXIT_FAILURE);
    }
    pclose(disk_info);
}

int main(void) {
    char disk_usage[64];
    getDiskUsage(disk_usage, sizeof(disk_usage));
    printf("Disk Usage: %s\n", disk_usage);
    return 0;
}

6. Obtaining Network IP Address

Knowing the IP address is crucial for network connectivity. We can use the ip command with grep to extract the IPv4 address of a specific network interface (e.g., eth0 or wlan0).

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void getEth0IP(char *ip_buffer, size_t buffer_size) {
    FILE *ip_info = popen("ip -4 addr show eth0 | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}'", "r");
    if (ip_info == NULL) {
        perror("Failed to execute IP command for eth0");
        exit(EXIT_FAILURE);
    }

    if (fgets(ip_buffer, buffer_size, ip_info) == NULL) {
        perror("Failed to read eth0 IP");
        pclose(ip_info);
        exit(EXIT_FAILURE);
    }
    pclose(ip_info);
}

void getWlan0IP(char *ip_buffer, size_t buffer_size) {
    FILE *ip_info = popen("ip -4 addr show wlan0 | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}'", "r");
    if (ip_info == NULL) {
        perror("Failed to execute IP command for wlan0");
        exit(EXIT_FAILURE);
    }

    if (fgets(ip_buffer, buffer_size, ip_info) == NULL) {
        perror("Failed to read wlan0 IP");
        pclose(ip_info);
        exit(EXIT_FAILURE);
    }
    pclose(ip_info);
}

int main(void) {
    char eth0_ip[16], wlan0_ip[16];
    getEth0IP(eth0_ip, sizeof(eth0_ip));
    getWlan0IP(wlan0_ip, sizeof(wlan0_ip));

    printf("eth0 IP: %s\n", eth0_ip);
    printf("wlan0 IP: %s\n", wlan0_ip);
    return 0;
}

Tags: ARM-Linux OrangePi system monitoring c programming proc filesystem

Posted on Fri, 15 May 2026 19:21:27 +0000 by thiggins09