void MemoryInstance::Update()

in source/code/scxsystemlib/memory/memoryinstance.cpp [812:1120]


    void MemoryInstance::Update()
    {
        SCX_LOGTRACE(m_log, L"MemoryInstance Update()");

#if defined(linux)

    /**
        Update the object members with values from /proc/meminfo.

        \ex
        /proc/meminfo:
          MemTotal:       516400 kB
          MemFree:         91988 kB
          Buffers:         46148 kB
          Cached:         277860 kB
          SwapCached:      64136 kB
          Active:         299804 kB
          Inactive:        97372 kB
          HighTotal:           0 kB
          HighFree:            0 kB
          LowTotal:       516400 kB
          LowFree:         91988 kB
          SwapTotal:      514040 kB
          SwapFree:       402508 kB
          Dirty:             676 kB
          Writeback:           0 kB
          Mapped:          96832 kB
          Slab:            20356 kB
          CommitLimit:    772240 kB
          Committed_AS:   281692 kB
          PageTables:       1700 kB
          VmallocTotal:   507896 kB
          VmallocUsed:      3228 kB
          VmallocChunk:   504576 kB
          HugePages_Total:     0
          HugePages_Free:      0
          HugePages_Rsvd:      0
          Hugepagesize:     4096 kB

        We are interested in the following fields:
          MemTotal
          MemFree
          SwapTotal
          SwapFree
    */
	
	/**
	    The 3.14+ linux kernel has MemAvailable: which gives more appropirate value for available memory. We will be getting the available memory from MemAvailable: (if present) instead of MemFree + Buffers + Cached
	    MemTotal:        3522864 kB
	    MemFree:          175844 kB
	    MemAvailable:    2813432 kB
	    Buffers:              36 kB
	    Cached:           289148 kB
	    SwapCached:          332 kB
	    Active:           234424 kB
	    Inactive:         250828 kB
	    Active(anon):      94120 kB
	    Inactive(anon):   203372 kB
	    Active(file):     140304 kB
	    Inactive(file):    47456 kB
	    Unevictable:           0 kB
	    Mlocked:               0 kB
	    SwapTotal:       6655996 kB
	    SwapFree:        6638924 kB
	    Dirty:                 8 kB
	    Writeback:             0 kB
	    AnonPages:        195772 kB
	    Mapped:            28868 kB
	    Shmem:            101424 kB
	    Slab:            2765564 kB
	    SReclaimable:    2745856 kB
	    SUnreclaim:        19708 kB
	    KernelStack:        4224 kB
	    PageTables:         6588 kB
	    NFS_Unstable:          0 kB
	    Bounce:                0 kB
	    WritebackTmp:          0 kB
	    CommitLimit:     8417428 kB
	    Committed_AS:    1004816 kB
	    VmallocTotal:   34359738367 kB
	    VmallocUsed:       67624 kB
	    VmallocChunk:   34359663604 kB
	    HardwareCorrupted:     0 kB
	    AnonHugePages:     75776 kB
	    HugePages_Total:       0
	    HugePages_Free:        0
	    HugePages_Rsvd:        0
	    HugePages_Surp:        0
	    Hugepagesize:       2048 kB
	    DirectMap4k:       94144 kB
	    DirectMap2M:     3575808 kB

	*/
        std::vector<std::wstring> lines = m_deps->GetMemInfoLines();

        scxulong buffers = 0, cached = 0, reportedAvailableMemory = 0; // KB

        for (size_t i = 0; i < lines.size(); i++)
        {
            std::wstring line = lines[i];

            SCX_LOGHYSTERICAL(m_log, std::wstring(L"UpdateFromMemInfo() - Read line: ").append(line));

            std::vector<std::wstring> tokens;
            StrTokenize(line, tokens);
            if (tokens.size() >= 2)
            {
                if (L"MemTotal:" == tokens[0])
                {
                    try
                    {
                        m_totalPhysicalMemory = StrToULong(tokens[1]) * 1024;  // Resulting units: bytes
                        m_foundTotalPhysMem = true;
                        SCX_LOGHYSTERICAL(m_log, StrAppend(L"    totalPhysicalMemory = ", m_totalPhysicalMemory));
                    }
                    catch (const SCXNotSupportedException& e)
                    {
                        SCX_LOGWARNING(m_log, std::wstring(L"Could not read m_totalPhysicalMemory from :").append(line).append(L" - ").append(e.What()));
                    }
                }
                if (L"MemAvailable:" == tokens[0])
                {
                    try
                    {
                        reportedAvailableMemory = StrToULong(tokens[1]) * 1024;  // Resulting units: bytes
                        m_foundAvailMem = true;
                        SCX_LOGHYSTERICAL(m_log, StrAppend(L"    availableMemory = ", m_availableMemory));
                    }
                    catch (const SCXNotSupportedException& e)
                    {
                        SCX_LOGWARNING(m_log, std::wstring(L"Could not read m_availableMemory from: ").append(line).append(L" - ").append(e.What()));
                    }
                }
                if (L"MemFree:" == tokens[0])
                {
                    try
                    {
                        m_availableMemory = StrToULong(tokens[1]) * 1024;  // Resulting units: bytes
                        m_foundAvailMem = true;
                        SCX_LOGHYSTERICAL(m_log, StrAppend(L"    availableMemory = ", m_availableMemory));
                    }
                    catch (const SCXNotSupportedException& e)
                    {
                        SCX_LOGWARNING(m_log, std::wstring(L"Could not read m_availableMemory from: ").append(line).append(L" - ").append(e.What()));
                    }
                }
                if (L"Buffers:" == tokens[0])
                {
                    try
                    {
                        buffers = StrToULong(tokens[1]) * 1024;  // Resulting units: bytes
                        SCX_LOGHYSTERICAL(m_log, StrAppend(L"    buffers = ", buffers));
                    }
                    catch (const SCXNotSupportedException& e)
                    {
                        SCX_LOGWARNING(m_log, std::wstring(L"Could not read buffers from: ").append(line).append(L" - ").append(e.What()));
                    }
                }
                if (L"Cached:" == tokens[0])
                {
                    try
                    {
                        cached = StrToULong(tokens[1]) * 1024;  // Resulting units: bytes
                        SCX_LOGHYSTERICAL(m_log, StrAppend(L"    Cached = ", cached));
                    }
                    catch (const SCXNotSupportedException& e)
                    {
                        SCX_LOGWARNING(m_log, std::wstring(L"Could not read buffers from: ").append(line).append(L" - ").append(e.What()));
                    }
                }
                if (L"SwapTotal:" == tokens[0])
                {
                    try
                    {
                        m_totalSwap = StrToULong(tokens[1]) * 1024; // Resulting units: bytes
                        m_foundTotalSwap = true;
                        SCX_LOGHYSTERICAL(m_log, StrAppend(L"    totalSwap = ", m_totalSwap));
                    }
                    catch (const SCXNotSupportedException& e)
                    {
                        SCX_LOGWARNING(m_log, std::wstring(L"Could not read m_totalSwap from: ").append(line).append(L" - ").append(e.What()));
                    }
                }
                if (L"SwapFree:" == tokens[0])
                {
                    try
                    {
                        m_availableSwap = StrToULong(tokens[1]) * 1024; // Resulting units: bytes
                        m_foundAvailSwap = true;
                        SCX_LOGHYSTERICAL(m_log, StrAppend(L"    availableSwap = ", m_availableSwap));
                    }
                    catch (const SCXNotSupportedException& e)
                    {
                        SCX_LOGWARNING(m_log, std::wstring(L"Could not read m_availableSwap from: ").append(line).append(L" - ").append(e.What()));
                    }
                }
            }
        }

        // perform some adjustments and calculations. Resulting units: bytes.
        if (reportedAvailableMemory)
        {
            m_availableMemory = reportedAvailableMemory;
        } else {
            m_availableMemory += buffers + cached;
        }
        m_usedMemory = m_totalPhysicalMemory - m_availableMemory;
        m_usedSwap = m_totalSwap - m_availableSwap;

        // This is "weak" in that it can easily be missed; we verify this in unit tests too now
        SCXASSERT(m_foundTotalPhysMem && "MemTotal not found");
        SCXASSERT(m_foundAvailMem && "MemFree not found");
        SCXASSERT(m_foundTotalSwap && "SwapTotal not found");
        SCXASSERT(m_foundAvailSwap && "SwapFree not found");

#elif defined(sun)

        /*
          Update the object members with info from sysconf and swapctl.
        */

        scxulong pageSize = m_deps->GetPageSize();
        m_totalPhysicalMemory = m_deps->GetPhysicalPages() * pageSize;      // Resulting units: bytes
        m_availableMemory = m_deps->GetAvailablePhysicalPages() * pageSize; // Resulting units: bytes

        SCX_LOGTRACE(m_log, StrAppend(L"MemoryInstance::Update() - Page Size (", pageSize).append(L")"));
        SCX_LOGTRACE(m_log, StrAppend(L"MemoryInstance::Update() - Total Physical Memory (", m_totalPhysicalMemory).append(L")"));
        SCX_LOGTRACE(m_log, StrAppend(L"MemoryInstance::Update() - Memory Available (", m_availableMemory).append(L")"));

        scxulong cacheSize = 0;
        GetCacheSize(cacheSize);
        SCX_LOGTRACE(m_log, StrAppend(L"MemoryInstance::Update() - ZFS Cache Size (", cacheSize).append(L")"));

        m_availableMemory += cacheSize;
        m_usedMemory = m_totalPhysicalMemory - m_availableMemory;           // Resulting units: bytes

        SCX_LOGTRACE(m_log, StrAppend(L"MemoryInstance::Update() - New Memory Available (", m_availableMemory).append(L")"));
        SCX_LOGTRACE(m_log, StrAppend(L"MemoryInstance::Update() - Used Memory (", m_usedMemory).append(L")"));

        scxulong max_pages = 0;
        scxulong reserved_pages = 0;
        m_deps->GetSwapInfo(max_pages, reserved_pages);
        SCX_LOGTRACE(m_log, StrAppend(L"MemoryInstance::Update() - Swap Max Pages (", max_pages).append(L")"));
        SCX_LOGTRACE(m_log, StrAppend(L"MemoryInstance::Update() - Swap Reserved Pages (", reserved_pages).append(L")"));

        m_totalSwap = max_pages * pageSize;                    // Resulting units: bytes
        m_availableSwap = (max_pages - reserved_pages) * pageSize;  // Resulting units: bytes
        m_usedSwap = reserved_pages * pageSize;                // Resulting units: bytes

        SCX_LOGTRACE(m_log, StrAppend(L"MemoryInstance::Update() - Swap Total (", m_totalSwap).append(L")"));
        SCX_LOGTRACE(m_log, StrAppend(L"MemoryInstance::Update() - Swap Available (", m_availableSwap).append(L")"));
        SCX_LOGTRACE(m_log, StrAppend(L"MemoryInstance::Update() - Swap Used (", m_usedSwap).append(L")"));

#elif defined(hpux)

        scxulong page_size = 0;
        scxulong physical_memory = 0;
        scxulong real_pages = 0;
        scxulong free_pages = 0;

        m_deps->GetStaticMemoryInfo(page_size, physical_memory);
        m_deps->GetDynamicMemoryInfo(real_pages, free_pages);

        m_totalPhysicalMemory = (physical_memory * page_size); // Resulting units: bytes
        m_usedMemory = (real_pages * page_size);               // Resulting units: bytes
        m_availableMemory = (free_pages * page_size);          // Resulting units: bytes

        // The reservedMemory size varies with a few MB up and down, so it's best to recompute 
        // this number every time so that the used and free percentages adds up.
        m_reservedMemory = m_totalPhysicalMemory - m_usedMemory - m_availableMemory;

        scxulong max_pages = 0;
        scxulong reserved_pages = 0;

        m_deps->GetSwapInfo(max_pages, reserved_pages);

        // totalSwap is the total size of all external swap devices plus swap memory, if enabled
        // availableSwap is the size of remaining device swap (with reserved memory subtracted)
        // plus remaining swap memory, if that was enabled in system configuration.
        // usedSwap is the difference between those. This is consistent with the 'total'
        // numbers when you do 'swapinfo -t'.
        m_totalSwap = max_pages * page_size;                   // Resulting units: bytes
        m_availableSwap = reserved_pages * page_size;          // Resulting units: bytes
        m_usedSwap = m_totalSwap - m_availableSwap;            // Resulting units: bytes

#elif defined(aix)

        scxulong total_pages = 0;
        scxulong free_pages = 0;
        scxulong max_swap_pages = 0;
        scxulong free_swap_pages = 0;

        m_deps->GetMemInfo(total_pages, free_pages, max_swap_pages, free_swap_pages);

        // All memory data given in bytes

        m_totalPhysicalMemory = (total_pages * 4) * 1024;      // Resulting units: bytes
        m_availableMemory = (free_pages * 4) * 1024;           // Resulting units: bytes
        m_usedMemory = m_totalPhysicalMemory - m_availableMemory;   // Resulting units: bytes

        m_totalSwap = (max_swap_pages * 4) * 1024;             // Resulting units: bytes
        m_availableSwap = (free_swap_pages * 4) * 1024;        // Resulting units: bytes
        m_usedSwap = m_totalSwap - m_availableSwap;

#else
#error "Not implemented for this platform."
#endif

    }