diff --git a/checkin_notes b/checkin_notes index b13830da4c..e6c0f687f4 100755 --- a/checkin_notes +++ b/checkin_notes @@ -9957,3 +9957,36 @@ David 7 Sept 2006 client/ *.C + +David 8 Sept 2006 + - core client: frustrating attempt to get page fault rate on Windows. + It turns out that the "page fault count" reported by Windows + includes "soft" page faults that don't read from disk. + A typical process gets hundreds or thousands of these per second. + There doesn't seem to be a way to get a count + of real page faults. + + In any case: I added PROCINFO to the ACTIVE_TASK structure, + eliminating the need for the vm_nbytes and rss_bytes fields. + + Note: the reason I'm worrying about this is: + suppose an OS defines a process's "working set" + as the amount of RAM it currently has. + Then all running apps will appear to fit in RAM, + and our goal of avoiding thrashing will fail. + I was looking at page fault rate as a way to get around this. + + However: I ran across a note that says that Windows + defines "working set" as "the amount of memory needed + for the process to run efficiently". + If that's the case, we don't need to worry about page fault rate. + + client/ + app.C,h + app_control.C + cpu_sched.C + lib/ + procinfo.h + procinfo_win.C + win_build/ + boinc_cli_curl.vcproj diff --git a/client/app.C b/client/app.C index 195e5efb28..ebffe879ad 100644 --- a/client/app.C +++ b/client/app.C @@ -95,12 +95,11 @@ ACTIVE_TASK::ACTIVE_TASK() { checkpoint_cpu_time = 0; checkpoint_wall_time = 0; current_cpu_time = 0; - vm_bytes = 0; - rss_bytes = 0; have_trickle_down = false; send_upload_file_status = false; pending_suspend_via_quit = false; want_network = 0; + memset(&procinfo, 0, sizeof(procinfo)); #ifdef _WIN32 pid_handle = 0; thread_handle = 0; @@ -197,25 +196,28 @@ void ACTIVE_TASK_SET::get_memory_usage() { static double last_mem_time=0; unsigned int i; - if (gstate.now - last_mem_time < 10) return; + double diff = gstate.now - last_mem_time; + if (diff < 10) return; last_mem_time = gstate.now; vector piv; - PROCINFO pi; procinfo_setup(piv); for (i=0; itask_state == PROCESS_EXECUTING) { + PROCINFO& pi = atp->procinfo; + unsigned long last_page_fault_count = pi.page_fault_count; memset(&pi, 0, sizeof(pi)); pi.id = atp->pid; procinfo_app(pi, piv); - atp->rss_bytes = pi.working_set_size; - atp->vm_bytes = pi.swap_size; + int pf = pi.page_fault_count - last_page_fault_count; + pi.page_fault_rate = pf/diff; if (log_flags.mem_usage_debug) { msg_printf(NULL, MSG_INFO, - "[mem_usage_debug] %s: RAM %dKB, page %dKB, user CPU %f, kernel CPU %f", + "[mem_usage_debug] %s: RAM %dKB, page %dKB, %f page faults/sec, user CPU %f, kernel CPU %f", atp->result->name, (int)(pi.working_set_size/1024), (int)(pi.swap_size/1024), + pi.page_fault_rate, pi.user_time, pi.kernel_time ); } @@ -387,8 +389,9 @@ int ACTIVE_TASK::write(MIOFILE& fout) { " %f\n" " %f\n" " %f\n" - " %f\n" - " %f\n", + " %f\n" + " %f\n" + " %f\n", result->project->master_url, result->name, task_state, @@ -398,8 +401,9 @@ int ACTIVE_TASK::write(MIOFILE& fout) { checkpoint_cpu_time, fraction_done, current_cpu_time, - vm_bytes, - rss_bytes + procinfo.swap_size, + procinfo.working_set_size, + procinfo.page_fault_rate ); if (supports_graphics() && !gstate.disable_graphics) { fout.printf( @@ -489,8 +493,9 @@ int ACTIVE_TASK::parse(MIOFILE& fin) { else if (parse_double(buf, "", fraction_done)) continue; else if (parse_double(buf, "", current_cpu_time)) continue; else if (parse_int(buf, "", n)) continue; - else if (parse_double(buf, "", vm_bytes)) continue; - else if (parse_double(buf, "", rss_bytes)) continue; + else if (parse_double(buf, "", procinfo.swap_size)) continue; + else if (parse_double(buf, "", procinfo.working_set_size)) continue; + else if (parse_double(buf, "", procinfo.page_fault_rate)) continue; else if (match_tag(buf, "")) continue; else if (parse_int(buf, "", n)) continue; else if (parse_int(buf, "", n)) continue; diff --git a/client/app.h b/client/app.h index be17203f04..af64275ea3 100644 --- a/client/app.h +++ b/client/app.h @@ -27,6 +27,7 @@ #include "client_types.h" #include "app_ipc.h" +#include "procinfo.h" class CLIENT_STATE; typedef int PROCESS_ID; @@ -82,7 +83,9 @@ public: WORKUNIT* wup; APP_VERSION* app_version; PROCESS_ID pid; - int slot; // which slot (determines directory) + PROCINFO procinfo; + + int slot; // subdirectory of slots/ where this runs int task_state; int scheduler_state; int next_scheduler_state; // temp @@ -103,10 +106,6 @@ public: // wall time at the last checkpoint double current_cpu_time; // most recent CPU time reported by app - double vm_bytes; - // swap space used - double rss_bytes; - // working set size int current_disk_usage(double&); // disk used by output files and temp files of this task char slot_dir[256]; // directory where process runs diff --git a/client/app_control.C b/client/app_control.C index 659699e02a..7cf6087942 100644 --- a/client/app_control.C +++ b/client/app_control.C @@ -468,12 +468,12 @@ bool ACTIVE_TASK::check_max_disk_exceeded() { } bool ACTIVE_TASK::check_max_mem_exceeded() { - if (max_mem_usage != 0 && rss_bytes > max_mem_usage) { + if (max_mem_usage != 0 && procinfo.working_set_size > max_mem_usage) { if (log_flags.mem_usage_debug) { msg_printf( result->project, MSG_INFO, "[mem_usage_debug] Task %s: memory usage %f exceeds limit %f\n", - result->name, rss_bytes, max_mem_usage + result->name, procinfo.working_set_size, max_mem_usage ); } //abort_task(ERR_RSC_LIMIT_EXCEEDED, "Maximum memory usage exceeded"); @@ -490,7 +490,7 @@ bool ACTIVE_TASK_SET::vm_limit_exceeded(double vm_limit) { for (i=0; iprocess_exists()) continue; - total_vm_usage += atp->vm_bytes; + total_vm_usage += atp->procinfo.swap_size; } return (total_vm_usage > vm_limit); diff --git a/client/cpu_sched.C b/client/cpu_sched.C index c1207cb281..315dada0a5 100644 --- a/client/cpu_sched.C +++ b/client/cpu_sched.C @@ -615,17 +615,17 @@ bool CLIENT_STATE::enforce_schedule() { // the scheduled result is already running. // see if it fits in mem // - if (mem_used + atp->rss_bytes > max_mem_used) { + if (mem_used + atp->procinfo.working_set_size > max_mem_used) { atp->next_scheduler_state = CPU_SCHED_PREEMPTED; nrunning--; if (log_flags.mem_usage_debug) { msg_printf(rp->project, MSG_INFO, "[mem_usage_debug] enforce: result %s mem1 %f %f %f", - rp->name, mem_used, atp->rss_bytes, max_mem_used + rp->name, mem_used, atp->procinfo.working_set_size, max_mem_used ); } } else { - mem_used += atp->rss_bytes; + mem_used += atp->procinfo.working_set_size; continue; } } @@ -635,11 +635,11 @@ bool CLIENT_STATE::enforce_schedule() { // atp = active_tasks.lookup_result(rp); if (atp) { - if (mem_used + atp->rss_bytes > max_mem_used) { + if (mem_used + atp->procinfo.working_set_size > max_mem_used) { if (log_flags.mem_usage_debug) { msg_printf(rp->project, MSG_INFO, "[mem_usage_debug] enforce: result %s mem2 %f %f %f", - rp->name, mem_used, atp->rss_bytes, max_mem_used + rp->name, mem_used, atp->procinfo.working_set_size, max_mem_used ); } continue; @@ -685,7 +685,7 @@ bool CLIENT_STATE::enforce_schedule() { atp = get_task(rp); atp->next_scheduler_state = CPU_SCHED_SCHEDULED; nrunning++; - mem_used += atp->rss_bytes; + mem_used += atp->procinfo.working_set_size; } } @@ -693,16 +693,16 @@ bool CLIENT_STATE::enforce_schedule() { // for (i=0; irss_bytes > max_mem_used) { + if (mem_used + atp->procinfo.working_set_size > max_mem_used) { atp->next_scheduler_state = CPU_SCHED_PREEMPTED; if (log_flags.mem_usage_debug) { msg_printf(atp->result->project, MSG_INFO, "[mem_usage_debug] enforce: result %s mem3 %f %f %f", - atp->result->name, mem_used, atp->rss_bytes, max_mem_used + atp->result->name, mem_used, atp->procinfo.working_set_size, max_mem_used ); } } else { - mem_used += atp->rss_bytes; + mem_used += atp->procinfo.working_set_size; } } diff --git a/lib/procinfo.h b/lib/procinfo.h index fab04a677d..271b034fb0 100644 --- a/lib/procinfo.h +++ b/lib/procinfo.h @@ -1,3 +1,25 @@ +// Berkeley Open Infrastructure for Network Computing +// http://boinc.berkeley.edu +// Copyright (C) 2005 University of California +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// either version 2.1 of the License, or (at your option) any later version. +// +// This software 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 Lesser General Public License for more details. +// +// To view the GNU Lesser General Public License visit +// http://www.gnu.org/copyleft/lesser.html +// or write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +#ifndef _PROCINFO_ +#define _PROCINFO_ + #include struct PROCINFO { @@ -5,9 +27,12 @@ struct PROCINFO { int parentid; double swap_size; double working_set_size; + unsigned long page_fault_count; double user_time; double kernel_time; bool is_boinc_app; + + double page_fault_rate; // derived by higher-level code }; extern int procinfo_setup(std::vector&); @@ -18,3 +43,5 @@ extern void procinfo_app(PROCINFO&, std::vector&); extern void procinfo_other(PROCINFO&, std::vector&); // After getting mem usage for all BOINC apps, // call this to get mem usage for everything else + +#endif \ No newline at end of file diff --git a/lib/procinfo_win.C b/lib/procinfo_win.C index c2faafb3d3..e550a1fa61 100644 --- a/lib/procinfo_win.C +++ b/lib/procinfo_win.C @@ -67,6 +67,7 @@ int get_procinfo_XP(vector& pi) { p.parentid = pProcesses->InheritedFromProcessId; p.swap_size = pProcesses->VmCounters.PagefileUsage; p.working_set_size = pProcesses->VmCounters.WorkingSetSize; + p.page_fault_count = pProcesses->VmCounters.PageFaultCount; p.user_time = ((double) pProcesses->UserTime.QuadPart)/1e7; p.kernel_time = ((double) pProcesses->KernelTime.QuadPart)/1e7; p.id = pProcesses->ProcessId; @@ -137,6 +138,7 @@ void add_proc_totals(PROCINFO& pi, vector& piv, int pid, int start) { pi.user_time += p.user_time; pi.swap_size += p.swap_size; pi.working_set_size += p.working_set_size; + pi.page_fault_count += p.page_fault_count; p.is_boinc_app = true; } if (p.parentid == pid) { diff --git a/win_build/boinc_cli_curl.vcproj b/win_build/boinc_cli_curl.vcproj index 4e5be20006..91d3351ce6 100644 --- a/win_build/boinc_cli_curl.vcproj +++ b/win_build/boinc_cli_curl.vcproj @@ -1724,6 +1724,10 @@ RelativePath="..\client\dhrystone.h" > + +