Memory REPORTing

18 views
Skip to first unread message

James Thorson

unread,
Jan 12, 2026, 11:00:47 AM (2 days ago) Jan 12
to TMB Users
Has anyone played around with REPORTing the memory (or displaying to terminal) using a CPP edit (see below)?

Specifically, the snippet appears to match the Windows-OS Task Manager reporting for Process Memory prior to `gc()` but:
  • I haven't tried testing on other OSes;
  • I haven't tried checking whether it passes CRAN checks;
  • I haven't tested whether the memory reporting is too context-dependent to be useful for tracking memory across different model decisions?
The topic of tracing memory use has come up many times ... my hope is that it would:
  1. For developers:  provide a simple way to compare memory use when comparing different model implementations;
  2. For users:  provide a useful way to track maximum memory use, e.g., when deciding how much memory is needed on a virtual machine;
I'd welcome any thoughts before spending too much time exploring :0

Jim



```c++
#include <TMB.hpp>

#ifdef _WIN32
  #include <windows.h>
  #include <psapi.h>
#else
  #include <sys/resource.h>
  #include <unistd.h>
#endif

// Helper function to cout current memory usage in MB
void log_memory(std::string label) {
    #ifdef _WIN32
    PROCESS_MEMORY_COUNTERS_EX pmc;
    GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
    SIZE_T physMemUsedByMe = pmc.WorkingSetSize;
    Rcout << label << ": " << physMemUsedByMe / 1024.0 / 1024.0 << " MB" << std::endl;
    #endif
}

// Helper function to REPORT current memory usage in MB
double get_memory_MB() {
#ifdef _WIN32
    PROCESS_MEMORY_COUNTERS_EX pmc;
    if (GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) {
        return (double)pmc.WorkingSetSize / 1024.0 / 1024.0;
    }
#elif defined(__linux__)
    // Linux-specific: Read from /proc/self/statm
    // Returns (size resident share text lib data dirty) in pages
    long pages = sysconf(_SC_PAGESIZE);
    FILE* fp = fopen("/proc/self/statm", "r");
    long rss = 0;
    if (fp) {
        if (fscanf(fp, "%*s%ld", &rss) == 1) { // Second value is RSS
            fclose(fp);
            return (double)rss * pages / 1024.0 / 1024.0;
        }
        fclose(fp);
    }
#elif defined(__APPLE__)
    // macOS-specific
    struct rusage usage;
    if (getrusage(RUSAGE_SELF, &usage) == 0) {
        // ru_maxrss is in bytes on macOS
        return (double)usage.ru_maxrss / 1024.0 / 1024.0;
    }
#endif
    return 0.0;
}
```

and then the standard template

```cpp
template<class Type>
Type objective_function<Type>::operator() ()
{
  log_memory("Start of Template");
  double memory_start_MB = get_memory_MB();
  REPORT(memory_start_MB);
  using namespace density;

  [...]
}
```

Kasper Kristensen

unread,
Jan 13, 2026, 6:43:56 AM (yesterday) Jan 13
to TMB Users
Jim, even if you could in principle make this work, it might not be very useful. Let me explain...

Only the first level of AD calls 'objective_function<Type>::operator()' so you could indeed get some useful information about the memory usage for the 'ADFun' tape.
However, usually memory issues occur later on when constructing 'ADGrad' from 'ADFun' or 'ADHess' from 'ADGrad'. These transformations do not call 'objective_function<Type>::operator()' at all, so the corresponding memory consumption would be invisible to the memory logger.
Reply all
Reply to author
Forward
0 new messages