bewing wrote:Brendan's mechanism is impressive, but kinda fails the fourth important concept of KISS.
I am intending to implement an earlier suggestion, myself. Each core has an independent scheduler, with an independent task queue. In my system, independent "jobs" own "threads" as subtasks. When a new job is created, it is assigned to the core with the least load at that time. The job then creates all its child threads on that same core.
If one core's scheduler runs out of >idle priority runnable tasks, it requests a load balance from the most loaded core. The most loaded core picks a fairly high priority job, and dumps that entire job worth of threads all at once to that empty core -- ie. the "affinity" for the entire job gets modified all at once.
I like the basic idea of one-shot tickless systems. However, the idea scares me, too. What happens if the timer fails to deliver the next one-shot interrupt to the CPU? Nothing in a system is absolutely 100% guaranteed, including interrupt delivery. I would really want to have some sort of backup mechanism to wake up a CPU that missed a one-shot interrupt, and got stuck running the same task forever.
In a tick-based system, at least you can always count on the fact that another timer tick will come along the next time around.
Hmm.... that sounds, well... not right to me
. What's the point of multi-threading if the threads are running on a single CPU only? I mean, say I am writing a game, it has AI in one thread, graphics engine in another... wouldn't it be better if they could run on seperate CPU's so both parts are done simultaneously, rather than on a single CPU where they are sharing cylces. That kind of defeats the main benefit of multithreading in a multi-cpu OS doesn't it? Also, transfering a high CPU load process is great, but now you are locking 2 buffers (removal and insertion qeues), and if that is the only process running and is high priority, what's to stop your kernel from passing it from cpu 0 -> 1 -> 2 -> 3 and back to 0 again on each check. Now, what if it's the only process running, and it has a lot of sub-threads (web-server type applications spawn many threads to use blocking i/o for clients), having all threads on one CPU and always moved with it's parent seems like a bit of a waste to me. While brandon's method may seem a bit 'overkill', sometimes keeping it simple isn't always the best solution. I plan to have process balancing of sorts in my OS, where each CPU stores a # indicating how much work it's doing (based on process count, and process priorities), on each task switch it check itself against the other CPU's (so, 3-6 compares with 4 cpu's), if it finds one that is different by a certain # of points (will play with values to find a good compromise, or have a variable in the OS for balancing), then it will move a thread (with a specific priority based on the difference between the 2). So, for example:
idle = 1
medium = 2
high = 3
CPU 0 -> 2 threads, both idle total = 2
CPU 1 -> 5 threads, 2 idle, 1 medium, and 2 high total =10
So, when CPU 0 runs, it would check, and realize that CPU 1 is doing way more work, and the difference is 8, so 8/2 = 4.. so it would take a high priority thread...
CPU 0 -> 2 idle, 1 high total = 5
CPU 1 -> 2 idle, 1 medium, 1 high = 7
CPU 1 would run, see that it has a higher number, if the difference was set really low (say 1), it would give CPU 0 an idle thread (difference of 2/1 = 1), and they would be balanced at 6. Although, typically that difference would be small enough to not be worth the moving, and would just start the next task.
So, now they are re-balanced.. now, my values probably won't be 1,2,3, probably closer to 1,3,7 or something like that, but you get the idea... I will probably have the CPU with the lowest # do the balancing for the rest of them, so it has the least chance of being interrupted (the locks spinning), and the most free CPU cycles. It's not all that complex (just comparing a few numbers, each time a task is added or removed, increment or decrement a number
. Pretty simple, but accomplishes balancing pretty well I think. I still have a lot of planning and implementing, but that's what i've come up with so far, trying to keep it simple, but still be useful. I may have something in place that tries to keep threads with the same parent on different CPU's, so they are able to run simultaneously, but that will be for later.