diff --git a/checkin_notes b/checkin_notes
index 706aae185f..4307a1454d 100755
--- a/checkin_notes
+++ b/checkin_notes
@@ -9401,3 +9401,23 @@ Charlie 28 Aug 2006
clientgui/
AdvancedFrame.cpp,h
Events.h
+
+David 28 Aug 2006
+ - Detection of memory usage now works on Windows.
+ You can find the amount of RAM (working set)
+ and page file spaced used by each running BOINC app,
+ and by all non-BOINC apps.
+ Currently this isn't used for anything.
+ If you set the flag in cc_config.xml,
+ it will print memory stats every 10 seconds.
+
+ TODO: get this working for Linux/Mac
+
+ client/
+ app.C
+ log_flags.C,h
+ lib/
+ procinfo.h
+ procinfo_win.h
+ win_build/
+ boinc_cli_curl.vcproj
diff --git a/client/app.C b/client/app.C
index 92432e7978..b9e8810bdf 100644
--- a/client/app.C
+++ b/client/app.C
@@ -67,6 +67,7 @@
#include "shmem.h"
#include "util.h"
#include "client_msgs.h"
+#include "procinfo.h"
#include "app.h"
using std::max;
@@ -199,6 +200,7 @@ void ACTIVE_TASK_SET::free_mem() {
//
bool ACTIVE_TASK_SET::poll() {
bool action;
+ unsigned int i;
static double last_time = 0;
if (gstate.now - last_time < 1.0) return false;
last_time = gstate.now;
@@ -210,7 +212,7 @@ bool ACTIVE_TASK_SET::poll() {
process_control_poll();
action |= check_rsc_limits_exceeded();
action |= get_msgs();
- for (unsigned int i=0; itask_state == PROCESS_ABORT_PENDING) {
if (gstate.now > atp->abort_time + 5.0) {
@@ -222,6 +224,35 @@ bool ACTIVE_TASK_SET::poll() {
if (action) {
gstate.set_client_state_dirty("ACTIVE_TASK_SET::poll");
}
+
+ if (log_flags.mem_usage_debug) {
+ static double last_mem_time=0;
+ if (gstate.now - last_mem_time > 10) {
+ last_mem_time = gstate.now;
+ vector piv;
+ PROCINFO pi;
+ procinfo_setup(piv);
+ for (i=0; itask_state == PROCESS_EXECUTING) {
+ memset(&pi, 0, sizeof(pi));
+ pi.id = atp->pid;
+ procinfo_app(pi, piv);
+ msg_printf(NULL, MSG_INFO, "%s: RAM %dKB, page %dKB, user %f, kernel %f",
+ atp->result->name,
+ (int)(pi.working_set_size/1024), (int)(pi.swap_size/1024),
+ pi.user_time, pi.kernel_time
+ );
+ }
+ }
+ procinfo_other(pi, piv);
+ msg_printf(NULL, MSG_INFO, "All others: RAM %dKB, page %dKB, user %f, kernel %f",
+ (int)(pi.working_set_size/1024), (int)(pi.swap_size/1024),
+ pi.user_time, pi.kernel_time
+ );
+ }
+ }
+
return action;
}
diff --git a/client/log_flags.C b/client/log_flags.C
index ad3c58e97b..d2a49e69a3 100644
--- a/client/log_flags.C
+++ b/client/log_flags.C
@@ -87,6 +87,7 @@ int LOG_FLAGS::parse(XML_PARSER& xp) {
else if (xp.parse_bool(tag, "guirpc_debug", guirpc_debug)) continue;
else if (xp.parse_bool(tag, "scrsave_debug", scrsave_debug)) continue;
else if (xp.parse_bool(tag, "app_msg_debug", app_msg_debug)) continue;
+ else if (xp.parse_bool(tag, "mem_usage_debug", mem_usage_debug)) continue;
else {
msg_printf(NULL, MSG_ERROR, "Unrecognized tag in %s: <%s>\n",
CONFIG_FILE, tag
diff --git a/client/log_flags.h b/client/log_flags.h
index 440ed985eb..87d27b5f1b 100644
--- a/client/log_flags.h
+++ b/client/log_flags.h
@@ -65,6 +65,7 @@ struct LOG_FLAGS {
bool guirpc_debug;
bool scrsave_debug;
bool app_msg_debug; // show shared-mem message from apps
+ bool mem_usage_debug; // memory usage
LOG_FLAGS();
int parse(XML_PARSER&);
diff --git a/lib/procinfo.h b/lib/procinfo.h
index 45c8a2bcce..fab04a677d 100644
--- a/lib/procinfo.h
+++ b/lib/procinfo.h
@@ -1,10 +1,20 @@
#include
struct PROCINFO {
- double virtual_size;
+ int id;
+ int parentid;
+ double swap_size;
double working_set_size;
double user_time;
double kernel_time;
+ bool is_boinc_app;
};
-extern int get_procinfo(std::vector& pi).
+extern int procinfo_setup(std::vector&);
+ // call this first to get data structure
+extern void procinfo_app(PROCINFO&, std::vector&);
+ // call this to get mem usage for a given app
+ // (marks process as BOINC)
+extern void procinfo_other(PROCINFO&, std::vector&);
+ // After getting mem usage for all BOINC apps,
+ // call this to get mem usage for everything else
diff --git a/lib/procinfo_win.C b/lib/procinfo_win.C
index b4a1fba205..c2faafb3d3 100644
--- a/lib/procinfo_win.C
+++ b/lib/procinfo_win.C
@@ -1,6 +1,19 @@
-#include "diagnostic_win.h"
+#include "diagnostics_win.h"
#include "procinfo.h"
+using std::vector;
+
+// NtQuerySystemInformation
+typedef NTSTATUS (WINAPI *tNTQSI)(
+ ULONG SystemInformationClass,
+ PVOID SystemInformation,
+ ULONG SystemInformationLength,
+ PULONG ReturnLength
+);
+
+// OpenThread
+typedef HANDLE (WINAPI *tOT)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
+
static int get_process_information(PVOID* ppBuffer, PULONG pcbBuffer) {
int retval = 0;
NTSTATUS Status = STATUS_INFO_LENGTH_MISMATCH;
@@ -40,7 +53,6 @@ int get_procinfo_XP(vector& pi) {
ULONG cbBuffer = 32*1024; // 32k initial buffer
PVOID pBuffer = NULL;
PSYSTEM_PROCESSES pProcesses = NULL;
- PSYSTEM_THREADS pThread = NULL;
HMODULE hKernel32Lib;
tOT pOT = NULL;
@@ -51,10 +63,15 @@ int get_procinfo_XP(vector& pi) {
pProcesses = (PSYSTEM_PROCESSES)pBuffer;
while (pProcesses) {
PROCINFO p;
- p.virtual_size = pProcesses->VmCounters.VirtualSize;
+ p.id = pProcesses->ProcessId;
+ p.parentid = pProcesses->InheritedFromProcessId;
+ p.swap_size = pProcesses->VmCounters.PagefileUsage;
p.working_set_size = pProcesses->VmCounters.WorkingSetSize;
- p.user_time = (double) pProcesses->UserTime.QuadPart;
- p.kernel_time = (double) pProcesses->KernelTime.QuadPart;
+ p.user_time = ((double) pProcesses->UserTime.QuadPart)/1e7;
+ p.kernel_time = ((double) pProcesses->KernelTime.QuadPart)/1e7;
+ p.id = pProcesses->ProcessId;
+ p.parentid = pProcesses->InheritedFromProcessId;
+ p.is_boinc_app = false;
pi.push_back(p);
if (!pProcesses->NextEntryDelta) {
@@ -66,14 +83,16 @@ int get_procinfo_XP(vector& pi) {
if (pBuffer) HeapFree(GetProcessHeap(), NULL, pBuffer);
return 0;
}
-int get_procinfo_NT(vector& pi) {
+int get_procinfo_NT(vector&) {
return 0;
}
-int get_procinfo_9X(vector& pi) {
+int get_procinfo_9X(vector&) {
return 0;
}
-int get_procinfo(vector& pi) {
+// get a list of all running processes.
+//
+int procinfo_setup(vector& pi) {
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(osvi);
GetVersionEx(&osvi);
@@ -83,7 +102,7 @@ int get_procinfo(vector& pi) {
switch(osvi.dwPlatformId) {
case VER_PLATFORM_WIN32_WINDOWS:
// Win95, Win98, WinME
- return get_procinfo_9x(pi);
+ return get_procinfo_9X(pi);
case VER_PLATFORM_WIN32_NT:
switch(osvi.dwMajorVersion) {
case 4:
@@ -97,11 +116,53 @@ int get_procinfo(vector& pi) {
// WinVista
return get_procinfo_XP(pi);
} else {
- return get_procinfo_9x(pi);
+ return get_procinfo_9X(pi);
}
default:
- return get_procinfo_9x(pi);
+ return get_procinfo_9X(pi);
}
}
- return get_procinfo_9x(pi);
+ return get_procinfo_9X(pi);
}
+
+// scan the process table from the given point,
+// adding in CPU time and mem usage
+//
+void add_proc_totals(PROCINFO& pi, vector& piv, int pid, int start) {
+ unsigned int i;
+ for (i=start; i& piv) {
+ add_proc_totals(pi, piv, pi.id, 0);
+}
+
+void procinfo_other(PROCINFO& pi, vector& piv) {
+ unsigned int i;
+ memset(&pi, 0, sizeof(pi));
+ for (i=0; i
+
+
@@ -1772,6 +1776,10 @@
RelativePath="..\Client\pers_file_xfer.h"
>
+
+