Linked by Hadrien Grasland on Sat 5th Feb 2011 10:59 UTC
OSNews, Generic OSes So you have taken the test and you think you are ready to get started with OS development? At this point, many OS-deving hobbyists are tempted to go looking for a simple step-by-step tutorial which would guide them into making a binary boot, do some text I/O, and other "simple" stuff. The implicit plan is more or less as follow: any time they'll think about something which in their opinion would be cool to implement, they'll implement it. Gradually, feature after feature, their OS would supposedly build up, slowly getting superior to anything out there. This is, in my opinion, not the best way to get somewhere (if getting somewhere is your goal). In this article, I'll try to explain why, and what you should be doing at this stage instead in my opinion.
Thread beginning with comment 461218
To view parent comment, click here.
To read all comments associated with this story, please click here.
RE[8]: Not always rational
by Neolander on Mon 7th Feb 2011 16:41 UTC in reply to "RE[7]: Not always rational"
Neolander
Member since:
2010-03-08

Firstly, I agree about not using interpreted languages in the kernel, so lets get that out of the picture right away.

In fact, that was what most of my post was about ;)

Secondly, to my knowledge, the performance problems with Java stem from poor libraries rather than poor code generation. For instance, Java graphics were designed to be easily portable rather than highly performing, therefor it's very poorly integrated with the lower level drivers. Would you agree this is probably where it gets it's reputation for bad performance?

Probably. Java is often praised for its extensive standard library, so if said library is badly implemented, the impact will probably be at least as terrible as if the interpreter is faulty since all Java software is using it.

Thirdly, many people run generic binaries which aren't tuned for the system they're using. Using JIT technology (actually, the machine code could be cached too to save compilation time), the generated code would always be for the current processor. Some JVMs go as far as to optimize code paths on the fly as the system gets used.

Does it have that much of an impact ? I'm genuinely curious. Didn't play much with mtune-like optimizations, but I'd spontaneously think that the difference is the same as between GCC's O2 and O3.

Can you illustrate why a safe language would necessarily be unsuitable for use in the kernel?

That was what the rest of the post was about.

'C' is only a language, there is absolutely nothing about it that is inherently faster than Ada or Lisp (for instance). It's like saying Assembly is faster than C, that's not true either. We need to compare the compilers rather than the languages.

Don't know... I'd say that languages have a performance at a given time, defined by the mean performance of the code generated by the popular compilers/interpreters of that time.

Anyway, what I was referring to is that interpreted languages are intrinsically slower than compiled languages, in the same way that an OS running in a VM is intrinsically slower than the same OS running on the bare metal : there's an additional bytecode re-compilation overhead. They don't have to be much slower though : given an infinite amount of time and RAM, compiled and interpreted code end up having equal speed in their stationary state, and interpreted can even be slightly faster due to machine-specific tuning. The problem is the transient, and situations where only few RAM is available.

"Code only a GC implementation, and your interpreter now has to do memory management. Code threads, and it has to manage multitasking and schedule things."

I don't understand this criticism, doesn't the kernel need to do these things regardless? It's not like you are implementing memory management or multitasking just to support the kernel VM.

Sure, but if the kernel's VM ends up doing most of the job of a kernel, what's the point of coding a kernel in X at all ? The VM, which is generally coded in a compiled language, ends up being close to a full-featured kernel, so I don't see the benefit : in the end, most of the kernel is actually coded in whatever language the VM is written in.

"Code pointer checks, and all X code which needs lots of pointers see its performance sink."

This is treading very closely to a full blown optimization discussion, but the only variables which must be range checked are those who's values are truly unknown within the code path. The compiler can optimize away all range checks on variables who's values are implied by the code path. In principal, even an unsafe language would require variables to be range checked explicitly by the programmer (otherwise they've left themselves vulnerable to things like stack overflow), which should be considered bugs and thus an unfair "advantage".

Take a linked list. When parsing it, a process ends up looking at lots of pointers without necessarily knowing where they come from. This is the kind of code which I had in mind.

In principal, paging can accomplish everything selectors did. In practice though switching selectors is much faster than adjusting page tables. A compiler could trivially ensure that the kernel module didn't overwrite data from other modules by simply enforcing the selectors except in well defined IPC calls - thus simultaneously achieving good isolation and IPC performance. Using page tables for isolation would imply that well defined IPC calls could not communicate directly with other modules without an intermediary helper or mucking with page tables on each call.

It's possible to have overhead only at process load and first call time with paging and tweaked binaries, but I need a better keyboard than my cellphone's one to explain it.

Edited 2011-02-07 16:52 UTC

Reply Parent Score: 1

RE[9]: Not always rational
by Alfman on Mon 7th Feb 2011 17:54 in reply to "RE[8]: Not always rational"
Alfman Member since:
2011-01-28

"Anyway, what I was referring to is that interpreted languages are intrinsically slower than compiled languages"

Yes.

"in the same way that an OS running in a VM is intrinsically slower than the same OS running on the bare metal"

But, most VM implementations do run apps on bare metal (within user space). We're talking about making a VM run on bare metal in kernel space.

A VM guaranties isolation, but beyond that requirement there is absolutely no reason it has to "interpret" code. It's genuine machine code which runs directly on the processor.

You said you've read the Java/C benchmarks, which is why I didn't cite any, but it sounds like your doubting the results? Why?



"Sure, but if the kernel's VM ends up doing most of the job of a kernel, what's the point of coding a kernel in X at all ? The VM, which is generally coded in a compiled language, ends up being close to a full-featured kernel, so I don't see the benefit"

Ok I understand.

We shouldn't underestimate what can be done in 'X' (as you call it). C's memory manager can be written in C, why rule out using X to do the same thing? It's only a question of bootstrapping.

More importantly though, the vast majority of code running in kernel space (whether micro/macro), is device drivers. In a micro-kernel design, the core kernel should be very small and do very little - like switch tasks and help them intercommunicate. If this very small piece cannot be implemented in pure 'X', then so be it. It's like peppering 'C' with assembly.

Even for a macro-kernel design, I'd say a safe language could be beneficial.

Personally, I actually like 'C', but the lack of bounds checking is something that developers have been struggling with since it's inception.
It has other shortcomings too: the lack of namespaces causing library collisions, ugly header file semantics, a very weak macro/template system, a lack of standardized strings, etc.

I'm not saying we should not use C, but if we do, then get ready for the "usual suspects".


"Take a linked list. When parsing it, a process ends up looking at lots of pointers without necessarily knowing where they come from. This is the kind of code which I had in mind."

One approach could be to adapt the way many safe languages already handle references (which let's face it, is a "safe" pointer). All references could be dereferenced safely without a check, any other pointers (let's say coming from user space) would need to be validated prior to use.

Reply Parent Score: 1

RE[10]: Not always rational
by Neolander on Mon 7th Feb 2011 18:34 in reply to "RE[9]: Not always rational"
Neolander Member since:
2010-03-08

"in the same way that an OS running in a VM is intrinsically slower than the same OS running on the bare metal"

But, most VM implementations do run apps on bare metal (within user space). We're talking about making a VM run on bare metal in kernel space.

Sorry for the confusion. I was talking about the VirtualBox/VMware kind of virtual machine there : software which "emulates" desktop computer hardware in order to run an OS in the userspace of another OS.

A VM guaranties isolation, but beyond that requirement there is absolutely no reason it has to "interpret" code. It's genuine machine code which runs directly on the processor.

So you say that it could be possible to envision "safe" code that's not interpreted ? What differs between this approach and the way a usual kernel isolates process from each other ?

You said you've read the Java/C benchmarks, which is why I didn't cite any, but it sounds like your doubting the results? Why?

What I've read showed that for raw computation and a sufficiently long running time, there's no difference between Java and C, which means that JIT compilation does work well. On the other hand, I've not seen benchmarks of stuff which uses more language features, like a comparison of linked list manipulation in C and Java or a comparison of GC and manual memory management from a performance and RAM usage point of view. If you have such benchmarks at hand...

We shouldn't underestimate what can be done in 'X' (as you call it).

I use X when I think that what I say applies to all "safe" programming languages.

C's memory manager can be written in C, why rule out using X to do the same thing? It's only a question of bootstrapping.

The problem is that in many safe languages, memory management and other high-level features are taken for granted, as far as I know, which makes living without them difficult. As an example, GC requires memory management to work, and it's afaik a core feature of such languages.

More importantly though, the vast majority of code running in kernel space (whether micro/macro), is device drivers. In a micro-kernel design, the core kernel should be very small and do very little - like switch tasks and help them intercommunicate. If this very small piece cannot be implemented in pure 'X', then so be it. It's like peppering 'C' with assembly.

There we agree... Except that good micro-kernels try to put drivers in user space when possible without hurting performance.

Even for a macro-kernel design, I'd say a safe language could be beneficial.

I think I agree.

Personally, I actually like 'C', but the lack of bounds checking is something that developers have been struggling with since it's inception.

Don't know... I hated it initially, but once I got used to it it only became a minor annoyance.

It has other shortcomings too: the lack of namespaces causing library collisions,

Fixed in C++

ugly header file semantics,

I totally agree there, C-style headers are a mess. The unit/module approach chosen by Pascal and Python is imo much better.

a very weak macro/template system,

Fixed in C++

a lack of standardized strings

Fixed in C++, but if I wanted to nitpick I'd say that char* qualifies.

I'm not saying we should not use C, but if we do, then get ready for the "usual suspects".

Low-level code must always be polished like crazy anyway.

One approach could be to adapt the way many safe languages already handle references (which let's face it, is a "safe" pointer). All references could be dereferenced safely without a check, any other pointers (let's say coming from user space) would need to be validated prior to use.

Are these working in the same way as the C++ ones ? If so, are they suitable for things like linked lists where pointers have to switch targets ?

Reply Parent Score: 1