diff --git a/src/MemoryUsage.cpp b/src/MemoryUsage.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5383f6ecc9ae1580a973dc210af934a9722a3db --- /dev/null +++ b/src/MemoryUsage.cpp @@ -0,0 +1,155 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "transport/MemoryUsage.h" + +#include +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#else +#include +#include +#endif +#ifdef __MACH__ +#include +#elif BSD +#include +#include +#include +#include +#include +#endif + +namespace Transport { + +#ifndef WIN32 +#ifdef __MACH__ + +void process_mem_usage(double& vm_usage, double& resident_set, pid_t pid) { + + struct task_basic_info t_info; + mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; + + if (KERN_SUCCESS != task_info(mach_task_self(), + TASK_BASIC_INFO, (task_info_t)&t_info, + &t_info_count)) { + vm_usage = 0; + resident_set = 0; + return; + } + vm_usage = t_info.virtual_size; + resident_set = t_info.resident_size; +} +#elif BSD +void process_mem_usage(double& vm_usage, double& resident_set, pid_t pid) { + int mib[4]; + size_t size; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + if (pid == 0) { + mib[3] = getpid(); + } + else { + mib[3] = pid; + } + struct kinfo_proc proc; + + size = sizeof(struct kinfo_proc); + + if (sysctl((int*)mib, 4, &proc, &size, NULL, 0) == -1) { + vm_usage = 0; + resident_set = 0; + return; + } + + // sysctl stores 0 in the size if we can't find the process information. + // Set errno to ESRCH which will be translated in NoSuchProcess later on. + if (size == 0) { + vm_usage = 0; + resident_set = 0; + return; + } + + int pagesize,cnt; + + size = sizeof(pagesize); + sysctlbyname("hw.pagesize", &pagesize, &size, NULL, 0); + + resident_set = (double) (proc.ki_rssize * pagesize / 1024); + vm_usage = (double) proc.ki_size; +} +#else /* BSD */ +void process_mem_usage(double& shared, double& resident_set, pid_t pid) { + using std::ios_base; + using std::ifstream; + using std::string; + + shared = 0.0; + resident_set = 0.0; + + // 'file' stat seems to give the most reliable results + std::string f = "/proc/self/statm"; + if (pid != 0) { + f = "/proc/" + boost::lexical_cast(pid) + "/statm"; + } + ifstream stat_stream(f.c_str(), ios_base::in); + if (!stat_stream.is_open()) { + shared = 0; + resident_set = 0; + return; + } + + // dummy vars for leading entries in stat that we don't care about + // + string pid1, comm, state, ppid, pgrp, session, tty_nr; + string tpgid, flags, minflt, cminflt, majflt, cmajflt; + string utime, stime, cutime, cstime, priority, nice; + string O, itrealvalue, starttime; + + // the two fields we want + // + unsigned long shared_; + long rss; + + stat_stream >> O >> rss >> shared_; // don't care about the rest + + long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages + shared = shared_ * page_size_kb; + resident_set = rss * page_size_kb; +} +#endif /* else BSD */ +#else +#define PSAPI_VERSION 1 +#define pid_t void* + void process_mem_usage(double& shared, double& resident_set, pid_t pid) { + PROCESS_MEMORY_COUNTERS_EX pmc; + GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)); + shared = (double)pmc.PrivateUsage; + resident_set = (double)pmc.WorkingSetSize; + } +#endif /* WIN32 */ + +}