From: GrayFox on
I'm writing a program that copies the bitmap of the desktop (like a
screenshot), calculates the average RGB value of the screen, and send it over
USB.
Everything is working and I manage to get 30+ loops per second, which is
good enough.

However, after some time (varying between ~20 sec and ~1 min 30 sec), and
not doing anything else, the loops per second suddenly drop to about 10 loops
per second, which is too slow for my purpose. This transition happens within
a fraction of a second.

When I watch the Task Manager, and don't see anything special happening. The
CPU time for my process remains the same, the total CPU usage is quite
stable, memory usage is stable as well.

I've tried changing Thread priority and Process priority but nothing seems
to work. I am at a loss here.

Anyone has any ideas? I would greatly appreciate any suggestions, advice and
thoughts.
From: Hector Santos on
How are you doing these "loops?" In a Thread? in a MFC OnTimer?

You might have to do this in a background thread.

--

GrayFox wrote:

> I'm writing a program that copies the bitmap of the desktop (like a
> screenshot), calculates the average RGB value of the screen, and send it over
> USB.
> Everything is working and I manage to get 30+ loops per second, which is
> good enough.
>
> However, after some time (varying between ~20 sec and ~1 min 30 sec), and
> not doing anything else, the loops per second suddenly drop to about 10 loops
> per second, which is too slow for my purpose. This transition happens within
> a fraction of a second.
>
> When I watch the Task Manager, and don't see anything special happening. The
> CPU time for my process remains the same, the total CPU usage is quite
> stable, memory usage is stable as well.
>
> I've tried changing Thread priority and Process priority but nothing seems
> to work. I am at a loss here.
>
> Anyone has any ideas? I would greatly appreciate any suggestions, advice and
> thoughts.



--
HLS
From: Woody on
On Mar 31, 3:30 pm, GrayFox <Gray...(a)discussions.microsoft.com> wrote:
> However, after some time (varying between ~20 sec and ~1 min 30 sec), and
> not doing anything else, the loops per second suddenly drop to about 10 loops
> per second, which is too slow for my purpose. This transition happens within
> a fraction of a second.

Your symptom suggests a switch from RAM to paged memory, which could
occur if you are creating objects from heap memory ('new') but not
deleting them. Also, if you're using XP, be sure you have SP 3, as
there was a resource leak in SP 2.

To see what's happening, you might want to use Process Explorer
(download from SysInternals). If you do use Task Manager, be sure you
have all the columns selected. Then, you can compare fast operation to
slow operation, and see if there's anything obvious.
From: GrayFox on


"Hector Santos" wrote:

> How are you doing these "loops?" In a Thread? in a MFC OnTimer?
>
> You might have to do this in a background thread.


I'm creating a thread from the initial dialog. So I just have a dialog based
application, and then on the OnInitDialog() I call CreateThread(), and as an
argument, I pass the 'this' pointer, so the thread (a global function) can
start a member function of the dialog class. I set the priority to
THREAD_PRIORITY_HIGHEST


"Woody" wrote:

> Your symptom suggests a switch from RAM to paged memory, which could
> occur if you are creating objects from heap memory ('new') but not
> deleting them. Also, if you're using XP, be sure you have SP 3, as
> there was a resource leak in SP 2.
>
> To see what's happening, you might want to use Process Explorer
> (download from SysInternals). If you do use Task Manager, be sure you
> have all the columns selected. Then, you can compare fast operation to
> slow operation, and see if there's anything obvious.
> .
>

I am running Vista, so that can't be it. Besides, I've already created
nearly all variables as members of the class, and not allocating them in
every loop cycle, mainly to avoid cpu time for the allocation and to prevent
memory leaks.
You're RAM to paging theory sounds pretty interesting, I'll check that out.
I'll try Process Explorer as you advised.
Thanks already guys!
From: Hector Santos on
GrayFox wrote:

>
> "Hector Santos" wrote:
>
>> How are you doing these "loops?" In a Thread? in a MFC OnTimer?
>>
>> You might have to do this in a background thread.
>
>
> I'm creating a thread from the initial dialog. So I just have a dialog based
> application, and then on the OnInitDialog() I call CreateThread(), and as an
> argument, I pass the 'this' pointer, so the thread (a global function) can
> start a member function of the dialog class. I set the priority to
> THREAD_PRIORITY_HIGHEST

First, I would personally put aside the thread priority increase until
all the "logic" is worked out, then if you need higher priority, play
with it.

Its hard to imagine what exactly the type of work you are doing and
how or rather what effect you have when communicating with the main
(GUI) thread.

Are you writing results back via This->DialogFunction(data)?

As long as you are not using multiple threads to write to the same
resource, it should work fine.

You indicated 30 loops per second which is ok for you?

What I did was create a quick MFC dialog with:

- Start Thread Button IDC_BTN_STARTTHREAD
- Stop Thread Button IDC_BTN_STOPTHREAD

- ListBox IDC_LIST_LOG, change property Sort to FALSE
- Add Variable CListBox mc_log for dlg class
- Add Variable HANDLE hThread (initial to NULL in constructor)
- Add Variable BOOL bAbort (initial to FALSE in constructor)

Then create this thread proc:

DWORD CALLBACK ClientThread(void *p)
{
CTestMfcThreadGreyFoxDlg *dlg = (CTestMfcThreadGreyFoxDlg *)p;
dlg->mc_log.AddString(L"- Starting Thread");
while (!dlg->bAbort) {
Sleep(1000/33); // about 30 loops per sec
dlg->mc_log.AddString(L"- Tick");
}
dlg->mc_log.AddString(L"- Ending Thread");
return 0;
}

and the Start Button Click function:

void CTestMfcThreadGreyFoxDlg::OnBnClickedBtnStartthread()
{
GetDlgItem(IDC_BTN_STARTTHREAD)->EnableWindow(FALSE);
GetDlgItem(IDC_BTN_STOPTHREAD)->EnableWindow(TRUE);
DWORD tid;
if (hThread == NULL) {
bAbort = FALSE;
hThread = CreateThread(NULL, 0, ClientThread, this, 0, &tid);
}
}

and the Stop Button Click function:

void CTestMfcThreadGreyFoxDlg::OnBnClickedBtnStopthread()
{
if (hThread != NULL) {
bAbort = TRUE;
while (1) {
DWORD rc = WaitForSingleObject(hThread,25);
if (rc == WAIT_OBJECT_0) {
CloseHandle(hThread);
hThread = NULL;
GetDlgItem(IDC_BTN_STARTTHREAD)->EnableWindow(TRUE);
GetDlgItem(IDC_BTN_STOPTHREAD)->EnableWindow(FALSE);
mc_log.AddString(L"* Thread Ended");
break;
}
if (rc == WAIT_OBJECT_0) {
mc_log.AddString(L"* Waiting for Thread to end");
}
// process any messages
MSG msg;
if ( PeekMessage(&msg, this->m_hWnd, 0, 0, PM_REMOVE) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

}
}
}

And it all seem fine to me, even after 45 minute when I went to have
breakfast. :)

If your loops is slowing down, then I can only imaging the its getting
slowed down with the dialog function call from the thread. In other
words, the function is slowing down. Technically the thread is
blocked when it makes the call until the dlg function is complete.
For example, in this code where the thread called:

dlg->mc_log.AddString(L"- Tick");

Eventually after a long time, that could slow down because the log
will be be big. If it was in SORT mode, that will even slow it down
further. It could be, forever you are doing, that you could be
generating a lot of messages.

Generally, the alternative and often better way is to post a message
to the main thread, that way your thread will not be blocked. But as
dialog function is fast and not doing a lot of work, it shouldn't be a
problem.

You indicated 30 loops per second, that is about 33 milliseconds per
loop. A quantum is 15 msecs so your loop will be preempted at least
twice. Not sure how that will play a role without looking at whats
being down. Increasing the priority may even preempt more times to
give your thread more time. That may all depend on what other threads
have the same priority. So that is why you want to work out the logic
first before you do this.

Short of looking at your code, this the best I can tell ya. Maybe
others can provide some insight.

--
HLS