From ProventusNova DeveloperWiki
No edit summary
No edit summary
Line 23: Line 23:
| <code>---</code> || <span style="color:darkcyan">Cyan</span> || '''Free System RAM''': Available memory within that physical address range.
| <code>---</code> || <span style="color:darkcyan">Cyan</span> || '''Free System RAM''': Available memory within that physical address range.
|-
|-
| <code>|</code> || <span style="color:red">Red</span> || '''Occupancy Marker''': The specific boundary of current memory pressure.
| <code>&#124;</code> || <span style="color:red">Red</span> || '''Occupancy Marker''': The specific boundary of current memory pressure.
|-
|-
| <code>...</code> || <span style="color:red">Red</span> || '''Reserved/IO''': Non-system RAM (MMIO, GPU, Reserved by Firmware).
| <code>...</code> || <span style="color:red">Red</span> || '''Reserved/IO''': Non-system RAM (MMIO, GPU, Reserved by Firmware).

Revision as of 16:21, 20 February 2026

Overview

mempix is a lightweight bash utility designed to visualize physical memory allocation and real-time occupancy. It maps the data from /proc/iomem and correlates it with global memory statistics from /proc/meminfo to provide a per-block visual "pixel map."

It is specifically optimized for both embedded Yocto environments (like the MediaTek Genio 720) and standard Desktop Linux (Ubuntu/Debian).


Features

  • Visual Occupancy: A 12-character progress bar showing used vs. free space within each RAM block.
  • Threshold Marker: A red marker (|) indicating the exact transition point between used and free memory.
  • Unit Intelligence: Automatically scales between KB, MB, and GB based on block size.
  • Hardware Mapping: Identifies non-RAM regions (PCIe, GPU, Reserved) that are "locked" by hardware.
  • Universal Compatibility: Uses POSIX-compliant math and standard escape codes for serial consoles.

Map Legend

Symbol Color Meaning
### Green Used System RAM: Memory currently occupied by the kernel or processes.
--- Cyan Free System RAM: Available memory within that physical address range.
| Red Occupancy Marker: The specific boundary of current memory pressure.
... Red Reserved/IO: Non-system RAM (MMIO, GPU, Reserved by Firmware).

Usage

Standard Run

On Yocto (root), run directly. On Ubuntu, use sudo:

sudo ./mempix.sh

Real-time Monitoring

To watch memory blocks change live as processes open/close:

watch -c sudo ./mempix.sh

Source Code

Save the following code as mempix.sh:

#!/bin/bash

IOMEM="/proc/iomem"
MEMINFO="/proc/meminfo"

# --- PERMISSION CHECK ---
# Try to actually read one line. If empty, the kernel is masking the data.
CHECK_READ=$(head -n 1 "$IOMEM" 2>/dev/null)
if [ -z "$CHECK_READ" ]; then
    echo -e "\033[31mError: Cannot read physical addresses from $IOMEM.\033[0m"
    echo "If on Ubuntu, you must run this script with sudo."
    exit 1
fi

# 1. Get Global Stats
T_MEM_KB=$(grep MemTotal "$MEMINFO" | awk '{print $2}')
F_MEM_KB=$(grep MemFree "$MEMINFO" | awk '{print $2}')
OCC_RATIO=$(awk "BEGIN {print 1 - ($F_MEM_KB/$T_MEM_KB)}")
FREE_RATIO=$(awk "BEGIN {print $F_MEM_KB/$T_MEM_KB}")

format_matched() {
    local val_mb="$1"
    local target_unit="$2"
    local is_small=$(awk "BEGIN {if ($val_mb < 0.1) print 1; else print 0}")
    if [ "$is_small" -eq 1 ]; then
        awk "BEGIN {printf \"%.1f KB\", $val_mb * 1024}"
    elif [ "$target_unit" == "GB" ]; then
        awk "BEGIN {printf \"%.2f GB\", $val_mb / 1024}"
    else
        awk "BEGIN {printf \"%.1f MB\", $val_mb}"
    fi
}

# --- LEGEND ---
echo -e "\033[1mMAP LEGEND:\033[0m"
echo -e "\033[32m###\033[0m : Used System RAM   \033[1;31m|\033[0m : Occupancy Marker"
echo -e "\033[36m---\033[0m : Free System RAM   \033[31m...\033[0m : Reserved/Hardware/IO"
echo ""

echo -e "\033[1mPHYSICAL BLOCK ANALYSIS\033[0m"
printf "%-12s | %-12s | %-18s | %-12s | %s\n" "ADDRESS" "PIXEL MAP" "FREE (MATCHED)" "TOTAL SIZE" "LABEL"
echo "---------------------------------------------------------------------------------------------------"

# Clean input and iterate
grep -E "System RAM|Kernel|reserved|pcie|gpu" "$IOMEM" | sed 's/^[ ]*//' | while read -r line; do
    ADDR=$(echo "$line" | cut -d' ' -f1)
    LABEL=$(echo "$line" | cut -d':' -f2- | xargs)
    S_HEX=$(echo "$ADDR" | cut -d'-' -f1)
    E_HEX=$(echo "$ADDR" | cut -d'-' -f2)

    # Validate Hex
    if [[ ! $S_HEX =~ ^[0-9a-fA-F]+$ ]]; then continue; fi

    S_DEC=$(printf "%d" "0x$S_HEX" 2>/dev/null)
    E_DEC=$(printf "%d" "0x$E_HEX" 2>/dev/null)
    SIZE_MB=$(awk "BEGIN {print ($E_DEC - $S_DEC + 1) / 1048576}")

    UNIT="MB"; [ $(awk "BEGIN {if ($SIZE_MB >= 1024) print 1; else print 0}") -eq 1 ] && UNIT="GB"

    if [[ "$LABEL" == "System RAM" ]]; then
        FREE_MB=$(awk "BEGIN {print $SIZE_MB * $FREE_RATIO}")
        P_FREE=$(awk "BEGIN {printf \"%.1f%%\", $FREE_RATIO * 100}")
        U_CH=$(awk "BEGIN {val = 12 * $OCC_RATIO; printf \"%.0f\", (val<1 && val>0)?1:val}")
        [ "$U_CH" -gt 12 ] && U_CH=12
        F_CH=$((12 - U_CH))

        if [ "$U_CH" -gt 0 ]; then
            BAR_USED=$(printf "%$((U_CH-1))s" | tr ' ' '#')
            MARKER="\033[1;31m|\033[0m"
            BAR_FREE=$(printf "%${F_CH}s" | tr ' ' '-')
            PIX="\033[32m${BAR_USED}${MARKER}\033[36m${BAR_FREE}\033[0m"
        else
            PIX="\033[36m------------\033[0m"
        fi
        STR_FREE=$(format_matched "$FREE_MB" "$UNIT")
        STR_TOTAL=$(format_matched "$SIZE_MB" "$UNIT")
    else
        PIX="\033[31m............\033[0m"
        P_FREE="0.0%"
        STR_FREE=$(format_matched 0 "$UNIT")
        STR_TOTAL=$(format_matched "$SIZE_MB" "$UNIT")
    fi

    printf "0x%08s | %b | %-18s | %-12s | %s\n" "$S_HEX" "$PIX" "$P_FREE ($STR_FREE)" "$STR_TOTAL" "$LABEL"
done

Troubleshooting

Error: Cannot read physical addresses

If you see this error, it means the Kernel is masking /proc/iomem for security.

  • Desktop: Ensure you are using sudo.
  • Embedded: Ensure you are logged in as a user with root privileges.