It's a little better in Windows 8, but when I rebuild my homeserver I went back to 7. I could have moved on to 8, but Microsoft's 'privacy' rules and 'automatic enforced updates' are not entirely my cup of tea.
The Microsoft task scheduler on Windows 7 (and 8, and perhaps 10) makes a few assumptions, such as 'n minutes with CPU activity lower than 10%' equals idling. This causes some troubles if you want to use a scheduled task to enforce a sleep or standby.
I understand it is pretty hard to detect sleep / idling mode on homeservers. For example, my homeserver is a simple but recent Pentium, and when serving music for example (running Logitech Squeezebox Server) the actual CPU load is so low that the system does detect it as idle.
I have been trying to cook up something that uses multiple different detection schemes as a kind of idle detection, but not yet with much success.
Anyone have any suggestions?
I am able to detect idling time versus kernel time (using the GetSystemTimes WinApi) but activity is so low, that I talk out things like 'idling 99.9% of the time means the PC has nothing to do, idling 99.8% means something is still going on'.
Does anyone have any additional suggestions for additional detection mechanisms? Possibilities... disk activity, memory activity... what else?
My currect code looks like this (ugly and uses some procedures that you can easily take out):
Code: Select all
EnableExplicit
IncludeFile("..\x_lib\x_lib.pb")
x_init()
;
Global kernel_nr.i
Global kernel_h.i
Global p_getsystemtimes.i
Global idle.FILETIME
Global kernel.FILETIME
Global user.FILETIME
Global idletime.q, kerneltime.q, usertime.q, totaltime.q
Global idletime_now.q, kerneltime_now.q, usertime_now.q
Global idletime_old.q, kerneltime_old.q, usertime_old.q
Global fast.q, smooth.q, tick.q, count.q, cputreshold.i, idleperiod.q
Global time.q, time_old.q, ticktime.q, downfactor.i, scanperiod.i, smoothfactor.i
Global event.i
Enumeration
#tick_title_nr
#tick_bar_nr
#tick_val_nr
#kernel_title_nr
#kernel_bar_nr
#kernel_val_nr
#smooth_title_nr
#smooth_bar_nr
#smooth_val_nr
#count_title_nr
#count_bar_nr
#count_val_nr
EndEnumeration
;
kernel_nr = 1
kernel_h = OpenLibrary(kernel_nr,"KERNEL32.DLL")
p_getsystemtimes = GetFunction(kernel_nr,"GetSystemTimes")
;
OpenWindow(1,100,100,280,110,"Idle Scanner")
ProgressBarGadget(#tick_bar_nr,45,5,170,20,0,1000)
ProgressBarGadget(#kernel_bar_nr,45,30,170,20,0,1000)
ProgressBarGadget(#smooth_bar_nr,45,55,170,20,0,1000)
ProgressBarGadget(#count_bar_nr,45,80,170,20,0,1000)
TextGadget(#tick_title_nr,5,10,40,20,"Tick")
TextGadget(#kernel_title_nr,5,35,40,20,"Kernel")
TextGadget(#smooth_title_nr,5,60,40,20,"Idle")
TextGadget(#count_title_nr,5,85,40,20,"Period")
TextGadget(#tick_val_nr,220,10,50,20,"")
TextGadget(#kernel_val_nr,220,35,50,20,"")
TextGadget(#smooth_val_nr,220,60,50,20,"")
TextGadget(#count_val_nr,220,85,50,20,"")
;
cputreshold = 796 ; minimal idle level in promille (1000 = 100%)
idleperiod = 5 * 60 ; scanperiod system must be idle before considered really idle, in seconds
downfactor = 10 ; ramp quicker down when activity detected
scanperiod = 2000 ; scanperiod, period between each check, affects ramping up / down, in milliseconds
smoothfactor = 10 ; average samples over a number of scanperiods
;
idleperiod = idleperiod*1000/scanperiod
;
Repeat
event = WaitWindowEvent(scanperiod)
time = x_timer()
ticktime = time - time_old
If ticktime > scanperiod
time_old = time
;
CallFunctionFast(p_getsystemtimes,@idle,@kernel,@user)
PokeL(@idletime_now,PeekL(@idle\dwLowDateTime))
PokeL(@idletime_now+4,PeekL(@idle\dwHighDateTime))
PokeL(@kerneltime_now,PeekL(@kernel\dwLowDateTime))
PokeL(@kerneltime_now+4,PeekL(@kernel\dwHighDateTime))
idletime = x_max(1,( idletime_now - idletime_old ) / 32768)
kerneltime = x_max(1, ( kerneltime_now - kerneltime_old ) / 32768)
idletime_old = idletime_now
kerneltime_old = kerneltime_now
;
tick = kerneltime * 1000 / ticktime
fast = idletime * 1000 / kerneltime
smooth = ( smooth * smoothfactor - smooth - smooth + tick + fast + 1 ) / smoothfactor
If smooth < cputreshold
count = count - downfactor
SetGadgetColor(#smooth_val_nr,#PB_Gadget_FrontColor,RGB(255,0,0))
If count <= 0
count = 0
SetGadgetColor(#count_val_nr,#PB_Gadget_FrontColor,RGB(255,0,0))
EndIf
Else
count = count + 1
SetGadgetColor(#smooth_val_nr,#PB_Gadget_FrontColor,#PB_Default)
If count >= ( idleperiod * 1000 / scanperiod )
count = idleperiod
SetGadgetColor(#count_val_nr,#PB_Gadget_FrontColor,#PB_Default)
SetWindowColor(1,RGB(255,0,0))
EndIf
EndIf
;
SetGadgetState(#tick_bar_nr,tick)
SetGadgetState(#kernel_bar_nr,fast)
SetGadgetState(#smooth_bar_nr,smooth)
SetGadgetState(#count_bar_nr,1000*count/idleperiod)
SetGadgetText(#tick_val_nr,x_strex(tick," #.#")+"%")
SetGadgetText(#kernel_val_nr,x_strex(fast," #.#")+"%")
SetGadgetText(#smooth_val_nr,x_strex(smooth," #.#")+"%")
SetGadgetText(#count_val_nr,x_strex(1000*count/idleperiod," #.#")+"%")
;
EndIf
Until event = #PB_Event_CloseWindow