Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

697 lines
20 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1998 - 2000.
  5. //
  6. // File: LowRes.cxx
  7. //
  8. // Contents: Default low-resource detection
  9. //
  10. // Classes: CLowRes
  11. // CUserActivityMonitor
  12. //
  13. // History: 21-Jul-98 KyleP Created
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.cxx>
  17. #pragma hdrstop
  18. #include <frmutils.hxx>
  19. #include <pageman.hxx>
  20. #include "lowres.hxx"
  21. CLowRes::CLowRes( CCiFrameworkParams & params )
  22. : _cRefs(1),
  23. _params( params ),
  24. _UserMon( )
  25. {
  26. //
  27. // Compute pages-per-meg for use in low memory computations.
  28. //
  29. SYSTEM_BASIC_INFORMATION Basic;
  30. NTSTATUS Status = NtQuerySystemInformation( SystemBasicInformation,
  31. &Basic,
  32. sizeof(Basic),
  33. 0 );
  34. if ( SUCCEEDED(Status) )
  35. {
  36. _ulPagesPerMeg = 1024*1024 / Basic.PageSize;
  37. _ulPageSize = Basic.PageSize;
  38. }
  39. else
  40. {
  41. _ulPagesPerMeg = 1024*1024 / PAGE_SIZE;
  42. _ulPageSize = PAGE_SIZE;
  43. }
  44. }
  45. //+-------------------------------------------------------------------------
  46. //
  47. // Method: CLowRes::AddRef
  48. //
  49. // Synopsis: Increments refcount
  50. //
  51. // History: 21-Jul-1998 KyleP Created
  52. //
  53. //--------------------------------------------------------------------------
  54. ULONG STDMETHODCALLTYPE CLowRes::AddRef()
  55. {
  56. return InterlockedIncrement( &_cRefs );
  57. }
  58. //+-------------------------------------------------------------------------
  59. //
  60. // Method: CLowRes::Release
  61. //
  62. // Synopsis: Decrement refcount. Delete if necessary.
  63. //
  64. // History: 21-Jul-1998 KyleP Created
  65. //
  66. //--------------------------------------------------------------------------
  67. ULONG STDMETHODCALLTYPE CLowRes::Release()
  68. {
  69. Win4Assert( _cRefs > 0 );
  70. ULONG uTmp = InterlockedDecrement( (long *) &_cRefs );
  71. if ( 0 == uTmp )
  72. delete this;
  73. return uTmp;
  74. }
  75. //+-------------------------------------------------------------------------
  76. //
  77. // Method: CLowRes::QueryInterface
  78. //
  79. // Synopsis: Rebind to other interface
  80. //
  81. // Arguments: [riid] -- IID of new interface
  82. // [ppvObject] -- New interface * returned here
  83. //
  84. // Returns: S_OK if bind succeeded, E_NOINTERFACE if bind failed
  85. //
  86. // History: 21-Jul-1998 KyleP Created
  87. //
  88. //--------------------------------------------------------------------------
  89. SCODE STDMETHODCALLTYPE CLowRes::QueryInterface( REFIID riid,
  90. void ** ppvObject)
  91. {
  92. IUnknown *pUnkTemp = 0;
  93. SCODE sc = S_OK;
  94. *ppvObject = 0;
  95. if ( IID_ICiCResourceMonitor == riid )
  96. pUnkTemp = (IUnknown *)(ICiCResourceMonitor *) this;
  97. else if ( IID_IUnknown == riid )
  98. pUnkTemp = (IUnknown *) this;
  99. else
  100. sc = E_NOINTERFACE;
  101. *ppvObject = (void *) pUnkTemp;
  102. if( 0 != pUnkTemp )
  103. pUnkTemp->AddRef();
  104. return sc;
  105. } //QueryInterface
  106. //+-------------------------------------------------------------------------
  107. //
  108. // Method: CLowRes::IsMemoryLow, public
  109. //
  110. // Returns: S_OK if memory is low, S_FALSE if it is not.
  111. //
  112. // History: 21-Jul-1998 KyleP Created
  113. //
  114. //--------------------------------------------------------------------------
  115. SCODE CLowRes::IsMemoryLow()
  116. {
  117. SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
  118. NTSTATUS Status = NtQuerySystemInformation( SystemPerformanceInformation,
  119. &PerfInfo,
  120. sizeof(PerfInfo),
  121. 0 );
  122. if ( SUCCEEDED(Status) )
  123. {
  124. ULONG ulFreeMeg = (PerfInfo.CommitLimit - PerfInfo.CommittedPages) / _ulPagesPerMeg;
  125. if ( ulFreeMeg < _params.GetMinWordlistMemory() )
  126. Status = S_OK;
  127. else
  128. Status = S_FALSE;
  129. }
  130. else
  131. Status = E_FAIL;
  132. return Status;
  133. }
  134. //+-------------------------------------------------------------------------
  135. //
  136. // Method: CLowRes::IsBatterLow, public
  137. //
  138. // Returns: S_OK if battery power is low, S_FALSE if it is not.
  139. //
  140. // History: 21-Jul-1998 KyleP Created
  141. //
  142. //--------------------------------------------------------------------------
  143. SCODE CLowRes::IsBatteryLow()
  144. {
  145. SCODE sc = S_OK;
  146. SYSTEM_POWER_STATUS PowerStatus;
  147. ULONG ulMinBattery = _params.GetMinWordlistBattery();
  148. if ( 0 == ulMinBattery )
  149. sc = S_FALSE;
  150. else if ( GetSystemPowerStatus( &PowerStatus ) )
  151. {
  152. if ( ( AC_LINE_ONLINE == PowerStatus.ACLineStatus ) ||
  153. ( ( BATTERY_FLAG_UNKNOWN != PowerStatus.BatteryFlag ) &&
  154. ( 0 == (PowerStatus.BatteryFlag & BATTERY_FLAG_NO_BATTERY) ) &&
  155. ( BATTERY_PERCENTAGE_UNKNOWN != PowerStatus.BatteryLifePercent ) &&
  156. ( PowerStatus.BatteryLifePercent > ulMinBattery ) ) )
  157. {
  158. sc = S_FALSE;
  159. }
  160. }
  161. else
  162. {
  163. ciDebugOut(( DEB_IWARN, "GetSystemPowerStatus returned %u\n", GetLastError() ));
  164. sc = HRESULT_FROM_WIN32( GetLastError() );
  165. }
  166. return sc;
  167. }
  168. //+-------------------------------------------------------------------------
  169. //
  170. // Method: CLowRes::IsOnBatterPower, public
  171. //
  172. // Returns: S_OK if on battery power is low, S_FALSE if it is not.
  173. //
  174. // History: 01-Oct-2000 dlee Created
  175. //
  176. //--------------------------------------------------------------------------
  177. SCODE CLowRes::IsOnBatteryPower()
  178. {
  179. SCODE sc = S_OK;
  180. SYSTEM_POWER_STATUS PowerStatus;
  181. if ( GetSystemPowerStatus( &PowerStatus ) )
  182. {
  183. if ( AC_LINE_ONLINE == PowerStatus.ACLineStatus )
  184. sc = S_FALSE;
  185. }
  186. else
  187. {
  188. ciDebugOut(( DEB_IWARN, "GetSystemPowerStatus returned %u\n", GetLastError() ));
  189. sc = HRESULT_FROM_WIN32( GetLastError() );
  190. }
  191. return sc;
  192. } //IsOnBatteryPower
  193. //+-------------------------------------------------------------------------
  194. //
  195. // Method: CLowRes::IsUserActive, public
  196. //
  197. // Arguments: [fCheckLongTerm] - TRUE if long-term activity should be checked.
  198. // Otherwise, short-term activity is checked.
  199. //
  200. // Returns: S_OK if user is typing or mousing, S_FALSE if it is not.
  201. //
  202. // History: 29 Jul 1998 AlanW Created
  203. //
  204. //--------------------------------------------------------------------------
  205. SCODE CLowRes::IsUserActive( BOOL fCheckLongTerm)
  206. {
  207. const cIdleThreshold = 5;
  208. SCODE sc = S_OK;
  209. const ULONG ulIdleDetectInterval = _params.GetWordlistUserIdle() * 1000;
  210. if ( 0 == ulIdleDetectInterval )
  211. sc = S_FALSE;
  212. else if ( fCheckLongTerm )
  213. {
  214. if ( _UserMon.GetUserActivity( ulIdleDetectInterval ) <=
  215. cIdleThreshold )
  216. sc = S_FALSE;
  217. }
  218. else
  219. {
  220. if ( _UserMon.GetUserActivity( 500 ) == 0 )
  221. sc = S_FALSE;
  222. }
  223. return sc;
  224. }
  225. //+-------------------------------------------------------------------------
  226. //
  227. // Method: CLowRes::SampleUserActivity, public
  228. //
  229. // Returns: S_OK
  230. //
  231. // History: 29 Jul 1998 AlanW Created
  232. //
  233. //--------------------------------------------------------------------------
  234. SCODE CLowRes::SampleUserActivity()
  235. {
  236. _UserMon.SampleUserActivity();
  237. return S_OK;
  238. }
  239. //+-------------------------------------------------------------------------
  240. //
  241. // Method: CLowRes::IsIoHigh, public
  242. //
  243. // Returns: S_OK if system is in a high i/o state, S_FALSE if it is not.
  244. //
  245. // History: 21-Jul-1998 KyleP Created
  246. //
  247. //--------------------------------------------------------------------------
  248. SCODE CLowRes::IsIoHigh( BOOL * pfAbort )
  249. {
  250. //
  251. // If the user doesn't care about checking IO, don't spend any time here
  252. //
  253. if ( 0xffffffff == _params.GetMaxWordlistIo() )
  254. return S_FALSE;
  255. unsigned const cSecSample = 5;
  256. SCODE scRet = S_FALSE;
  257. SYSTEM_PERFORMANCE_INFORMATION PerfInfo[2];
  258. NTSTATUS Status = NtQuerySystemInformation( SystemPerformanceInformation,
  259. &PerfInfo[0],
  260. sizeof(PerfInfo),
  261. 0 );
  262. if ( NT_SUCCESS(Status) )
  263. {
  264. //
  265. // Alertable sleep. Sleep for about 5 seconds total in 200ms increments.
  266. //
  267. // NOTE: When it's about time for the tick count to wrap, dwEndTicks
  268. // could be less than the initial value of dwSleepTicks, which
  269. // simply means that we could misdiagnose whether the machine is
  270. // busy about once in 49 days.
  271. //
  272. DWORD dwSleepTicks = GetTickCount();
  273. DWORD dwEndTicks = dwSleepTicks + cSecSample * 1000;
  274. while ( dwSleepTicks < dwEndTicks )
  275. {
  276. if ( *pfAbort )
  277. break;
  278. _UserMon.SampleUserActivity();
  279. DWORD dwCurrentTicks = GetTickCount();
  280. if ( dwCurrentTicks >= dwEndTicks )
  281. break;
  282. dwSleepTicks += 200;
  283. if ( dwCurrentTicks < dwSleepTicks )
  284. {
  285. //Win4Assert( dwSleepTicks - dwCurrentTicks <= 200 );
  286. Sleep( dwSleepTicks - dwCurrentTicks );
  287. }
  288. }
  289. Status = NtQuerySystemInformation( SystemPerformanceInformation,
  290. &PerfInfo[1],
  291. sizeof(PerfInfo),
  292. 0 );
  293. if ( NT_SUCCESS(Status) )
  294. {
  295. Win4Assert( PerfInfo[1].IoReadTransferCount.QuadPart >= PerfInfo[0].IoReadTransferCount.QuadPart );
  296. Win4Assert( PerfInfo[1].IoWriteTransferCount.QuadPart >= PerfInfo[0].IoWriteTransferCount.QuadPart );
  297. Win4Assert( PerfInfo[1].IoOtherTransferCount.QuadPart >= PerfInfo[0].IoOtherTransferCount.QuadPart );
  298. Win4Assert( PerfInfo[1].PageReadCount >= PerfInfo[0].PageReadCount );
  299. Win4Assert( PerfInfo[1].CacheReadCount >= PerfInfo[0].CacheReadCount );
  300. Win4Assert( PerfInfo[1].DirtyPagesWriteCount >= PerfInfo[0].DirtyPagesWriteCount );
  301. Win4Assert( PerfInfo[1].MappedPagesWriteCount >= PerfInfo[0].MappedPagesWriteCount );
  302. LONGLONG cIo = PerfInfo[1].IoReadTransferCount.QuadPart - PerfInfo[0].IoReadTransferCount.QuadPart;
  303. cIo += PerfInfo[1].IoWriteTransferCount.QuadPart - PerfInfo[0].IoWriteTransferCount.QuadPart;
  304. //
  305. // This doesn't work when a Jaz drive is in the system.
  306. //
  307. //cIo += PerfInfo[1].IoOtherTransferCount.QuadPart - PerfInfo[0].IoOtherTransferCount.QuadPart;
  308. cIo += (PerfInfo[1].PageReadCount - PerfInfo[0].PageReadCount) * _ulPageSize;
  309. cIo += (PerfInfo[1].CacheReadCount - PerfInfo[0].CacheReadCount) * _ulPageSize;
  310. cIo += (PerfInfo[1].DirtyPagesWriteCount - PerfInfo[0].DirtyPagesWriteCount) * _ulPageSize;
  311. cIo += (PerfInfo[1].MappedPagesWriteCount - PerfInfo[0].MappedPagesWriteCount) * _ulPageSize;
  312. if ( cIo >= _params.GetMaxWordlistIo() * 1024 * cSecSample )
  313. {
  314. ciDebugOut(( DEB_ITRACE, "IsIoHigh: %u bytes in %u seconds is HIGH (more than %u bytes/sec)\n",
  315. cIo, cSecSample, _params.GetMaxWordlistIo() * 1024 ));
  316. scRet = S_OK;
  317. }
  318. }
  319. }
  320. return scRet;
  321. }
  322. //+-------------------------------------------------------------------------
  323. //
  324. // Method: CUserActivityMonitor::SampleUserActivity, public
  325. //
  326. // Synopsis: Check to see if the user has used the keyboard or mouse
  327. //
  328. // Returns: - nothing -
  329. //
  330. // History: 30 Jul 1998 AlanW Created
  331. //
  332. //--------------------------------------------------------------------------
  333. void CUserActivityMonitor::SampleUserActivity()
  334. {
  335. #if CIDBG == 1
  336. if ( 0 == _tid )
  337. _tid = GetCurrentThreadId();
  338. else
  339. Win4Assert( GetCurrentThreadId() == _tid );
  340. #endif // CIDBG == 1
  341. LASTINPUTINFO ii;
  342. memset(&ii, 0, sizeof(ii));
  343. ii.cbSize = sizeof(ii);
  344. GetLastInputInfo( &ii );
  345. DWORD dwNow = GetTickCount();
  346. SetInputFlag( ii.dwTime );
  347. SetSampleFlag( dwNow );
  348. if (IsBufferEmpty())
  349. {
  350. Win4Assert( _iTail == 0 );
  351. _adwSamples[_iTail++] = _dwLastInputTime = ii.dwTime;
  352. _adwSamples[_iTail] = _dwLastSampleTime = dwNow;
  353. return;
  354. }
  355. #if CIDBG == 1
  356. if ( (Ticks(dwNow) - Ticks(_dwLastSampleTime)) > 5000 )
  357. {
  358. DWORD dwPeriod = Ticks(dwNow) - Ticks(_dwLastSampleTime);
  359. ciDebugOut(( DEB_IWARN,
  360. "SampleUserActivity, WARNING - freq. too low. Interval = %u.%03u\n",
  361. dwPeriod/1000, dwPeriod%1000 ));
  362. }
  363. #endif // CIDBG == 1
  364. if (ii.dwTime == _dwLastInputTime)
  365. {
  366. //
  367. // No input events since last time we looked. Just overwrite the last
  368. // sample time with the current one.
  369. //
  370. Win4Assert( IsSample( _adwSamples[_iTail] ) );
  371. #if 0 //CIDBG == 1 note: this can mess up ordering of samples in buffer
  372. if ( _adwSamples[_iTail] != dwNow )
  373. Add( dwNow ); // always add the sample time for analysis
  374. #else
  375. _adwSamples[_iTail] = dwNow;
  376. #endif // CIDBG == 1
  377. }
  378. else
  379. {
  380. Win4Assert( IsSample( _adwSamples[_iTail] ) );
  381. // The following could happen if an input event happens between
  382. // the calls to GetLastInputInfo and GetTickCount above.
  383. if ( Ticks( ii.dwTime ) < Ticks( _adwSamples[_iTail] ) )
  384. {
  385. _adwSamples[_iTail] = ii.dwTime - 1;
  386. Win4Assert( IsSample( _adwSamples[_iTail] ) );
  387. }
  388. Add( ii.dwTime );
  389. Add( dwNow );
  390. }
  391. _dwLastInputTime = ii.dwTime;
  392. _dwLastSampleTime = dwNow;
  393. }
  394. //+-------------------------------------------------------------------------
  395. //
  396. // Method: CUserActivityMonitor::GetUserActivity, public
  397. //
  398. // Synopsis: Return an indication of the activity level of the interactive user.
  399. //
  400. // Arguments: [dwTickCount] - number of ticks to consider for activity
  401. //
  402. // Returns: ULONG - number of input events detected over the interval
  403. //
  404. // Notes: This may behave oddly around the time when the tick count
  405. // overflows, but since that may just lead to some misdaiganosis
  406. // for a few minutes every 7 weeks, it's not worth worrying about.
  407. //
  408. // History: 30 Jul 1998 AlanW Created
  409. //
  410. //--------------------------------------------------------------------------
  411. ULONG CUserActivityMonitor::GetUserActivity(ULONG dwTickCount)
  412. {
  413. DWORD dwStart = Ticks(_dwLastSampleTime) - dwTickCount;
  414. //
  415. // If the interval is very short, just return whether any input
  416. // has occurred since that time.
  417. //
  418. if ( dwTickCount <= 3000 )
  419. {
  420. SampleUserActivity();
  421. if ( Ticks(_dwLastInputTime) <= dwStart)
  422. return 0;
  423. else
  424. return 1;
  425. }
  426. //
  427. // Quick return if there has been no activity in the interval.
  428. //
  429. if ( Ticks(_dwLastInputTime) <= dwStart)
  430. return 0;
  431. #if CIDBG == 1
  432. Analyze( 0x1000 );
  433. #endif // CIDBG == 1
  434. DWORD dwFirstSample = 0;
  435. BOOL fFullInterval = FALSE;
  436. ULONG cInputEvent = 0, cTotalEvents = 0;
  437. for (unsigned i = _iHead; i != _iTail; i = Next(i))
  438. {
  439. DWORD dw = _adwSamples[i];
  440. if (Ticks(dw) < dwStart)
  441. {
  442. fFullInterval = TRUE;
  443. //
  444. // If an input event and a sample time bracket the start of
  445. // the interval, we can consider the input event as the first
  446. // sample because we know that the user gave no input in that time.
  447. //
  448. if ( IsInput(dw) &&
  449. Ticks(_adwSamples[ Next(i) ]) >= dwStart )
  450. dwFirstSample = dw;
  451. continue;
  452. }
  453. else if (0 == dwFirstSample)
  454. dwFirstSample = dw;
  455. if (IsInput(dw))
  456. cInputEvent++;
  457. cTotalEvents++;
  458. }
  459. #if CIDBG == 1
  460. if (! fFullInterval)
  461. {
  462. ciDebugOut(( DEB_IWARN,
  463. "GetUserActivity, WARNING - sampling freq. too high! missed %d\n",
  464. dwFirstSample - dwStart ));
  465. }
  466. if (2 == cTotalEvents)
  467. {
  468. ciDebugOut(( DEB_IWARN, "GetUserActivity, WARNING - sampling frequency too low\n" ));
  469. }
  470. #endif // CIDBG == 1
  471. DWORD dwInterval = Ticks(_dwLastSampleTime) - Ticks(dwFirstSample);
  472. // Scale the results if we don't have samples for 80% of the requested time
  473. if (dwInterval*100 < dwTickCount*80)
  474. {
  475. // Scale the count found to fit the full interval
  476. ciDebugOut(( DEB_IWARN, "GetUserActivity, need to scale count %u %u\n",
  477. dwInterval, dwTickCount ));
  478. cInputEvent *= dwTickCount;
  479. if (dwInterval)
  480. cInputEvent /= dwInterval;
  481. }
  482. return cInputEvent;
  483. }
  484. #if CIDBG == 1
  485. inline void PrintTicks( ULONG infolevel, DWORD dwTicks )
  486. {
  487. ciDebugOut(( infolevel|DEB_NOCOMPNAME, "%3u.%03u", dwTicks/1000, dwTicks%1000 ));
  488. }
  489. #define SHORT_TERM_IDLE 500
  490. #define LONG_TERM_THRESHOLD 20
  491. #define LONG_TERM_INTERVAL (120 * 1000)
  492. #define MID_TERM_THRESHOLD 10
  493. #define MID_TERM_INTERVAL (30 * 1000)
  494. void CUserActivityMonitor::Analyze( ULONG infolevel )
  495. {
  496. if (_iSnap == _iTail)
  497. return;
  498. ciDebugOut(( infolevel, "\t----\n" ));
  499. for (unsigned i = _iSnap; i != _iTail; i = Next(i))
  500. {
  501. DWORD dw1 = _adwSamples[i];
  502. DWORD dw2 = _adwSamples[Next(i)];
  503. if (IsInput(dw1))
  504. {
  505. ciDebugOut(( infolevel|DEB_NOCOMPNAME, "%u", dw1 ));
  506. }
  507. else
  508. {
  509. Win4Assert( Ticks(dw1) <= Ticks(dw2) );
  510. ciDebugOut(( infolevel|DEB_NOCOMPNAME, "\t%u\n", dw1 ));
  511. }
  512. if (Next(i) == _iTail)
  513. ciDebugOut(( infolevel|DEB_NOCOMPNAME, "\t%u\n", dw2 ));
  514. }
  515. DWORD dwStart1 = Ticks(_dwLastSampleTime) - MID_TERM_INTERVAL;
  516. DWORD dwStart2 = Ticks(_dwLastSampleTime) - LONG_TERM_INTERVAL;
  517. DWORD dwFirstInput = 0;
  518. DWORD dwIdleTime = 0;
  519. DWORD dwUnknTime = 0;
  520. unsigned cInputEvent = 0;
  521. unsigned cInputQualified1 = 0;
  522. unsigned cInputQualified2 = 0;
  523. unsigned cTotalEvent = 0;
  524. for (i = _iHead; i != _iTail; i = Next(i))
  525. {
  526. DWORD dw1 = _adwSamples[i];
  527. DWORD dw2 = _adwSamples[Next(i)];
  528. if (IsInput(dw1))
  529. {
  530. Win4Assert( Ticks(dw1) <= Ticks(dw2) );
  531. cInputEvent++;
  532. if ( IsSample(dw2) )
  533. dwIdleTime += Ticks(dw2) - Ticks(dw1);
  534. if (Ticks(dw1) > dwStart1)
  535. cInputQualified1++;
  536. if (Ticks(dw1) > dwStart2)
  537. cInputQualified2++;
  538. }
  539. else
  540. {
  541. Win4Assert( Ticks(dw1) <= Ticks(dw2) );
  542. if ( IsSample(dw2) )
  543. dwIdleTime += Ticks(dw2) - Ticks(dw1);
  544. else
  545. dwUnknTime += Ticks(dw2) - Ticks(dw1);
  546. }
  547. cTotalEvent++;
  548. }
  549. ciDebugOut(( infolevel, "\tTotal time in buffer\t" ));
  550. PrintTicks( infolevel, Ticks(_dwLastSampleTime) - Ticks(_adwSamples[_iHead]) );
  551. ciDebugOut(( infolevel|DEB_NOCOMPNAME, "\n\tTime since last snapshot\t" ));
  552. PrintTicks( infolevel, Ticks(_dwLastSampleTime) - Ticks(_adwSamples[_iSnap]) );
  553. ciDebugOut(( infolevel|DEB_NOCOMPNAME, "\n\t\tTrue idle time\t" ));
  554. PrintTicks( infolevel, dwIdleTime );
  555. ciDebugOut(( infolevel|DEB_NOCOMPNAME, "\n\t\tUnknown time\t" ));
  556. PrintTicks( infolevel, dwUnknTime );
  557. ciDebugOut(( infolevel|DEB_NOCOMPNAME, "\n\t\tInput events\t%7d Qualified\t%d %d\n", cInputEvent, cInputQualified1, cInputQualified2 ));
  558. if ( (Ticks(_dwLastSampleTime) - Ticks(_dwLastInputTime)) < SHORT_TERM_IDLE )
  559. {
  560. ciDebugOut(( infolevel|DEB_NOCOMPNAME,
  561. "\t*** Short term criteria\t%3d %3d\n", SHORT_TERM_IDLE,
  562. Ticks(_dwLastSampleTime) - Ticks(_dwLastInputTime) ));
  563. }
  564. if ( cInputQualified1 >= MID_TERM_THRESHOLD )
  565. {
  566. ciDebugOut(( infolevel|DEB_NOCOMPNAME,
  567. "\t*** Mid term threshold\t%2d/%3d %3d\n",
  568. MID_TERM_THRESHOLD, MID_TERM_INTERVAL,
  569. cInputQualified1 ));
  570. }
  571. if ( cInputQualified2 >= LONG_TERM_THRESHOLD )
  572. {
  573. ciDebugOut(( infolevel|DEB_NOCOMPNAME,
  574. "\t*** Long term threshold\t%2d/%3d %3d\n",
  575. LONG_TERM_THRESHOLD, LONG_TERM_INTERVAL,
  576. cInputQualified2 ));
  577. }
  578. _iSnap = _iTail;
  579. }
  580. #endif // CIDBG == 1