Re: Shared libraries and modules
- From: Theo Markettos <theom+news@xxxxxxxxxxxxxxxxxxxxxx>
- Date: 06 Nov 2008 22:14:32 +0000 (GMT)
Keith Hopper <kh@xxxxxxxxxxxxx> wrote:
In article <lFz*FnXqs@xxxxxxxxxxxxxxxxxxxxxxxxxxx>,
Theo Markettos <theom+news@xxxxxxxxxxxxxxxxxxxxxx> wrote:
I don't quite understand this. There are two basic implementations of
stacks:
'A stack of 32 bit words'
'A stack of pointers'
Ooohh! No! What about a stack of 4-bit objects or 8-bit ones or
80-bit ones??? Think of the inefficiencies of using 32-bit instructions
willy-nilly when handling UTF-8 or UTF-16 or double length floats or many
enumerations - very few of which exceed 8-bit spaces.
But given the memory architecture it's quick to load a 32 bit word, but it
isn't quick to load 4 bits from a packed array. Unless you're dealing with
millions of data elements the space implications are minimal. If you're
bothered you compile optimised for space not time, but nobody does on the
desktop.
This is rather a trivial example, and not many people will care if we repeat
the code 10 times. Can you think of bigger cases where polymorphism might
be useful? I can think of cases at the high level ('do you want to pay by
Mastercard or Visa?' - much of the basic processing is the same but there
are some differences) which are more like derived classes in an
object-oriented view but none that would be similar enough that they could
happen at instruction level.
I don't know how functional languages compile polymorphism down to
assembler.
I'm perhaps old-fashioned, but I know that many architectures are more
efficient when using narrow octets, hextets, than with register wide
manipulations and shifts, etc. I'v always been concerned to minimise times
AND space when writing a code generator.
I'm afraid that superscalar processors these days are suitably complex that
attempts to make things quicker sometimes have the opposite effect. Modern
architectures have wide registers, and when you fetch from memory you get
the whole cache line for free. The aim is to reduce cache thrashing,
branches/branch mispredictions and dependencies between instructions - not
things the average 'tight' 1980s-style programmer thinks about. We've
also suddenly rediscovered the need to exploit parallelism in programs as in
instructions - again something programmers find difficult.
Generally the big problem today is managing the complexity of programs:
while it may be possible to mow Wembley Stadium with nail clippers and get a
perfect finish, it's not an efficient use of your (the developer's) time. A
ride-on lawnmower isn't as neat, but it'll get the job done sometime quicker
than next month.
Very definitely not! If a program in a class-based language wished to
have a garbage collecting memory management facility then this could
seriously affect the whole machine memory managemtne if it isn't done under
the OS (so to speak).
OK. I heard an interesting lesson from someone who worked on the Squid web
cache. Squid has its own disc caching system. He discovered that it's more
efficient to throw away the disc caching. The reason being it was fighting
against the OS: he would load a cached file from disc into RAM, and the OS
would immediately swap it out again. It was more efficient to let the OS do
the caching in its own way, and not try to do it yourself.
What about languages using exception mechanisms - I am horrified at the
way that all fomrs of asynchronous transfer of control are around so that
no program - unless it implements its own exception mechanism can treat
all of them in the same way - unless this is done under the OS (again so
to speak), then it becomes a bolt-on obfuscation of implementation code
which makes a nonsense of code efficiency.
What about threading/processes, etc. Various models of multi-threading
exist and, so far as I am aware, each one seems to be bolted onto the
outside of the OS.
Dynamic code generation requires all sorts of convolutions to
interface it to the OS properly if you don't have a low-level interface to
the 'exec'(say) loader.
Fair enough - I agree these need some level of OS support.
It is my contention that these sort of things are - if efficiently
implemented the micro-kernel of an OS - everything else is dynamically
loadable 'modules' and 'libraries. We really do need a new approach to
object OS architecture to improve efficiencies and permit any programming
language to define its own RTE to interface directlyt with the
micro-kernel.
I sort of see what you mean, but these are effectively OS-level
functionality because they need some degree of privilege. Currently you put
it in the OS, or in an OS support module (it would be virtual device driver
or similar on Windows, a kernel module on Linux) or farm it out to something
in userland (like FUSE userspace filesystems on Linux, which have a usermode
process to do the actual FS stuff). I can see you might want a
slightly-more-privileged layer here.
What about distributed programs which really need to be below the IP
level so far as comms and interrupts, etc are concerned?
At layer 2 you mean? Quite often programs are blocking with something like
select() (which I assume also works for layer 2 file descriptors too). On
RISC OS that's a problem because it holds everything up, but on Unix it just
means the process sleeps until it gets some activity. Then it's woken up
when something happens.
The RISC OS equivalent is a pain to program for. Unless you're using
TaskWindow, you're not allowed to block because that'll hold up the desktop.
You get an event on your socket when something happens. You need to go back
to sleep when you've done your thing. So you have to write your code as a
big state machine, where an incoming event causes you to transition into the
next state(s). When you transition you do some work (process, send some
stuff), but as soon as something might block you have to relinquish control
and return from your event, and make a note of what happened so you can take
it up next time.
That model's fine from a trivial remote procedure call point of view
(receive a small event, formulate your response, send it back all in one go)
but anything more complex is a pain (what if you want to receive an event,
process it, then send it on somewhere else? You have to manage two
connections which could block at any time, even in the middle of a command
string). This means you either need a big state machine, or some way to
generate that state machine automatically. It's much easier to have the OS
hold the state for you and operate in a quasi-linear flow.
Frankly, I'm not interested in what commercial organisation do or wish
to do - only in getting it right - whatever that may mean for any
individual language designer.
I should add that I'm not up with current research so I may be out of date
as to modern design.
Theo
.
- Follow-Ups:
- Re: Shared libraries and modules
- From: Keith Hopper
- Re: Shared libraries and modules
- From: Rob Kendrick
- Re: Shared libraries and modules
- References:
- Re: Shared libraries and modules
- From: Keith Hopper
- Re: Shared libraries and modules
- From: Theo Markettos
- Re: Shared libraries and modules
- From: Keith Hopper
- Re: Shared libraries and modules
- Prev by Date: Re: More government snooping
- Next by Date: Re: More government snooping
- Previous by thread: Re: Shared libraries and modules
- Next by thread: Re: Shared libraries and modules
- Index(es):
Relevant Pages
|