Time critical thread seems to pause briefly once every few seconds

J

Joe Withawk

I have an application in which there exist a thread that handles directx
rendering. It runs on a dual core system with windows vista and xp.
It is set to have highest priority and simply loops with
while(isRendering)
{
prepare for rendering;
do render;
present()
}

It runs smoothly and then pauses very briefly and resumes.
I assume it has to do with windows wanting to do some background processing,
but I did not expect it to interrupt a high priority thread.
I am wondering if it has to do with the call to directx's present. It will
not always return immideately. Sometimes, when it has filled an outbuffer
with rendered frames (that buffer is small.. 2 or 3 frames), it will block.
If the thread blocks there then it will become idle and windows will grab
its processor for its own purposes and not release it again quickly enough.
This then causes the small pause in a high priority thread?

Generally with two cores and few processes, I beleive the core running the
critical thread will be more or less reserved for the thread and the other
core will be uses for low priority work. Is this not correct?

I am running low on ideas to how I should fix this, but it would help to
hear if my theory seem plausible at all. If it is, would the solution then
be to do a spin wait in the thread when I can see that present() will block?
Something like replacing present() with
while(presentWillBlock());
present();

This way the thread never powers down and should not worry about anyone
taking its core?
 
P

Peter Duniho

I have an application in which there exist a thread that handles directx
rendering. It runs on a dual core system with windows vista and xp.
It is set to have highest priority and simply loops with
while(isRendering)
{
prepare for rendering;
do render;
present()
}

[...]
Generally with two cores and few processes, I beleive the core running
the critical thread will be more or less reserved for the thread and the
other core will be uses for low priority work. Is this not correct?

That assumes that your thread is the only high priority thread on the
computer. If there are enough high priority threads, they will all
consume the available CPU cores and no lower priority thread will get to
run (mostly).

Philosophically, I wouldn't call a rendering thread "time critical".
"Time critical" is for things that, if you do not process them by some
specific time something simply fails. Examples of this would be a thread
servicing an unbuffered i/o port (or one with a very small buffer), such
as reading from some kind of serial port, or writing data to an audio
output device.

Even for a "time critical" thread, raising the priority is only
appropriate if you know that the thread _must_ run when it's time for it
to run, but it will finish quickly, never consuming its entire timeslice.

A rendering thread doesn't fall into that category.

It's difficult to say without having code to test, but...if I had to
guess, I'd guess that your pausing is _because_ your thread has elevated
priority. This isn't an appropriate approach anyway, but in this case I
suspect that you are starving lower priority threads. But Windows doesn't
let threads get completely starved. Eventually, they get a temporary
priority boost until they're high enough to run.

At that point, a whole bunch of threads that have been starved for
attention then get to do whatever it was that they wanted to do, and your
high-priority thread gets to wait for them.

This will probably sound counter-intuitive, but the solution to your
problem is likely to be to stop messing with the thread priority and leave
your thread at normal priority. Or even to _lower_ the thread priority a
bit. Lowering the priority, your thread will still get practically as
much CPU time that it otherwise would have gotten, but the system will be
much more user-responsive. It's a much more user-friendly way to write
your code.

Bottom line: threads that don't block shouldn't be set to an elevated
priority. If anything, they should have _lowered_ priority.

Pete
 
J

Joe Withawk

Even for a "time critical" thread, raising the priority is only
appropriate if you know that the thread _must_ run when it's time for it
to run, but it will finish quickly, never consuming its entire timeslice.

A rendering thread doesn't fall into that category.

Mine does actually. I need to feed an external dvi to svideo-converter, and
if I fail then the odd even scanlines will come out of sync and all hell
breaks lose. Especially since I have no feedback telling me exactly how much
I am behind so I can compensate.
It's difficult to say without having code to test, but...if I had to
guess, I'd guess that your pausing is _because_ your thread has elevated
priority. This isn't an appropriate approach anyway, but in this case I
suspect that you are starving lower priority threads. But Windows doesn't
let threads get completely starved. Eventually, they get a temporary
priority boost until they're high enough to run.

Yes I saw thatsuggestion in theother thread I started about fiding a
profiler to tell me exactly what is going on. It is a good one too, but I
tried lowering priority and the problem actually got worse :-/
Bottom line: threads that don't block shouldn't be set to an elevated
priority. If anything, they should have _lowered_ priority.

There are many details let out in my posts, for obvious reasons, but my
thread do actually block.
It renders at most 3 frames ahead and then blocks until the graphics card
pushes out a frame and then it writes yet another frame.
That is also why it seems odd that I see the pause. 3 frames with 60Hz is
50ms which seem like a very long time to be preempted.
 
P

Peter Duniho

[...]
There are many details let out in my posts, for obvious reasons, but my
thread do actually block.
It renders at most 3 frames ahead and then blocks until the graphics
card pushes out a frame and then it writes yet another frame.
That is also why it seems odd that I see the pause. 3 frames with 60Hz
is 50ms which seem like a very long time to be preempted.

Well, I don't really understand the nature of the problem you're trying to
solve. However, I'd suggest that if the problem is that you can't risk
having pairs of frames disconnected, then perhaps rendering three frames
at a time isn't a good idea. It would probably be better to render pairs
of frames at a time, yielding in between so that other threads get a
chance to run and are less likely to preempt you when you're trying to do
something.

Pete
 
J

Joe Withawk

Well, I don't really understand the nature of the problem you're trying to
solve. However, I'd suggest that if the problem is that you can't risk
having pairs of frames disconnected, then perhaps rendering three frames
at a time isn't a good idea. It would probably be better to render pairs
of frames at a time, yielding in between so that other threads get a
chance to run and are less likely to preempt you when you're trying to do
something.

That was not a bad suggestion actually.
Not that it would solve the problem of having the odd/even get crossed, but
it might be a goog idea to actively relinguish control when I know it is ok.
Well.. if I am sure to get it back again within 50ms that is. I will try it.
The reason it doesnt really help to render two frames and then wait is that
if I lose one frame (or rather field) in between paits of two fields, then I
still get out of synch.
I will try actively releasing. I assume this is best done with
Thread.Sleep()?
 
P

Peter Duniho

[...]
The reason it doesnt really help to render two frames and then wait is
that if I lose one frame (or rather field) in between paits of two
fields, then I still get out of synch.

If you're only drawing two fields, I don't see how you could lose a third
one "in between pairs of two fields". But, whatever.
I will try actively releasing. I assume this is best done with
Thread.Sleep()?

Yes. Call Thread.Sleep(1) (if you pass 0, you will only yield to threads
of the same or higher priority...passing 1 ensures that all runnable
threads will get a chance to execute).

Pete
 
J

Joe Withawk

Yes. Call Thread.Sleep(1) (if you pass 0, you will only yield to threads
of the same or higher priority...passing 1 ensures that all runnable
threads will get a chance to execute).

Did not do the trick though. :-/

Perhaps this whole question should be refhrased to...
on an otherwise clean installation og windows vista on a system with a core
2 duo 1.5GHz, should I not could expect to never get preempted for as long
as 50ms? Should I not could expect to run more often than this? Should I
conclude that the system is faulty and that the application itself is not to
blame?
 
P

Peter Duniho

Perhaps this whole question should be refhrased to...
on an otherwise clean installation og windows vista on a system with a
core 2 duo 1.5GHz, should I not could expect to never get preempted for
as long as 50ms? Should I not could expect to run more often than this?
Should I conclude that the system is faulty and that the application
itself is not to blame?

Fundamentally, it's your expectations that are flawed.

Windows is not a real-time operating system. Real-time applications
running on Windows are inherently doomed to fail eventually.

You ask "should I not could expect to never get preempted for as long as
50ms". The fact is, with that being in the same neighborhood as the
actual timeslice for a thread in Windows, any single thread could in fact
delay you that long, if it gets to run and uses its entire timeslice. In
pratice, it's very unusual for a thread to take that long, or even for
some number of threads to in aggregate use up that much time. But it
certainly is theoretically possible, and on Windows you will _never_ be
able to avoid this basic fact.

That said, I don't completely understand why you're not getting the
behavior you need. Certainly Windows can keep up with things on the order
of 50-60hz and does so on a regular basis. That suggests that there
_might_ be something wrong with your application design or implementation.

But this newsgroup is not really going to be an appropriate forum for
working out fine details like that. We can, and have, offered quite a lot
of advice regarding the generalities of writing time-sensitive code on
Windows. But ultimately, if you are seeing delays that interfere with the
proper operation of your program, you're going to need to debug those
delays yourself.

There is no substitute for first-hand information about what's actually
happening, and you are the only person in a position to gather that
information.

If the delays occur within your own process, you may be able to use the
usual debugging tools to do that. If they are a consequence of thread
scheduling on Windows, you're likely to need a kernel debugger so that you
can monitor what the OS is actually doing (and of course even there it's
not going to be easy, since actually stepping in a debugger without
completely obscuring the problem is likely to be impossible).

Pete
 
J

Joe Withawk

You ask "should I not could expect to never get preempted for as long as
50ms". The fact is, with that being in the same neighborhood as the
actual timeslice for a thread in Windows, any single thread could in fact
delay you that long, if it gets to run and uses its entire timeslice.
That said, I don't completely understand why you're not getting the
behavior you need. Certainly Windows can keep up with things on the order
of 50-60hz and does so on a regular basis.

If I need to do something every 16 ms and I am preempted for longer than
that, then the problem is right there. Is there something I don't see here?
There is no substitute for first-hand information about what's actually
happening, and you are the only person in a position to gather that
information.

True. I was hoping for some general info on what might be wrong.
I received a lot of that, and it was helpfull... even though the problem
persist.
I have now come to the conclusion that there is something wrong with my
current installation. I have not tried moving it to other machines yet since
that is not quite so simple, but i will.
 
P

Peter Duniho

If I need to do something every 16 ms and I am preempted for longer than
that, then the problem is right there. Is there something I don't see
here?

I don't know. I may have misunderstood your statement. But it seems to
me that if your code can handle two fields in less than one timeslice, and
you are careful to only ever process two fields when you have just
returned from a call to Thread.Sleep(1), then you should be guaranteed to
always be able to process those two fields before your timeslice is up.

In other words, you should be able to guarantee that you can always keep
two fields together.

It gets trickier if you want to try to send out more than one pair of
fields in a given timeslice, and of course you always run the risk of
having to wait some arbitrarily long amount of time once you've yielded
(or been preempted). But assuming you've got the system configured
properly, without extraneous software that might be burdening the CPU,
this shouldn't be an issue.
[...]
I have now come to the conclusion that there is something wrong with my
current installation. I have not tried moving it to other machines yet
since that is not quite so simple, but i will.

It's certainly worth a try. In any case, whatever computer you run this
one, you should go to great pains to disable _everything_ that is not
absolutely necessary. For sure, that rules out having any non-essential
third-party software. You will probably also want to research which
services can be safely disabled. A number of the services running by
default are not actually needed; you can use Google to find a number of
online articles regarding which ones can be turned off without disabling
your computer completely.

Pete
 
J

Joe Withawk

In other words, you should be able to guarantee that you can always keep
two fields together.

That is true. That much is certain. What is not a given is that the numbr of
frames where I prsent nothing new to the external hardware is an even
number.
If I send out paits of fields, which is good, but i send two, sleep while
the receiver expects another three fields, and then sends two more, then the
receiver will read my even fields as odd and vice versa.

It's certainly worth a try. In any case, whatever computer you run this
one, you should go to great pains to disable _everything_ that is not
absolutely necessary. For sure, that rules out having any non-essential
third-party software. You will probably also want to research which
services can be safely disabled. A number of the services running by
default are not actually needed; you can use Google to find a number of
online articles regarding which ones can be turned off without disabling
your computer completely.

Yes I should do that. It will be a pain though since it will eventually be
installed on a lot of machines.
Thanks for your feedback :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top