PDA

View Full Version : Win32 client isn't really idle



Troodon
01-22-2003, 11:22 AM
I've done a little research about the idle problem (http://www.free-dc.org/forum/showthread.php?threadid=2254&perpage=25&pagenumber=1). Althought Windows task manager shows sb.exe as having the lowest priority, that's not true.
I discovered that SB client's "idle" setting equals to priority=4 in Euler2000 (CPU distribution ~50%). If I run Euler2000 with a lower setting, SB takes all the (free) CPU power. If I run Euler2000 with prority=4, I have the same problems (temporary freezes, client's CPU use climbs to 99%) as I have when I run SB.
And, funny, if I run Euler2000 with the lowest priority (1, no problems), the task manager show its prority as normal :) .

Hawk
01-22-2003, 11:53 AM
The reason is that both threads and processes have priorities. If you set a process to idle, then its threads get set to priority 4, which should be low enough to cause no noticeable problems usually.

You can also set thread priority (which is what Euler is doing) which allows you to precisely specify the priority, but it doesn't change the process priority (which is why it still shows as Normal where SB shows Idle).

Troodon
01-22-2003, 04:49 PM
Originally posted by Hawk
The reason is that both threads and processes have priorities. If you set a process to idle, then its threads get set to priority 4, which should be low enough to cause no noticeable problems usually.
4 it's not low enough. For me, idle means lowest priority, and that's 1.


You can also set thread priority (which is what Euler is doing) which allows you to precisely specify the priority, but it doesn't change the process priority (which is why it still shows as Normal where SB shows Idle).
I think Euler's way is better and offers more control to the user.

Thanks!

jjjjL
01-22-2003, 06:08 PM
The SB process runs at idle. It has always been that way.

As of version 1, SB DOES set it's computation thread's priority to the lowest possible using standard API calls. Euler must use some undocumented hack to set priority.

-Louie

MathGuy
01-22-2003, 06:44 PM
Probably the best way to check ACTUAL priority is with Spy++ or some similar tool. If you do this, you will find that, with SB set to its "Idle" config, the UI thread has a base priority of 4 and the computation thread has a base priority of 2. This corresponds (Microsoft documentation) to a process priority of IDLE_PRIORITY_CLASS and a thread priority of THREAD_PRIORITY_LOWEST. However, THREAD_PRIORITY_LOWEST really just means "2 points below the process class" and it really isn't the "lowest" priority (don't ask me why they called it that...they didn't ask me). There is a "lower than lowest" thread priority: THREAD_PRIORITY_IDLE which is always priority 1 (unless the process has REALTIME priority).

My guess (can you confirm this, Louie?) is that the config setting is used to set the process priority class and then the computation thread is set to THREAD_PRIORITY_LOWEST. This would at least correspond to what I've seen in the few cases I've looked at.

If this is the case, you might consider dropping that THREAD_PRIORITY_LOWEST to THREAD_PRIORITY_IDLE only when the config setting is set to idle.

OTOH, it works great for me as it is...but I'm not running any other DC clients that I need to split time with.

jjjjL
01-22-2003, 07:24 PM
Thanks MathGuy. I think you're completely right.

Actually, looking though the code, it appears I consciously decided not to use THREAD_PRIORITY_IDLE back in November when I compiled it:

SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
// SetThreadPriority(cfg->worker_thread, THREAD_PRIORITY_IDLE); too low
SetThreadPriority(cfg->worker_thread, THREAD_PRIORITY_LOWEST);

I seem to remember getting reports that THREAD_PRIORITY_IDLE yields to the idle thread on WinNT back when I was testing v1. Most DC projects don't run at priority 1 from what I can tell. I know that everything I've ever run with it at idle (I haven't tried Euler2000) shares cycles 1 for 1 with SB as is.

I'll probably add an option in the next version that warn users they may stop SB completely by setting it to complete idle.


-Louie

Troodon
01-22-2003, 07:44 PM
Thanks MathGuy and Louie! I think the best solution would be to use by default THREAD_PRIORITY_LOWEST and let the user to choose THREAD_PRIORITY_IDLE.
Here is the code other clients use for setting priority:

a) Sum95 (Euler2000)

void SetPriority(HANDLE thread)
{
SetPriorityClass (GetCurrentProcess (),
(PRIORITY < 2 || PRIORITY > 6) ?
NORMAL_PRIORITY_CLASS :
IDLE_PRIORITY_CLASS);

SetThreadPriority (thread,
(PRIORITY == 1) ? THREAD_PRIORITY_IDLE :
(PRIORITY == 2 || PRIORITY == 7) ? THREAD_PRIORITY_LOWEST :
(PRIORITY == 3 || PRIORITY == 8) ? THREAD_PRIORITY_BELOW_NORMAL :
(PRIORITY == 4 || PRIORITY == 9) ? THREAD_PRIORITY_NORMAL :
(PRIORITY == 5 || PRIORITY == 10) ? THREAD_PRIORITY_ABOVE_NORMAL :
THREAD_PRIORITY_HIGHEST);
if (CPU_AFFINITY != 99 && !isWindows95 ())
SetThreadAffinityMask (thread, 1 << CPU_AFFINITY);
}


b) Distributed.net 20010416

#elif (CLIENT_OS == OS_WIN32)
{
static int useidleclass = -1; // track detection state.
int threadprio = 0, classprio = 0;
HANDLE our_thrid = GetCurrentThread(); // Win32 pseudo-handle constant.

if (set_for_thread && (w32ConGetType() & 0xff)=='G')
{ // crunchers in a 'fat-'GUI client always run at idle prio
prio = 0;
}

/*************************** Article ID: Q106253 *******************
process priority class
THREAD_PRIORITY Normal, in Normal, in
Idle Background Foreground High Realtime
_TIME_CRITICAL 15 15 15 15 31
_HIGHEST 6 9 11 15 26
_ABOVE_NORMAL 5 8 10 14 25
_NORMAL 4 7 9 13 24
_BELOW_NORMAL 3 6 8 12 23
_LOWEST 2 5 7 11 22
_IDLE 1 1 1 1 16
********************************************************************/

/* If we want to run with an idle priority *class*, we need to be able
to set a *thread* priority of _TIME_CRITICAL for the main and
window-handler threads, otherwise I/O will be laggy beyond belief.

If we cannot set _TIME_CRITICAL, then we have no choice but to use a
NORMAL_PRIO_CLASS. Such is win32 scheduling; stupid, stupid, stupid.
*/
if (useidleclass == -1) /* haven't selected yet */
{
SetPriorityClass( GetCurrentProcess(), IDLE_PRIORITY_CLASS );
Sleep(1);
SetThreadPriority( our_thrid, THREAD_PRIORITY_TIME_CRITICAL);
if (GetThreadPriority( our_thrid ) == THREAD_PRIORITY_TIME_CRITICAL)
useidleclass = 1;
else
{
useidleclass = 0;
SetPriorityClass( GetCurrentProcess(), NORMAL_PRIORITY_CLASS );
Sleep(1);
}
SetThreadPriority( our_thrid, THREAD_PRIORITY_NORMAL );
}

if (useidleclass == 1)
{
classprio = IDLE_PRIORITY_CLASS;
if (!set_for_thread) threadprio = THREAD_PRIORITY_TIME_CRITICAL;/* 15 */
else if (prio >= 7) threadprio = THREAD_PRIORITY_HIGHEST; /* 6 */
else if (prio >= 5) threadprio = THREAD_PRIORITY_ABOVE_NORMAL; /* 5 */
else if (prio >= 4) threadprio = THREAD_PRIORITY_NORMAL; /* 4 */
else if (prio >= 3) threadprio = THREAD_PRIORITY_BELOW_NORMAL; /* 3 */
else if (prio >= 2) threadprio = THREAD_PRIORITY_LOWEST; /* 2 */
else /* prio < 2 */ threadprio = THREAD_PRIORITY_IDLE; /* 1 */
}
else /* if (useidleclass == 0) */
{
classprio = NORMAL_PRIORITY_CLASS;
if (!set_for_thread) threadprio = THREAD_PRIORITY_NORMAL; /* 8 */
else if (prio >= 7) threadprio = THREAD_PRIORITY_BELOW_NORMAL; /* 6 */
else if (prio >= 5) threadprio = THREAD_PRIORITY_LOWEST; /* 5 */
else threadprio = THREAD_PRIORITY_IDLE; /* 1 */
}
//SetPriorityClass( GetCurrentProcess(), classprio );
//Sleep(1);

SetThreadPriority( our_thrid, threadprio );
}

smh
01-24-2003, 03:58 AM
It would be great if a future client has the abbility to set the priority level (i,e, 1-10) instead of idle, low, below normal, normal)