<rdar://problem/13963648>

Collect 'anonymous memory' info, if possible

git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@182523 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/debugserver/source/DNBDefs.h b/tools/debugserver/source/DNBDefs.h
index c915fd7..e4c95a9 100644
--- a/tools/debugserver/source/DNBDefs.h
+++ b/tools/debugserver/source/DNBDefs.h
@@ -356,6 +356,7 @@
     
     eProfileMemory              = (1 << 6), // By default, excludes eProfileMemoryDirtyPage.
     eProfileMemoryDirtyPage     = (1 << 7), // Assume eProfileMemory, get Dirty Page size as well.
+    eProfileMemoryAnonymous     = (1 << 8), // Assume eProfileMemory, get Anonymous memory as well.
     
     eProfileAll                 = 0xffffffff
 };
diff --git a/tools/debugserver/source/MacOSX/MachTask.cpp b/tools/debugserver/source/MacOSX/MachTask.cpp
index f80d479..30fc22c 100644
--- a/tools/debugserver/source/MacOSX/MachTask.cpp
+++ b/tools/debugserver/source/MacOSX/MachTask.cpp
@@ -364,7 +364,9 @@
     mach_vm_size_t vprvt = 0;
     mach_vm_size_t vsize = 0;
     mach_vm_size_t dirty_size = 0;
-    if (m_vm_memory.GetMemoryProfile(scanType, task, task_info, m_process->GetCPUType(), m_process->ProcessID(), vm_stats, physical_memory, rprvt, rsize, vprvt, vsize, dirty_size))
+    mach_vm_size_t purgeable = 0;
+    mach_vm_size_t anonymous = 0;
+    if (m_vm_memory.GetMemoryProfile(scanType, task, task_info, m_process->GetCPUType(), m_process->ProcessID(), vm_stats, physical_memory, rprvt, rsize, vprvt, vsize, dirty_size, purgeable, anonymous))
     {
         std::ostringstream profile_data_stream;
         
@@ -439,6 +441,12 @@
             
             if (scanType & eProfileMemoryDirtyPage)
                 profile_data_stream << "dirty:" << dirty_size << ';';
+
+            if (scanType & eProfileMemoryAnonymous)
+            {
+                profile_data_stream << "purgeable:" << purgeable << ';';
+                profile_data_stream << "anonymous:" << anonymous << ';';
+            }
         }
         
         profile_data_stream << "--end--;";
diff --git a/tools/debugserver/source/MacOSX/MachVMMemory.cpp b/tools/debugserver/source/MacOSX/MachVMMemory.cpp
index 17879c3..d9771a9 100644
--- a/tools/debugserver/source/MacOSX/MachVMMemory.cpp
+++ b/tools/debugserver/source/MacOSX/MachVMMemory.cpp
@@ -17,6 +17,7 @@
 #include <mach/mach_vm.h>
 #include <mach/shared_region.h>
 #include <sys/sysctl.h>
+#include <dlfcn.h>
 
 MachVMMemory::MachVMMemory() :
     m_page_size    (kInvalidPageSize),
@@ -281,14 +282,7 @@
         }
     }
     
-    static vm_size_t pagesize;
-    static bool calculated = false;
-    if (!calculated)
-    {
-        calculated = true;
-        pagesize = PageSize (task);
-    }
-    
+    vm_size_t pagesize = PageSize (task);
     rsize = pages_resident * pagesize;
     dirty_size = pages_dirtied * pagesize;
 }
@@ -333,14 +327,7 @@
     
     mach_vm_size_t aliased = 0;
     bool global_shared_text_data_mapped = false;
-    
-    static vm_size_t pagesize;
-    static bool calculated = false;
-    if (!calculated)
-    {
-        calculated = true;
-        pagesize = PageSize (task);
-    }
+    vm_size_t pagesize = PageSize (task);
     
     for (mach_vm_address_t addr=0, size=0; ; addr += size)
     {
@@ -430,8 +417,68 @@
     rprvt += aliased;
 }
 
+#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22
+
+// cribbed from sysmond
+static uint64_t
+SumVMPurgeableInfo(const vm_purgeable_info_t info)
+{
+    uint64_t sum = 0;
+    int i;
+    
+    for (i = 0; i < 8; i++)
+    {
+        sum += info->fifo_data[i].size;
+    }
+    sum += info->obsolete_data.size;
+    for (i = 0; i < 8; i++)
+    {
+        sum += info->lifo_data[i].size;
+    }
+    
+    return sum;
+}
+
+#endif
+
+static void
+GetPurgeableAndAnonymous(task_t task, uint64_t &purgeable, uint64_t &anonymous)
+{
+#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22
+
+    kern_return_t kr;
+    task_purgable_info_t purgeable_info;
+    uint64_t purgeable_sum = 0;
+    mach_msg_type_number_t info_count;
+    task_vm_info_data_t vm_info;
+    
+    if (dlsym(RTLD_NEXT, "task_purgable_info") != NULL )
+    {
+        kr = task_purgable_info(task, &purgeable_info);
+        if (kr == KERN_SUCCESS) {
+            purgeable_sum = SumVMPurgeableInfo(&purgeable_info);
+            purgeable = purgeable_sum;
+        }
+    }
+
+    info_count = TASK_VM_INFO_COUNT;
+    kr = task_info(task, TASK_VM_INFO, (task_info_t)&vm_info, &info_count);
+    if (kr == KERN_SUCCESS)
+    {
+        if (purgeable_sum < vm_info.internal)
+        {
+            anonymous = vm_info.internal - purgeable_sum;
+        }
+        else
+        {
+            anonymous = 0;
+        }
+    }
+#endif
+}
+
 nub_bool_t
-MachVMMemory::GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, vm_statistics_data_t &vm_stats, uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size)
+MachVMMemory::GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, vm_statistics_data_t &vm_stats, uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size, mach_vm_size_t &purgeable, mach_vm_size_t &anonymous)
 {
     if (scanType & eProfileHostMemory)
         physical_memory = GetPhysicalMemory();
@@ -453,6 +500,11 @@
             // This uses vmmap strategy. We don't use the returned rsize for now. We prefer to match top's version since that's what we do for the rest of the metrics.
             GetRegionSizes(task, rsize, dirty_size);
         }
+        
+        if (scanType & eProfileMemoryAnonymous)
+        {
+            GetPurgeableAndAnonymous(task, purgeable, anonymous);
+        }
     }
     
     return true;
diff --git a/tools/debugserver/source/MacOSX/MachVMMemory.h b/tools/debugserver/source/MacOSX/MachVMMemory.h
index 3c544a0..565ead0 100644
--- a/tools/debugserver/source/MacOSX/MachVMMemory.h
+++ b/tools/debugserver/source/MacOSX/MachVMMemory.h
@@ -28,7 +28,7 @@
     nub_size_t Write(task_t task, nub_addr_t address, const void *data, nub_size_t data_count);
     nub_size_t PageSize(task_t task);
     nub_bool_t GetMemoryRegionInfo(task_t task, nub_addr_t address, DNBRegionInfo *region_info);
-    nub_bool_t GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, vm_statistics_data_t &vm_stats, uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size);
+    nub_bool_t GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, vm_statistics_data_t &vm_stats, uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size, mach_vm_size_t &purgable, mach_vm_size_t &anonymous);
 
 protected:
     nub_size_t  MaxBytesLeftInPage(task_t task, nub_addr_t addr, nub_size_t count);