Re: Segmentation in real mode

From: Beth (BethStone21_at_hotmail.NOSPICEDHAM.com)
Date: 03/13/05


Date: Sun, 13 Mar 2005 08:59:58 GMT

wolfgang kern wrote:
> Tom asked:
> | Ladies and gentlemen,
> :)
> | Thank you ALL very much for your most instructive replies. I will study
> | them all thoroughly.
> |
> | My question, however, remains:
> |
> | Why absolute address = segment *16 + offset, and not just
> | absolute address = segment + offset.
> |
> | So, why the division (first) and multiplication (back again)?
> |
> | I understand I can take it the way it comes, still, there needs to be a
> | sensible because to this why.
>
> Yes:
> Once Intel decided to make a CPU for larger memory than 64Kb,
> the designers were allowed to use a few more 16-bit registers
> to cover (the very huge range at this time) 1 Mb of memory.

Yes:
But surely the more logical scheme (even at the time...after all, this _IS_
how the 8080 managed its 16-bit addresses on an 8-bit chip...the same
"problem" just at a lower "bitage" :) would have been to use the exact same
"pairing" scheme yet again...except, simply, the addresses were now two
16-bit registers in a "pair" (e.g. "DS:BX") rather than two 8-bit registers
(e.g. "HL"), as was the case with the 808x...

Other points to note is that the "segment registers" were introduced by
Intel _SOLELY_ for the purpose of being the "upper part" of an address (not
"general-purpose" registers)...they could have - if "economics" was a
factor - have, say, used a _byte_ for "segment registers", bringing about a
24-bit "far" address (which is only an extra byte for the "far" pointer and
would cover their designed 20-bit address space...the extra four bits
possibly "ignored")...8-bit segment registers and 24-bit addresses - if
they were _insisting_ on this 20-bit address space stuff, not to consider
anything else - would have been even better "economics", surely?

Though, this "economic" factor does NOT seem at all convincing...after all,
they _DID_ put in full 16-bit registers exactly for this purpose...then
they "crippled" them down to a 1MB address space...that's a pretty
seriously wasteful way to go about things...so, "economics" doesn't ring
true as a factor in this decision...

That is, with my 24-bit "far" address here, that would only really waste 4
bits when "clamped" to a 20-bit address range (though, the bits could be
"wired up" in future to extend to 24-bits, which is a 16MB range, as time
went on...when "going 32-bit", they could extend it to 16-bits for the
"segment registers")...as "bad" as that might sound, the scheme Intel did
go with is _effectively_ wasting 12-bits (out of 16 total: That's quite a
large chunk of "waste" there) by "duplication"...

Also, thinking about the actual chip implementation itself, "addition" of
addresses would require more "die space", surely, than to simply to
"end-on-end pairing" instead? You know, with the "pairing", you literally
send the first 16 address bus bits from the "offset" and then the remaining
4 bits from the "segment"...literally just "sending them to the address bus
'as is'"...the "addition" scheme requires "messing around" with the values
in the registers before you send them onto the address bus...now, they
never did implement this, so I don't know for sure, but could it even be
that this cost us a "performance penalty"? If not in execution (because it
was nicely "optimised" in the hardware) then certainly from the perspective
that "die space" was used up for implementing the "address addition"
circuitry that could have been devoted to something else...another
instruction or more circuitry to improve instructions already
present...something like that...especially because, of course, they were
juggling around less "transistors" at the time...the "die space" a little
more "precious" back then because they couldn't pack as much onto a chip in
those days, as they can today...

On the contrary, the "economic" argument doesn't ring true at all...because
what Intel did finally go with was a touch "extravagent" (special "segment
registers" rather than just "re-using" the general-purpose registers, as
per what was quite typical prior to this...effectively wasting 12-bits of
these new 16-bit registers they'd introduced...eating up "die space" on the
more complicated "addition" operation)...I mean, in adding _full 16-bit
segment registers_ they _ALREADY PAID THE PRICE_ for a 4GB address space
but, weirdly, "crippled" it down to 1MB...so, it doesn't really sound like
it was an "economic" case because, you know, they _PAID_ for the 16:16
register pair but then delibrately _under-used_ it and required adding in
more complicated circuitry to deal with that "underuse"...no, no...it seems
Intel were not being at all "economic" here...they were being actually
really rather "extravagently wasteful"...

As I say, if "economics" were a factor then, logically, I'd say that 8-bit
segment registers for a 24-bit "far" address - 8:16 - without the
"addition" nonsense would have been the "cheapest"...yes, there would be a
lack of "symmetry" there...but, then again, if we look to the '386 and
32-bit, we can see that Intel don't have a problem with that because the
segment registers are _still_ 16-bit, even in "32-bit mode" for a 16:32,
48-bit "far" address...in fact, if we look at Intel's designs throughout
the x86, then "lack of symmetry" has _NEVER_ been a problem for them...

> Why:
> The decision for an even distribution of the 'new-16 bit' segments
> sounds logical (at least in the view from the past).

Hmm, I'm not sure...it doesn't sound particularly "logical" to me at
all...and Rene has replied to you here that he knew someone who was around
at Intel at the time, who didn't think it was particularly "logical"
either...plus, this is _VERY UNUSUAL_...no other common chip out there ever
did implement anything so "weird" as this...

"Economically", you're _PAYING THE PRICE_ for a potential 4GB address
space...but then delibrately _under-use_ it...that's not particularly
"logical" either...you know, it's like buying a Ferrari and then
"modifying" the engine so it's no better than a typical "family car" (buy
16:16 then "cripple" it to act as a 4:16)...like: Buy a "family car" in the
first place (buy 8:16 and just ignore the top 4 bits...if that sounds
wasteful to "ignore" the 4 bits (though, you don't have to do that...I'm
just assuming the "1MB address space" was a "set in stone" design decision
:), then just remember that the "real mode addressing" is far worse,
effectively wasting 12 out of 16 bits...far more wasteful a scheme)...it's
_cheaper_ for the same performance...

> Unfortunately all following CPUs, including late AMD/EMT64, are made
> backwards compatible to this ancient 8086 chip.

Yes; Ultimately, the true "blame" is with "backwards compatibility", in the
sense that it wouldn't particularly matter what "scheme" they chose for a
particular chip, if it wasn't for the fact that it has to be _RETAINED_
forever in the x86 line because of "backwards compatibility" philosophy...

You know, other chips also have their own faults, strange "design
decisions" and that kind of thing...but they can be simply _replaced_ with
a better chip later on...the problem with the x86 line is that it became so
successful that too much came to _depend_ on a "100% backwards
compatibility" scheme...

Intel daren't "break compatibility" with so important and successful a line
of chips...and, indeed, we can _see_ the various consequences that has
brought about...it's not just the "real mode addressing"...it's the 3-bits
encoding for registers, keeping them "stuck" at 8...it's some of the
"quirks" of protected mode (which you apparently don't particularly like
too much, wolfgang...can't say I blame you ;) because, of course, it had a
16-bit implementation in the '286 first before it's 32-bit implementation
in the '386...

As I mention in my other post here, you'll notice that the x86 line
_breaks_ what Intel have done with every other chip...the 4004 was 4-bit
and moving up to 8-bit with the 8008, they _started again_ with the
design...moving from the 8008 to the 8086, they _started again_ with the
design...and, in a sense, we can see that with the IA-64, they were again
trying to get back to the "start afresh" scheme (from an engineer's
perspective, this really is the most useful way to go about
things...changing "bitage" is a major upheavel that, if you could only be
"permitted" to do so by the "bosses", then _starting afresh_ is the best
approach)...but the '286 -> '386 "bitage jump" _breaks_ the trend that
Intel otherwise always typically kept to...

The underlying "reason" here is, of course, obvious once it is considered
that PCs are 90+% of all desktop machines in the entire world with an x86
sitting in the middle of them...with what has to be easily the largest
"catalogue" of software there's ever been (yes, even more than the Spectrum
had in games...that was always the Spectrum's chief "winning point" in its
infamous "battles" with the C64...it wasn't as good a machine but it could
easily claim far more available games software for it and, hey, the C64 was
hardly "lacking" in that department...remembering that a long "lead time"
in those days was a month or two, not years :)...

Basically, it's "business suicide" to mess around with the x86 line in too
"breaks compatibility" a way...I understand that perfectly...doesn't mean,
though, that I like it or that it isn't true to point out that if we
_didn't_ have "backwards compatibility", we'd actually have almost
certainly a far more superior machine and OS and software than we actually
have got...

That is, "backwards compatibility" is a _COMPROMISE_ solution...you _ARE_,
in fact, paying much the same "price" as would be paid for having to
replace all your software...but it's a "hidden" cost, being paid in terms
of "future progress" and not directly by users in having to fork out for
more software...the "price" of this, I would say, is _EQUAL_ to not having
"backwards compatibility"...the difference is _WHERE_ we're paying that
price...without "backwards compatibility", users pay the price _VISIBLY_ in
having to re-stock all their software (of course, the cynical attitude
points out that _we all do this ANYWAY_ thanks to the "upgrade" cycle...so,
_ARE_ we saving anything, in fact, in the long run? For example, the
original selling point of the PC with businesses was to point out to them
that it could be upgraded in a "piecemeal" fashion...add in more RAM,
change the CPU, stick it a soundcard, etc....that you could slowly
"upgrade" the machine over time, rather than simply dumping it in a skip
and buying a completely new system...which, of course, is a major cost for
businesses when they have hundreds or thousands of such systems to
replace...this seems "attractive"...but, these days, the "balance" has
actually changed - because they are so "mass-market" now that the price of
the hardware drops like a rock from an aeroplane and the speed of
development to better hardware so fast - that it tends to be cheaper to do
the "wait until this is obselete, throw it away and get a brand new
complete system" thing...because, you know, Windows has a new version and
it requires a 10 times more powerful machine that, in fact, to "piecemeal
upgrade", you're, in fact, having to replace so much of the system, it's
easier to just replace the entire thing...meaning that, ironically, the
"balance" has turned around that the "hobbyists" now do "piecemeal" while
the businesses don't, when it used to make more sense the other way around
at the beginning...but the "economics" of it all changed, as the PC has now
ended up in many a person's living room...you know, the computer games
market is now seriously more money than even Hollywood films...the
"economics" all shifted around ;)...

Anyway, yes...the truth, I'd say, is that you really _ARE_ still paying as
equal a "price" _with_ "backwards compatibility" as without it...it's just
the "price" paid is _elsewhere_...it's not directly visible...consider that
this "real mode addressing" scheme was actually a pretty serious and
long-lasting "obstacle" for progress...you know, software "stuck" in 16-bit
for a decade or so after the '386 chip technically made it
unnecessary...that, quite significantly, all technologies are currently
grounded - and not really that much more "mature", despite the time passed
by - in '60s and '70s and early '80s stuff...because everything has to be
"compatible" with UNIX ('70s) or x86 ('70s) or whatever...

Note that it's not that this "legacy" is "wrong" in any way...it's great
stuff...but it's "shackles" around our feet...it's a "ball and chain"...the
"price" is in "missed opportunity" and the problem with any price measured
in that nebulous "unit" is that people don't directly or visibly see
it...or, at least, some of us here talk about how software is actually
still in "crisis"...that, relative to hardware, it's actually _getting
worse_, not better...lazy and bloated coding...BUT the problem with
convincing people of this argument is that if you don't directly see what
you're "missing", you don't realise what the problem even is..."you can't
know what you can't know", as the saying goes...you can only see it
"through the cracks" where, as I like to post from time to time, someone
has actually gone to the _effort_ of extreme non-lazy, non-bloatware coding
(mostly in things like "demos", admittedly...but the principle _COULD_ very
validly be extended elsewhere...it's just, you know, no-one wants to code
or see an "extreme spread*** demo!"...the "demos" are done for
"entertainment" and that's just not a particularly "entertaining"
thing...useful, productive, etc....but not "entertainment"...it's not that
other software couldn't also be better coded like these demos exhibit, it's
just no-one's really very bothered in general to even attempt to do so
:)...otherwise, people just aren't even "aware" that something might be
"up" with software...

> Protected mode was the attempt to make segments larger, but here some
> paranoid influence for protection made the story needless complicated.

In fact, there _COULD_ be a point of significance here...

Let us remember that Intel and IBM didn't only make microprocessors for
home computers...their biggest customers were, in fact, businesses and
"mainframe" systems...

The concept of "device drivers", for example, originated in those
"mainframe" systems but, in time, the PC adopted these things as it become
more powerful...the use of an on-chip MMU unit that implemented
"protections" is another "inheritance" passed down from
"mainframes"...mainframes, of course, were inherently "multi-tasking,
multi-user" systems by design...one "big computer" sitting in the middle
and then "dumb terminals" (a keyboard and a monitor, no real processing
power at all there :) hooked up to that mainframe...

Hence, mainframes _NEEDED_ this kind of "protections" device...you know, if
you're running a mainframe in a business or university or something, then
you could have _hundreds_ of user logged on, all running _many_
programs...now, if my copy of Windows 98 "blue screens" on me in the middle
of doing some word-processing, then, okay, I'm really pissed off...but,
fine, I reboot and I start again...it's just me as the sole user and I'm
only really using this one bit of software...

But the situation is markedly different for a business with this
"mainframe" style of system...imagine it's some telephone "call
centre"...and all the telephone operators are in front of "dumb terminals"
attached to the central mainframe...okay, no problem...the mainframe "time
slices" between all the users and all the programs, so that everyone using
the system is able to do their work...work which is basically taking down
"customer details" and things like that: Accessing the "database" on the
mainframe...

Our problem is this: One telephone operator does something they shouldn't
or triggers some "bug" in the software and - BANG! - it crashes...problem
is, with a mainframe design, it's _all_ processed - every single program
and user - on the "central mainframe"...hence, if the program crashing is
allowed to bring down the mainframe then, oh boy, does it cause _MAJOR_
damage..._ALL_ telephone operators find every single "terminal"
crashes...the last "back up" was an hour ago...all data since that point
just went to "digital oblivion"...there's going to be quite a cost attached
in trying to get that data back (including possible "loss of custom" when
your customers aren't particularly impressed by you phoning them back -
_IF_ you didn't lose their telephone number in the crash that you're just
completely screwed, waiting for them to contact you - to ask them to repeat
all the information all over again...doesn't inspire "confidence" in the
competence of your company when this happens far too often to their
customers ;)...blah-blah-blah...

Hence, it's somewhat "implicit" in the mainframe design...it's not just
"convenient" but is _essential_ that a single program crashing just CANNOT
be allowed to bring down the entire system...that is, essentially, where
all this "protections" stuff comes from...and when the PC was moving into
"multi-tasking" areas, then some hardware "protections" would come in handy
for much the same reasons...you know, it's very nice that Linux can happily
give you an "uptime" of _many years_ in extreme cases (oh, reminds me of
that hilarious comment about needing to reboot the machine: "As everyone
knows, the machine can only actually do work whilst switched off"...a
genius sarcastic comment there ;)...

Okay, so what does this have to do with anything? Well, the "why?" of
"segmentation" being introduced to the 8086 could have been simply Intel
"jumping too early" in wanting to introduce "mainframe"-like functionality
into their processors...an alternative to being "too short-sighted" is that
it could have been the complete opposite of "thinking too far ahead"...and
then thinking "oh, we'll put these segments in now and can later add
'protections' to these segments" (after all, they _DID_ exactly so with the
'286)...the problem with that is that it was "jumping too early" to do this
with a 16-bit machine, really...

Or, at least, that is another "possibility" behind their otherwise rather
"weird" choice of using "segmentation"...they were thinking in terms of
"mainframe" designs and trying to "migrate" it downwards to the
microprocessors..._THEN_ it begins to make some kind of sense...you want to
"segment" the memory into 64KB "chunks" so that multiple 8080-based (64KB
limited) older software could be run _multi-tasked_ together...after all,
you _DON'T_ strictly need "protections" to do multi-tasking itself (just a
"timer interrupt", really :) but it just makes things "neater"...

Ah, of course...that probably _IS_ it...Intel were seeing "converted" 8080
programs being run with _multi-tasking_ capability on their new "16-bit"
chip...and took this "design decision" to make that possible and easy...and
the basic problem was: NO-ONE TOOK ADVANTAGE OF THAT AT ALL...you know, DOS
on the PC was single-tasking...and the expectation of lots of "converted"
8080 software (because it had been a _very successful_ chip for Intel)
moving across didn't really greatly materialise...so, there was a "why?"
but this "why?" never actually happened as Intel expected it to...leading
to the fact that software was trying to run in a completely different way
on a chip with a design intended for something else...no wonder it was such
an awkward bugger, eh? ;)...

Remember, before Sir Bill "renamed" it, MS-DOS was originally QDOS...and
that stood for "Quick and Dirty Operating System"...or, in other words,
even for the time, this was NOT considered a particularly "clever"
OS...even its own author called it "quick and dirty"...so, yeah, it took
the "easy route" throughout...single-tasking, basic memory management,
simple file system, etc....NOT taking advantage of the capabilities Intel
had "planned" that the 8086 would be typically used for...indeed, a "cheap
half-port" of a CP/M-like system, its design was based on the capabilities
of a _completely different system_, in fact...

Intel pulling in one direction, IBM in a different direction, Microsoft in
yet another different direction...

Note that Intel did directly start trying to put "mainframe"-like stuff
into their 432 and 960 processors, imaging a future of "personal computers"
with "mainframe" capabilities (the only accurate assessment, in fact)...IBM
were seeing PCs as a "fad" and saw their future in selling mainframes (the
PC merely an "afterthought", seeing Apple Macs taking over people's
desktops and, as the original "evil empire", didn't like to see
_competition_ sitting in their otherwise "all IBM" customers' offices
:)...Microsoft were just seeing an opportunity for "quick and dirty"
profit-making by selling someone else's software "re-branded"...future?
What future? *Bill's eyes glazing over with dollar signs* ;)...

Considering that they weren't seeing "eye to eye" in any regard at all,
then it's perhaps actually miraculous that the x86 line wasn't torn apart
any more than it actually was...after all, software needs hardware...and
hardware needs software...and the same basic thing happened _yet again_
when Intel introduced "32-bit protected mode" but Microsoft couldn't really
be bothered to do much with it for a decade or so...IBM asked them to do
OS/2 but, well, this is Microsoft...once they got what they wanted, they
just walked...NT actually used "protected mode" more properly but then,
again, "someone else's code"...hired in ex-VMS programmers to do that and
only because businesses were annoyingly asking for something more
"robust"...

Speaking of which, does any OS actually bother to use anything other than
"ring 0" and "ring 3"? Or "supervisor" and "user", as all other chips
typically think of these as being? True enough, wolfgang, it is a touch
"unnecessarily complicated"...proof of which is that all OSes stick solely
with "ring 0" and "ring 3", using "flat mode"...or your OS just uses "ring
0" throughout...and I would think that it actually makes sense (if you want
"security" and "protections") to do the opposite and actually run nearly
_everything_ in "ring 3" (because with the "I/O permissions bitmap" and
"memory mapping", you can actually "grant" a ring 3 program all the
"access" it needs for hardware access and such...why does it have to go
into "ring 0" anyway? You solely need _ONE_ program running in "ring 0" to
have the capability to "grant" the various "permissions" to other programs,
by checking up the "security" to do so...a "nano-kernel", so to speak, in
that _only_ the tiniest "security" module need be "ring 0" and everything
else - including many things usually attributed to being "kernel", like a
memory manager and such - runs as "user code" throughout..."ring 3" ->
"ring 3" transitions are just as "lean" as your "ring 0" -> "ring 0"
transitions for "performance", wolfgang...the extra expense comes from
"checks" when switching "privilege levels"...as you yourself have worked
out: Then just "don't"...the minor difference is that I'm thinking of "all
ring 3" rather than your "all ring 0"...then you can get this same
"performance" thing while "security" and "protections" would be possible
too...just the _one_ very small "security" module that runs "ring 0", in
order to "grant" permissions to other modules (just to make sure "security
permissions" are correct...useful if going for "multi-user" design)...you
know, just "opens a hole" in the "I/O permissions" for direct I/O access
and can "map in" memory for a process too...and then the program should be
able to do "direct access" without suffering any problems or obstacles in
its way :)...

Actually, wolfgang, as you've written an OS already, does this idea
actually sound like it would work? I know for your design, you're not
bothering with "security permissions" and such, so the "ring 0" stuff makes
sense with that design...but just imagine that we want this "security" and
"protections" stuff...would this approach - make it all "ring 3" with just
the one small "ring 0" module to "grant" direct I/O and memory accesses -
actually still be reasonable with "performance"? Because I'm thinking that
a program would only "ask for permissions" _ONCE_ when it loads up and,
thereafter, it could then "direct access" all it likes until
termination...so, you'd only get the "ring 3 -> ring 0" transition stuff
very rarely...just typically once per application when it loads...you know,
instead of _constantly_ "asking for permission" by doing everything via OS
API, the idea is that you just ask the OS _ONCE_ "can I access the hard
drive directly, please?" (which is _solely_ a "security" thing to make sure
that the "user" has the correct "permissions" to be doing such things...you
know, stopping your 8 year old cousin walking up and screwing up all your
work by only allowing "delete all files" to be executed by the right
"login" user account :)...and then it's "granted" for the program - a
"hole" in the "protections" is opened through which the program can happily
work through - so then it can "direct access" the hardware and doesn't get
any "general protection faults" doing so...

Of course, "micro-kernels" and Linux and such do more or less basically
work in this kind of way already...but a case of "taking it to the
extreme"...make absolutely _everything_ "user code"...except for,
obviously, the necessity that _something_ is "ring 0" in order to be alter
the memory tables and "open up holes" in the I/O range...which, logically
enough, would be some "security" module, who's only job is just to make
sure that it's a "legitimate" request (that is, it checks that the program
accessing for direct access to the GDT and IDT is, indeed, the "memory
manager"...or that the "guest" user account is allowed to wipe out the
entire hard drive...or that the program claiming to be the "video device
driver" really is what it claims to be before giving it the run of the
video system...just a case of "checking security permissions" with the user
account details and, if it all checks out properly, then, yeah, give the
program all it wants for "direct access" :)...

Under this scheme, then "device drivers" would, in fact, be absolutely
nothing "special" at all...they are just ordinary programs that are acting
as "libraries" for other programs to call that do the "direct access" on
their behalf...so both "direct access" and "device drivers" are equally
possible (device drivers do have some useful practical uses...you know,
"regulating" programs trying to "share" the same hardware or just the
practical thing that with so many different video cards out there, then
writing "direct access" for them all is too impractical...though, as I say,
this would equally allow both so you could have the interesting possibility
that a program uses the "device drivers" unless it's a particular piece of
hardware it "recognises" to "direct access"...a half and half solution, so
when you have the right hardware, performance is improved but it can still
be made to work with "unsupported" hardware too by doing that kind of stuff
via the "device driver" :)...the only real distinction between a "device
driver" and an ordinary program is that the "device driver" does "direct
access" and acts as a "library" for other programs and "registers" itself
with the OS as being the "device driver" for a particular device (so that
when applications ask: "is there a device driver for this device?", the OS
can reply: "yes, this program registered itself as being exactly that"
:)...

It's like "micro-kernel" but, well, it's all a bit weird that you have to
constantly jump from "ring 3" -> "ring 0" and back again, just to ask the
OS to tell you what the time is or get the user's login name or to write a
character to a file or whatever...it's, like: "why does it need to be ring
0 for that?"...it doesn't, really...and, taking this to the extreme, then,
really, only _one_ "module" strictly needs "ring 0" and that's the
"security module" which is just there to hand out "privilege" to other
modules...or, at least, that's the "theory"...

Another OS related idea is with scheduling...because the usual "round robin
with priorities" is doing an awful lot of constant interrupting...if it
interrupts too often and switches tasks all the time, surely this isn't
actually particularly good for the "cache memory"? You know, something
like:

A -> B -> C -> A -> B -> C (blocks) -> A -> B -> A -> B -> etc.

...could be more efficiently done as:

A (x4) -> B (x4) -> C (x2 then blocks)

...needing only two "task switches" rather than some 9 task
switches...after all, these take up CPU time to do the "switch"...plus, if
constantly switching between them - and they all reside in different
"address spaces" - then the "cache" is going to be all over the
place...filled up with A, emptied out and filled up with B, emptied out and
filled up with C, emptied out and filled up with A again, emptied out and
filled up with B again and so forth...the "cache" is "least recently used",
after all...and if we're switching around to completely different address
spaces all the time then "recently used" has often nothing to do with
what's now going on...

So, simply, the basic idea is to give the program as long as possible with
the CPU...but there is a "conflict of interest" that we also want to be
switching often enough for that "optical illusion" that we're running many
processes at the same time...

Hence, my new little idea about the "scheduling policy" is to perhaps have
a _dynamic_ "time slice" system...that is, we decide that we need to go
through every program at least once every 1/60th of a second (that is, this
is the "frame rate" of the monitor...if every program gets a fair share of
the CPU in this time then, visually, we'll have our "optical illusion" that
they are all running at the same time...because, every frame, they all
appear to have done something :)...

The problem, of course, is that if we've got two processes running then for
each program to run once within 1/60th of a second would mean they each get
1/30th of a second each...BUT, with three processes, they would need 1/20th
of a second each...4 processes: 1/15th of a second...

BUT, then again, launching and terminating processes just _doesn't_
constantly happen all the time...you know, the user runs a program, the
process starts...they hit "close" and the process then terminates...it's a
comparatively "rare event"...

So, here's the simple idea: The scheduler has _dynamically-sized_ "time
slices"...whenever new process starts or a running process ends, the
scheduler then "adjusts" that "time slice" size so as to give each process
the CPU for the _maximum_ amount of time that it can, allowing for the need
for it to do a full "round robin" of all processes within a set period to
get that "optical illusion" thing going...

Less task switching, longer uninterrupted runs of each process, better
cache use and so forth...should help to improve the system's overall
performance...BUT, as the "dynamic time slice" is exactly re-calculated
whenever the number of processes changes (part of the "StartProcess" /
"EndProcess" kernel code and then just "informs" the scheduler of its new
"time slice" size :), it can maintain the "optical illusion" stuff
perfectly well...

In short, the underlying idea is that we have "throughput" and we have
"responsiveness"...and the idea of having the "dynamic time slices" is that
we can generally "re-calculate" the "balance" between the two all the time,
as processes start and end, to try to maximise both (as the situation
demands)...so, when there are just two processes, we want each to run at
least once within, say, the "refresh rate" so that they both _appear_ on
the monitor to be running "simultaneously", as both have updated their
graphics within each "frame" on the monitor...but we don't want to
interrupt them more often than is necessary to do that, really...so, if the
refresh rate is 60fps and there's two processes, we can calculate 60 / 2 =
30...right, we "task switch" at 30Hz...another process starts - this'll
change things - so we re-calculate our "time slice size"...60 / 3 =
20...okay, we then change to a "task switch" at 20Hz...one of the processes
stops, so we switch back to 30Hz...two more processes start, we then "task
switch" at 15Hz...

You see what I'm doing here? We do our best to re-calculate the "optimal
task switch frequency" whenever a process starts or stops (which is,
comparatively speaking, an "infrequent event" :)...so, as to constantly and
dynamically try to keep the system's overall performance as "optimal" as
possible...

Note that, otherwise, of course, everything else is "as per normal" for
"pre-emptive multi-tasking"...so, processes will, of course, "block" when
they need to wait for an "event" to happen and don't take up any CPU time
at all..."priorities" can still be applied and higher priority tasks are
scheduled first...and so on...it otherwise works in exactly the same usual
way...

The only slight difference is that instead of setting the "time slice"
really low at a fixed rate of, say, "so many thousand times a second", it's
a "dynamic" thing...the OS can "re-adjust" the size of the "time slice" as
is appropriate to the amount of processes currently running, active,
blocked or whatever...

And the reason for this is quite simple: The "demands" on the system are
constantly changing...so, really, the scheduler should be constantly
changing too, to reflect the current "demands"...then it can "maximise" the
performance and the throughput by giving each process as much time as it
possibly can with the CPU uninterrupted...also, simply, less "context
switches" for no apparent reason (after all, though quick by design,
context switches themselves do not take up zero time...how much CPU is
spent on simply switching "contexts" so many thousands of times a second?
:)...

It's a kind of "compromise" idea between all the various "demands" we have
to satisfy..."throughput" vs. "responsiveness"...changing often enough to
give the "optical illusion" that we're running more than one process at a
time but not so often that, in fact, we're wasting a not insignificant sum
of CPU time on constant "context switching" thousands of times a
second...the point is that there is really a "balance" to be struck here
between various - often conflicting - "demands"...so, seems to me that a
simple idea is to make the "time slice" a _dynamic_ quantity...that it can
be _changed_ as "demands" on the system change...and, yeah, we can
concentrate - all other things being equal - on "maximising performance"...

Beth :)