Page 1 of 2

virtuality (from "Your OS design")

Posted: Tue Aug 09, 2005 7:29 am
by JoeKayzA
@Legend: And there are several other advantages. I am one of those, who believe (despite the widespread opinion) that such a system could even perform _better_ than a 'traditional' operating system, executing natively compiled C/C++ code and isolating them by virtual address spaces. These are my arguments:
  • Privilege levels: Since all the code that is executed on the system is generated by the JIT-Compiler (which is trusted), all the code can be considered trusted, thus executing it at ring0. A system call needs no ring transition any more.
  • Memory Management: When you involve a copying garbage collector (that every application uses), additional memory optimization at runtime can be done. Also, this garbage collector could take care of swapping (writing an unused object to disk and reuse its memory), swapping takes place at object level rather than page level, thus the need for an mmu would disappear. It remains to be seen however, whether the mmu could still be used to improve performance (dirty bit to determine how often a memory region is used...).
  • Runtime optimization: In traditional natively compiled code, any optimization has to take place at compile time. When code must be compiled seperately for portability or manageability reasons (driver <-> kernel <-> syscall-library <-> app <-> utility-lib), it must be linked seperately. When the native code is generated at load time by the JIT-Compiler, any optimization can be carried out there, the code could be profiled at run-time and recompiled with different settings to achieve the best results. As a side effect, the code will also be architecture independent ;D. Note that optimization also covers inlining of procedures, which is then possible for functions that reside in a different library, or even in the kernel (when there still is a construct like a kernel).
  • Usage of privileged instructions: For very short critical sections, the JIT-Compiler could simply disable interrupts to prevent concurrent access to a memory location/device, instead of acquiring a lock.

What do you think about this? I had a more detailed design on my VM-OS somewhere about 2 years ago, it was quite inspired by J2EE at that time. I'll write something more about it when you are interested.

cheers Joe

Re:Your OS design

Posted: Tue Aug 09, 2005 7:52 am
by Colonel Kernel
I've thought about the same kind of VM-based design, and eventually I came to the conclusion that you'd still need the MMU, even if you don't need it for protection. Here's why:
  • You will eventually run out of physical memory, so swapping to disk is still a good idea. Paging is the fastest and most efficient way to do that IMO.
  • Even if you don't run out of physical memory, if you're on a 32-bit system you will eventually run out of address space. This might not be as much of a problem on 64-bit systems, but if you use paging and multiple addresses spaces you definitely won't run out.
The other thing to note is that there should be more than one garbage collector.
  • If you have only one GC in the system and it manages all memory for all applications, then individual collections will take longer.
  • Generational GCs won't work very well in such a system because the system-wide memory usage patterns will be more "noisy" than they would be on a per-application basis.
  • If the GC is allowed to vary per-application, then it can be optimized for that application (e.g. -- ASP.NET has its own GC that is tuned for web apps and web services; the .NET Compact Framework has its own GC, etc.).

Re:Your OS design

Posted: Tue Aug 09, 2005 8:14 am
by AR
I've already had an extensive argument/discussion about the effectiveness of Virtual Machines. As far as I can see bytecode offers no advantages in "correctness", you have as much chance of determining that as with raw machine code. The thing people never seem to understand is that machine code is bytecode, the CPU interprets the bytecode and performs the operation. Essentially the VM just creates a virtual CPU that does the same thing as the real CPU but is 100s of times slower (manually decode the instruction opcode, decode the operands, perform the operation - by the time you actually perform the op you've already used 100s of clock cycles with no direct benefit). Sure the VM's emulated CPU can have operations that you think are more secure, but then you may as well manufacture your own CPU. The Java people already tried this (an extension card that executed Java bytecode in hardware), I'm not about to buy extension cards to run programs when my main CPU is perfectly capable of running exactly the same types of software. JIT alleviates this to a certain extent but it still requires rather pointless runtime interpretation, the results will generally always be the same on a particular CPU anyway (The .Net libraries themselves are compiled during the install process for example).

Architecture independance is about the only real advantage of byte code, but then why not just distribute the raw source code and compile that, it's more or less the same (and actually better since the higher up you are, the more interconnections you can see and the better the optimizations can be).

You also cannot abolish locks for the simple reason that locks aren't used as often in single CPU mode. Locks are needed primarily in multi-CPU mode where disabling interrupts won't stop the other CPUs from running over you.

Re:Your OS design

Posted: Tue Aug 09, 2005 8:52 am
by JoeKayzA
AR wrote: JIT alleviates this to a certain extent but it still requires rather pointless runtime interpretation, the results will generally always be the same on a particular CPU anyway (The .Net libraries themselves are compiled during the install process for example).
??? What runtime interpretation do you mean at this point? I don't see a difference between JIT compiled virtual bytecode and the code a compiler produces, the point was just that the compilation step takes place at a different point of time. So why should it be any slower?
Architecture independance is about the only real advantage of byte code, but then why not just distribute the raw source code and compile that, it's more or less the same (and actually better since the higher up you are, the more interconnections you can see and the better the optimizations can be).
In my view bytecode is, technically, source code, however not that verbose and human readable. Not everyone wants to distribute source code to the public. My emphasis was not that you need bytecode to accomplish the above advantages, of course you could also replace bytecode with (scripted) source code (such as ruby), and JIT-compile this instead, the result will be the same again.
You also cannot abolish locks for the simple reason that locks aren't used as often in single CPU mode. Locks are needed primarily in multi-CPU mode where disabling interrupts won't stop the other CPUs from running over you.
That's a point, I have to admit. ::)

cheers Joe

Re:Your OS design

Posted: Tue Aug 09, 2005 9:43 am
by Brendan
Hi,
AR wrote:Architecture independance is about the only real advantage of byte code, but then why not just distribute the raw source code and compile that, it's more or less the same (and actually better since the higher up you are, the more interconnections you can see and the better the optimizations can be).
There are problems involved with distributing raw source code. Firstly, while most languages are "mostly portable" the libraries aren't completely compatible or in some cases aren't even present (otherwise we wouldn't need things like "autoconfigure" - compile Bochs to see what I mean). The other problem is that commercial software vendors don't want to supply their source code for everyone in the world to see (I won't list reasons for this).

If you distribute "byte code" instead, then it can be entirely portable (if your byte code has a standard set of libraries that behave identically on all platforms, or if the language is high level enough not to need libraries). This byte code can be interpretted (great for debugging), run using JIT compilation, or compiled into native/binary code on the target machine (just like source code). If the tools to interpret or compile the byte code has built in decryption, then other people can be prevented from reading the source code.

This is the sort of thing I'm considering (for the future - it won't be this week). The OS would have a single standard "byte code" language, and things like HLL source code, shell scripts, etc would all be converted into this byte code.

Imagine you write a big shell script or batch file to compile your project. The first few times it's used the OS would convert it to byte code and interpret it. The next few times the OS decides to use a JIT compiler on it, but after more use the OS compiles it into a highly platform dependant binary.

Now imagine you've got a large project written in C. You'd compile it from C into byte code and then distribute the byte code - no need for autoconfigure or configuration scripts, no need to check if the "foo" library is present on the target machine, no confusion about how long a "long" might be, etc. Again, the first few times the user runs it it might use the JIT compiler (with a large heap of error checking). Perhaps the user doesn't trust the software and tells the JIT compiler to limit memory usage to 8 MB, or to tell them about all network traffic going to/from the application, or file IO. The JIT compiler could display a message "This app crashed at line 1234 in original source file 'foo/bar.c', please email the following auto-generated error report to the author at [email protected]".

After a while the user (or OS) might decide it's been tested enough and compile it into a highly platform dependant binary (without all of error checking). Perhaps the application is always converted directly into a platform dependant native binary when it's installed? Maybe it depends on what the system adminstrator configured the OS to do...

There's a large number of features and benefits that could be included in a system like this, without any real performance problems.

I say all this, because IMHO there isn't much difference between a "byte-code" language like this and a virtual machine (same thing, different words).

Of course for my purposes, "platform independant" would mean "portable to another version of my OS running on different hardware". Portability between my OS and Windows, Linux, DOS, whatever, is not desirable (these OSs can all go in the bin when I'm finished my OS ;D).


Cheers,

Brendan

Re:Your OS design

Posted: Tue Aug 09, 2005 11:39 am
by Legend
AR wrote: As far as I can see bytecode offers no advantages in "correctness", you have as much chance of determining that as with raw machine code.
You can verify a native program to be a program written for the x86, but that does by far not mean that it would be trustworthy to be put into an address space with a lot of different other programs.

@Joe: Well, I have to agree with brendan, I think swapping using paging will still be more efficient. The biggest issue is that you would have to check for yourself on every access to an object if it is swapped out, unless I'm missing something very obvious here.

Another good thing (that probably could be applied to native code) is that the linking at run time solves some problems that appeared with for example C++, like binary stability of libraries.

Re:Your OS design

Posted: Tue Aug 09, 2005 12:05 pm
by JoeKayzA
@Joe: Well, I have to agree with brendan, I think swapping using paging will still be more efficient. The biggest issue is that you would have to check for yourself on every access to an object if it is swapped out, unless I'm missing something very obvious here.
OK, that's true, I don't see how you could implement this efficiently... I was thinking of resetting all the references to an object by an invalid address when you swap out the object. (Since it is a copying garbage collector, this must be possible) Then, when some code tries to access it, it genererates a fault and the object will be fetched from disk again. The problem is, without a MMU, there is no invalid address ::), that triggers a fault.

cheers Joe

Re:Your OS design

Posted: Tue Aug 09, 2005 12:08 pm
by Legend
Another thing, where I'm very doubtful (not about the design but garbage collectors in general) is the stop & copy collector. Not only does a copying garbage collector halt the vm, I'm really sceptical if the overhead of copying things around in memory is not probably higher then what you could save on allocating. On the other hand, they seem to be very much liked, but I didn't get it really till now.

Re:Your OS design

Posted: Tue Aug 09, 2005 2:25 pm
by Colonel Kernel
AR wrote: As far as I can see bytecode offers no advantages in "correctness", you have as much chance of determining that as with raw machine code. The thing people never seem to understand is that machine code is bytecode, the CPU interprets the bytecode and performs the operation. Essentially the VM just creates a virtual CPU that does the same thing as the real CPU but is 100s of times slower
You're describing only one point on the spectrum that I'm familiar with -- interpreted Java bytecode.

If bytecode indeed mimics machine code, then yes, you can't verify if it's safe. This is exactly why IL (the intermediate language used by the CLI a.k.a. Mono and .NET) is not like Java bytecode in that it simply cannot be executed in hardware. It's too abstract for that. It's awkward even to interpret it, which is why it's always JIT-compiled.

My understanding of IL is that it has a "safe" subset that only deals in object references and field offsets, not directly with memory addresses. This means that for a certain class of programs, you can prove whether or not the program is typesafe simply by looking at the IL and corresponding class metadata. If you can't prove it for a given program, make the (safe) assumption that it's unsafe.

I don't want to resurrect the whole VM argument again :) -- I just want to clear up this misconception about bytecode. As far as I'm concerned, Java-style bytecode is not the only way (and certainly not the best way) to do things.
Well, I have to agree with brendan, I think swapping using paging will still be more efficient.
LOL... Now all of Brendan's vast knowledge is being attributed to me? I feel honoured. ;D Or is it the other way around...? ;)

Re:Your OS design

Posted: Tue Aug 09, 2005 2:30 pm
by Colonel Kernel
Legend wrote: Another thing, where I'm very doubtful (not about the design but garbage collectors in general) is the stop & copy collector. Not only does a copying garbage collector halt the vm, I'm really sceptical if the overhead of copying things around in memory is not probably higher then what you could save on allocating. On the other hand, they seem to be very much liked, but I didn't get it really till now.
As with most things, stop & copy GC works well for a particular type of application behaviour. A generational stop & copy GC like the stock GC in the .NET Framework works best with small allocations where the objects in memory tend to be either very old and live long, or very young and are short-lived. The very old ones are down at the bottom of the heap, while the young ones get created and collected fairly quickly. This is how you can sort them into "generations". A generational collector will only deal with the young objects on top of the heap during a typical collection, to keep the interruption to a minimum. In practice, the .NET GC can collect in about the time it takes to satisfy a page fault.

The other thing to remember about GC is that it saves you from having to do a lot of bookkeeping in your app -- reference counting, deep chains of destructor calls, etc. All this overhead goes away with GC (although deterministic destruction is still nice to have for non-memory resources IMO).

Re:Your OS design

Posted: Wed Aug 10, 2005 2:19 am
by Legend_
Colonel Kernel wrote:
AR wrote:
Well, I have to agree with brendan, I think swapping using paging will still be more efficient.
LOL... Now all of Brendan's vast knowledge is being attributed to me? I feel honoured. ;D Or is it the other way around...? ;)
Err, I'm sorry if I messed someting up there. Was already a bit late at night here! ;)

Re:virtuality (from \

Posted: Wed Aug 10, 2005 11:03 am
by NotTheCHEAT
Java IS great but PLEASE don't try to write an operating system in Java (or anything else that's interpreted). This is almost as bad as trying to write an OS in BASIC, or Perl, some other such nonsense. It can't be done and it won't work. You'll always need to write some parts of the OS in assembly, and assembly and Java/C++ are like polar opposites. A JIT compiler makes it faster, yes, but then what's the whole point of that? Why not use the outpt from the JIT compiler for the kernel ALWAYS, instead of recompiling it each time you boot?

jitcompiler interpretedos > /mnt/floppya/kernel.sys

Much easier, and even faster that way. Trying to write an interpreted OS sounds really stupid. You folks are too lazy to write good old low-level code, or what?

Re:virtuality (from \

Posted: Wed Aug 10, 2005 11:23 am
by Legend
Hmm, using gcj on the core components that are common for each kernel might really be an idea.

And being lazy? Yes, I am. I really got tired of free(), delete, etc.
Especially with todays hardware and software complexity you can achieve more by optimizing your algorithm then chasing free()s around.

Re:virtuality (from \

Posted: Wed Aug 10, 2005 11:43 am
by Colonel Kernel
NotTheCHEAT wrote: Much easier, and even faster that way. Trying to write an interpreted OS sounds really stupid. You folks are too lazy to write good old low-level code, or what?
First, no one said anything about interpreting. Second, the point is to avoid costly transitions between kernel-mode and user-mode without putting "unsafe" code in the kernel (the way current monolithic systems do for drivers, kernel modules, etc.).

Third, I don't much like your attitude, and I haven't from nearly the first post you've made here. If you're trying to be funny, it's not working. Be respectful and mature or no one is going to take you seriously.

Re:virtuality (from \

Posted: Wed Aug 10, 2005 1:52 pm
by JoeKayzA
NotTheCHEAT wrote: It can't be done and it won't work. You'll always need to write some parts of the OS in assembly, and assembly and Java/C++ are like polar opposites.
I guess that's obvious. And I guess 90% of people reading this thread also knew this, since they know that you can't write 100% of an OS in C, even if it's much closer to the machine...
A JIT compiler makes it faster, yes, but then what's the whole point of that? Why not use the outpt from the JIT compiler for the kernel ALWAYS, instead of recompiling it each time you boot?
The JIT compiler's output will go to a compiler cache, that can also be stored on disk of course (and contains native code). As long as the source files (script files, bytecode...) and the settings for JIT compilation (debug mode, safe mode, optimized mode...) won't change, the JIT compiler won't recompile. And of course this cache can be configured to survive a reboot or even more. Also, the user could decide when the JIT compilation takes place (at first load time, or at installation time?). I guess we are quite flexible in this point...
Trying to write an interpreted OS sounds really stupid. You folks are too lazy to write good old low-level code, or what?
I have to join Colonel Kernel at this point.

@Pype.Clicker: Thanks for forking this thread. I should have thought of this when I started the discussion ::). This topic seems to be covered with misassumptions and sometimes prejudices, hope we do away with some of them. (I guess it was quite the same with C++ in system development, at the time when assembly was 'the usual way' of doing things)

cheers Joe