Delphi 7: Dual Core

Started by
6 comments, last by spek 15 years, 3 months ago
Time to make use of the second CPU. But how? I have a game that can roughly be divided into 4 sections: 1.- Main game loop + render (OpenGL) 2.- Physics / Sound 3.- Streaming / AI 4.- Realtime Ambient light updater (some sort of raytracer) If I had a quadcore, I would like to assign each part to 1 core. But let's keep it simple for now, I want part 1/2/3 running on the primary core, step 4 on the secundary core. How can I tell threads in Delphi7 to run on which core? Are there also programming differences between Windows XP and Vista? I remember some of my test programs made 100% of core1, 0% of the second core, while in Vista both cores were used. I didn't divide the program into multiple threads, I just executed a big bad function when clicking on a button. Anyhow, the Realtime Ambient updater will need all the energy it can get, that's why I'd like to specifically assign it to a core... if possible (Delphi7 is getting old) Greetings, Rick
Advertisement
Generally it's a bad idea to assign threads to a specific core. Just create the number of threads you need and let Windows assign them to the appropriate cores. For example doing that will help a lot where you have four or more processor cores (the Core i7 can run up to 8 threads at once).

If need be you can assign priorities to threads to make Windows run one thread in preference to the others.

For your raytracer you can also easily use multiple threads for the one task (e.g. split the screen into four pieces and give one to each thread). That will speed it up a lot on high end CPUs.
Allright, I didn't know the thread management would be that "intelligent". Well, that might save me headache. Although it might be a little bit more difficult to predict speed maybe... Highest priority gets to the main rendering process that basically works like any other game. But the ambient lighting stuff will need a fair deal of CPU power as well. The idea was to give it ~50% (therefore, 1 of the 2 cores). But how will it work with the automatic management?

Another question, once a thread has been started, will it stick with the same core for the rest of the program life cycle, or can it be divided onto multiple cores/get 'ping-ponged' to another core?

Thanks for the info!
Rick
Quote:Original post by spek
But how will it work with the automatic management?

Another question, once a thread has been started, will it stick with the same core for the rest of the program life cycle, or can it be divided onto multiple cores/get 'ping-ponged' to another core?
Automatic management will generally boil down to this: If you need computing resources, and there are computing resources, you get those computing resources. Not binding to a specific core/processor means that you play better with other programs that may not be so nice. There is a huge list of examples of this, where binding to a processor opens you up to added inefficiency/poor resource utilization/easy attack/etc, but the bottom line is that by tying the OS's hands with respect to scheduling, you give up computing power that you could be otherwise using, rather than the other way around. You will get resources as they are available, and more importantly, you will play nice with others, since you are not the only one interested in using those two cores [and many programmers are not so nice]. This is just another instance of fewer constraints -> higher resource utilization.

As to your second question, the OS will migrate your thread around between processors based on load/resource locality/however it damn well feels like. It however doesn't result in a big problem from your perspective, so don't lose sleep over it. The effects of this generally manifest in the form of short durations of increased occurrence of low impact cache misses, which will likely be completely unnoticeable from your end. The OS will generally not just move your thread around for giggles, and will be doing so when it feels there is an actual interest in doing so. Thread binding is an interesting option on some processor architectures, but not so much on these. It gets a bit more interesting if you know for a fact that you can have exclusive run of the place on a given processor without creating a shortage otherwise [say, for example, if you have 128 cores, and 1 program running on all of them].

*edit* fixed stupid typos

[Edited by - Drigovas on January 15, 2009 5:19:42 PM]
Thanks for some Thread lessons. It seems that, except of making good use of multithreading, there didn't change that much for the programmer so far. I really thought I needed to do all this stuff myself. Well, let's just try it in practice.

One last question then. One of the threads involves streaming. Loading a couple of textures takes relative much time. Luckily I have plenty of time. Let's say it takes 10 seconds before I actually need the data. How to spread out the loading time as smoothly as possible? Now I have a thread that loads a single object/texture, sleeps 200 ms, then goes to the next object. Priority for this thread is low (while others are high/highest). Won't this cause the speed to 'fluctuate' (each 200 ms an 'impact')? Maybe its better to skip the sleeptime? I could make the thread priority even lower (idle), although I might risk some stuff never gets loaded then.

@Adam / Drigovas
Made a little mistake with the user rating for one of the two of you. Clicked "Somewhat unhelpfull / unfriendly". That should have been the opposite. Excusez moi :) Don't want you to think you didn't help me!

Both you guys, thanks!
Rick
For a thread that's just loading data off disc set it to a reasonably high priority. The reason is that while Windows is reading data from the disc it will put the thread waiting for that data to sleep so the CPU load from that thread will be close to zero anyway. The high priority just lets it get back to requesting the next file as soon as possible, which will get them all loaded quickest.

There's no need to wait between loading files - just load them as quick as you can. Even if you have other threads loading other data at the same time Windows will let them both share the disc. However for maximum read performance it's best not to read two files at the same time from separate threads to minimize the number of seeks.
Don't worry too much about the ratings. Besides being pretty pointless in the grand scheme of things, you can always go back and adjust the rating nudge you gave by re-rating. Really though... whatever.

Loading data with multiple threads won't likely yield much benefit. This is because the hard drive from which you are loading is only servicing one request at a time. When there is one request, it services it with all of it's attention. If there are two requests, it skips around between the two. Since hard drives have such a large seek time, it turns out that hitting the disk with one thread at a time is best in terms of throughput in most cases [unless you have a raid array or some other multi-disk configuration that can take multiple hits at a time]. Loading data in one thread and processing it in another DOES result in benefit.

The solution generally boils down to this. Devote one thread to blocking on disk reads. Have this thread just soak up the data that you will need in the future. This thread's only job will be to get data from the disk into memory, and just keep doing that. The CPU load of this thread will effectively be zero, since all it will do is repeatedly hit the hard drive and thus be de-scheduled by the OS. Have a second thread that gets fed the already loaded files [textures], and tells the file-reading thread each time it is completely done with a given file [and has thus freed up the memory and resources associated with it]. The file reading thread uses this information so that it doesn't get too far ahead of the thread that is actually using the data. This could potentially be a concern if your processing is time consuming compared to your file reads, which would result in your file reads filling up your memory [to the limit, if you have enough files].

File IO is one of those 'first candidates' for multithreading for exactly this reason. It is 100% benefit, and easy to do. No added CPU overhead because it is all IO bound. No need to block on a long IO read in your main thread because you have a slave thread to do it for you. Everything is a plus here. The communication is pretty simple too. For people looking for where to look first with respect to multithreading, in terms of the most obvious first pick that will also yield the biggest benefit, file IO and network IO are always on the top of the list.

*edit* Damnit adam..... you and your speedy fingers.
>> Rating
Maybe pointless, but it's the least I can do if someone takes time and helps me :)

I would have done the opposite, giving low priorities to "slow moving" procedures. But I get the point, reading data depends most on the harddisk/disk reader, instead of the CPU.

There is still a problem though, although this is somewhat specific to OpenGL and the video card hardware. After loading a picture, it also needs to be send to the video card memory of course. Yet again, this is a relative simple task (just pass a big array with colors). So I'm not sure where the bottleneck actually is... Probably the limited bandwidth available for CPU -> GPU transfers. Ifso, I guess this won't actually require much of the CPU, thus doing this in the same thread wouldn't hurt in that case. However, I'm not even sure if its allowed to send data (via OpenGL) to the GPU anytime from any thread...

For the other threads that actually need the CPU (Physics, AI, pathfinding, you name it), should I use lower priorities / longer sleep times for the parts that don't need very rapid updates? So far I had this scheme in mind (besides from the main rendering loop):

Thread1: Streamer, sleeptime 0 ms, priority HIGHEST
Thread2: Physics, sleeptime 25 ms, priority HIGH(EST)
Thread3: Sound, sleeptime 250 ms, priority LOW
Thread4: AI, sleeptime 250 ms, priority NORMAL
Thread5: Ambient Raytracer, sleeptime 0 ms, priority HIGH

Don't know if these are wise choices. Anyhow, AI and sound are not time critical. 4 AI updates per second to make decissions is more than enough. Same for the sound where the updates mean that sfx is started/stopped or updates its position/pitch/volume. Physics is important of course, I have to prevent shocking movement or too inaccurate physics. The raytracer is important too. The faster it spits out maps, the better the graphical results.

Greetings,
Rick

This topic is closed to new replies.

Advertisement