From 17a4ab8db904385f9f8248b2e353651d3f4b73af Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 11 Dec 2012 16:05:40 -0800 Subject: [PATCH] David 11 Dec 2012 - Win process control (affects API and wrapper): Since Win doesn't have an API for process suspend/resume, we were suspending processes by 1) enumerating all the threads in the system (typically several thousand) 2) suspending those belonging to the given process The problem: for each thread, the code was calling a function in diagnostics_win.cpp to see if the thread was exempted from suspension. This check (which is unnecessary anyway if we're suspending another process) was surrounded by a semaphore acquire/release. The result: performance problems. It could take a minute to suspend the threads. Solution: 1) do the check for exemption only if we're suspending threads in our own process (i.e. from the API) 2) if we're suspending multiple processes, enumerate the threads only once, and see if each one belongs to any of the processes 3) have the wrapper elevate itself to normal priority. Otherwise it can get preempted for long periods, sometimes in the middle of scanning the threads. Note: post-9x versions of Win have a process group API that includes suspend/resume. We'll switch to this soon. --- api/boinc_api.cpp | 16 ++--- client/gpu_detect.cpp | 7 --- lib/proc_control.cpp | 116 ++++++++++++++++++++---------------- lib/proc_control.h | 6 +- lib/procinfo.cpp | 9 +-- lib/util.h | 7 +++ samples/wrapper/wrapper.cpp | 20 ++++++- 7 files changed, 104 insertions(+), 77 deletions(-) diff --git a/api/boinc_api.cpp b/api/boinc_api.cpp index 87bca9f2d5..2fe27dfb4c 100644 --- a/api/boinc_api.cpp +++ b/api/boinc_api.cpp @@ -860,10 +860,10 @@ int boinc_wu_cpu_time(double& cpu_t) { int suspend_activities() { #ifdef _WIN32 - static DWORD pid; - if (!pid) pid = GetCurrentProcessId(); + static vector pids; if (options.multi_thread) { - suspend_or_resume_threads(pid, timer_thread_id, false); + if (pids.size() == 0) pids.push_back(GetCurrentProcessId()); + suspend_or_resume_threads(pids, timer_thread_id, false, true); } else { SuspendThread(worker_thread_handle); } @@ -872,7 +872,7 @@ int suspend_activities() { // suspension is done by signal handler in worker thread // if (options.multi_process) { - suspend_or_resume_descendants(0, false); + suspend_or_resume_descendants(false); } #endif return 0; @@ -880,16 +880,16 @@ int suspend_activities() { int resume_activities() { #ifdef _WIN32 - static DWORD pid; - if (!pid) pid = GetCurrentProcessId(); + static vector pids; if (options.multi_thread) { - suspend_or_resume_threads(pid, timer_thread_id, true); + if (pids.size() == 0) pids.push_back(GetCurrentProcessId()); + suspend_or_resume_threads(pids, timer_thread_id, true, true); } else { ResumeThread(worker_thread_handle); } #else if (options.multi_process) { - suspend_or_resume_descendants(0, true); + suspend_or_resume_descendants(true); } #endif return 0; diff --git a/client/gpu_detect.cpp b/client/gpu_detect.cpp index a4879b98cb..4dce23dd3b 100644 --- a/client/gpu_detect.cpp +++ b/client/gpu_detect.cpp @@ -47,13 +47,6 @@ using std::string; using std::vector; -bool in_vector(int n, vector& v) { - for (unsigned int i=0; i& pids) { PROC_MAP::iterator i = pm.find(pid); if (i == pm.end()) return; @@ -67,64 +71,81 @@ void get_descendants(int pid, vector& pids) { retval = procinfo_setup(pm); if (retval) return; get_descendants_aux(pm, pid, pids); +#ifdef DEBUG + fprintf(stderr, "descendants of %d:\n", pid); + for (unsigned int i=0; ipids, DWORD calling_thread_id, bool resume, bool check_exempt ) { HANDLE threads, thread; - static HMODULE hKernel32Lib = NULL; THREADENTRY32 te = {0}; - static tOT pOT = NULL; - - // Dynamically link to the proper function pointers. - if (!hKernel32Lib) { - hKernel32Lib = GetModuleHandleA("kernel32.dll"); - } - if (!pOT) { - pOT = (tOT) GetProcAddress( hKernel32Lib, "OpenThread" ); - } - if (!pOT) { - return -1; +#ifdef DEBUG + fprintf(stderr, "start: check_exempt %d %s\n", check_exempt, precision_time_to_string(dtime())); + fprintf(stderr, "%s processes", resume?"resume":"suspend"); + for (unsigned int i=0; i& pids, bool resume) { - for (unsigned int i=0; i descendants; - if (!pid) { #ifdef _WIN32 - pid = GetCurrentProcessId(); -#else - pid = getpid(); -#endif - } + int pid = GetCurrentProcessId(); get_descendants(pid, descendants); - suspend_or_resume_all(descendants, resume); + suspend_or_resume_threads(descendants, 0, resume, false); +#else + int pid = getpid(); + get_descendants(pid, descendants); + for (unsigned int i=0; i pids; + pids.push_back(pid); + suspend_or_resume_threads(pids, 0, resume, false); #else ::kill(pid, resume?SIGCONT:SIGSTOP); #endif - } diff --git a/lib/proc_control.h b/lib/proc_control.h index c8a6df1c47..7dd84308c0 100644 --- a/lib/proc_control.h +++ b/lib/proc_control.h @@ -28,11 +28,13 @@ extern bool any_process_exists(std::vector& pids); extern void kill_all(std::vector& pids); #ifdef _WIN32 extern void kill_descendants(); -extern int suspend_or_resume_threads(DWORD pid, DWORD threadid, bool resume); +extern int suspend_or_resume_threads( + std::vector pids, DWORD threadid, bool resume, bool check_exempt +); #else extern void kill_descendants(int child_pid=0); #endif -extern void suspend_or_resume_descendants(int pid, bool resume); +extern void suspend_or_resume_descendants(bool resume); extern void suspend_or_resume_process(int pid, bool resume); #endif diff --git a/lib/procinfo.cpp b/lib/procinfo.cpp index ff1e9a02f7..3da3cc8844 100644 --- a/lib/procinfo.cpp +++ b/lib/procinfo.cpp @@ -31,6 +31,8 @@ #include #endif +#include "util.h" + #include "procinfo.h" using std::vector; @@ -64,13 +66,6 @@ void add_child_totals(PROCINFO& pi, PROC_MAP& pm, PROC_MAP::iterator i) { } } -static inline bool in_vector(int n, vector& v) { - for (unsigned int i=0; i& v) { + for (unsigned int i=0; i