|
A couple things to note about this comment.
The JIT (Just In Time) compilation doesn't happen entirely at start time. It literally happens "just in time". In addition, this can be done at installation time instead. Finally, on this point, the IL is specifically designed to be fast to compile.
Yes, you can use smart pointers to manage memory in C++. However, by itself, a smart pointer doesn't do much to improve performance. Specialized allocators would be required to really optimize performance there. And there's an issue with memory management that is very difficult to address in C++, that's automatically handled in .NET. Memory allocations in C++ generally can lead to fragmentation and excessive page faults. The GC in .NET, on the other hand, is a "compacting garbage collector", which eliminates fragmentation and can reduce page faults.
There's a very interesting series of articles on this topic by some of the top Microsoft developers, both experts at optimizing code. http://blogs.msdn.com/ricom/archive/2005/05/10/performance-quiz-6-chinese-english-dictionary-reader.aspx[^].
William E. Kempf
|
|
|
|
|
FYI, I am new to .Net world.
William E. Kempf wrote: The JIT (Just In Time) compilation doesn't happen entirely at start time. It literally happens "just in time".
Compiling at "Just in time" makes the user feel like using a slower application.
William E. Kempf wrote: In addition, this can be done at installation time instead.
This seems to be a good option. But still the executable runs under the runtime where the slowness problem comes in.
William E. Kempf wrote: Finally, on this point, the IL is specifically designed to be fast to compile.
IL is designed to be fast to compile but the JIT Compiler is not compiled for the specific processor so JIT compiler gives us faster executable for the specific processor but the JIT compiler itself is slower because of the generic code in it.
William E. Kempf wrote: Yes, you can use smart pointers to manage memory in C++. However, by itself, a smart pointer doesn't do much to improve performance.
Smart pointers are to manage memory not to increase the performance.
And in C++ most of the time we don't need to use "new" to allocate heap memory.
We can avoid it as much as possible and use smart pointers whenever we need it.
But .Net allocates objects in heap memory and wait for GC to collect.
Thanks and correct me if i am wrong
|
|
|
|
|
.NET Framework during installation, installs not the IL code, but a NGen'd version of the IL code. Similarly, using our installer, we can "second compile" the application during installation using "NGen.exe". This is one way to improve the performance by preventing the second compilation that happens during startup.
Thanks & Regards,
M.Mugunth Kumar
M +65 82448625
W http://mugunth.kumar.googlepages.com
B http://tech-mugunthkumar.blogspot.com (Technology Blog) *NEW
Nanyang Technological University,
Wee Kim Wee School of Communication and Information,
31 Nanyang Link, Singapore - 637718.
|
|
|
|
|
Thanks Mugunth, I understand the NGen and the performance benefits.
|
|
|
|
|
codeprojecter_ wrote: Compiling at "Just in time" makes the user feel like using a slower application.
Maybe, maybe not. Since small amounts are being compiled, and they're compiling fast, in many circumstances the user can't even perceive the compilation overhead. There's too many variables to consider here to make a blanket claim one way or the other.
codeprojecter_ wrote: This seems to be a good option. But still the executable runs under the runtime where the slowness problem comes in.
I don't understand this comment. The "runtime" in this case is just an API, no different than running under the Win32 "runtime". With the way you said this, it seems like you think it's still somehow running in an interpreted mode. It's not. It's running as native code. The only overhead to the .NET runtime would be the overhead of the security features, and that's not overly significant and is likely worth the cost for most applications.
codeprojecter_ wrote: IL is designed to be fast to compile but the JIT Compiler is not compiled for the specific processor so JIT compiler gives us faster executable for the specific processor but the JIT compiler itself is slower because of the generic code in it.
You're making assumptions there. I'm not going to make any claims to know how the JIT is performed, as I've never had a reason to care enough to research it. But there's no reason not to assume the code that performs the JIT wasn't NGened and thus running optimally for the platform.
codeprojecter_ wrote: And in C++ most of the time we don't need to use "new" to allocate heap memory.
We can avoid it as much as possible and use smart pointers whenever we need it.
But .Net allocates objects in heap memory and wait for GC to collect.
Actually, you do have to use new to allocate heap memory most of the time. The other options are malloc and cousins and custom allocators, but for custom classes these options have to use at least placement new to construct the object. Maybe you didn't mean to say "heap" memory, and meant that you could instead rely on stack allocations, but I'd contend that most applications will rely on at least as much heap, if not significantly more, as it will stack.
And again, in case the point wasn't understood, smart pointers don't do anything for performance, or for dealing with allocations. They only address issues with deallocation. The GC addresses so much more than that, and produces significant performance benefits. Yes, there's drawbacks, such as the non-deterministic nature of collecting, and the fact that it addresses only memory and not other types of resource acquisitions, so I'm not trying to oversell the GC. But strictly discussing performance, which is the point of this article, the GC is a better general purpose solution.
BTW, the CLR uses both stack and heap allocations. It's just not as easy to determine where allocations occur.[^]
William E. Kempf
|
|
|
|
|
William E. Kempf wrote: Maybe, maybe not. Since small amounts are being compiled, and they're compiling fast, in many circumstances the user can't even perceive the compilation overhead. There's too many variables to consider here to make a blanket claim one way or the other.
May be True.
William E. Kempf wrote: I don't understand this comment.
Sorry if i am confusing. English is not my native language.
William E. Kempf wrote: it seems like you think it's still somehow running in an interpreted mode. It's not. It's running as native code.
Yes i am trying to say about the interpreted nature of IL. I understand the NGen's native code.
William E. Kempf wrote: The only overhead to the .NET runtime would be the overhead of the security features, and that's not overly significant and is likely worth the cost for most applications.
The "only" overhead ?
William E. Kempf wrote: You're making assumptions there. I'm not going to make any claims to know how the JIT is performed, as I've never had a reason to care enough to research it. But there's no reason not to assume the code that performs the JIT wasn't NGened and thus running optimally for the platform.
I just assumed nothing more nothing less
William E. Kempf wrote: Maybe you didn't mean to say "heap" memory, and meant that you could instead rely on stack allocations, but I'd contend that most applications will rely on at least as much heap, if not significantly more, as it will stack.
I try to mean the stack memory. Yes C++ application depends on heap. But i hope not for all objects which .Net objects does.
William E. Kempf wrote: But strictly discussing performance, which is the point of this article, the GC is a better general purpose solution.
In the scope of this article GC is a better "general purpose" solution
William E. Kempf wrote: BTW, the CLR uses both stack and heap allocations. It's just not as easy to determine where allocations occur.
Link seem to be not working
|
|
|
|
|
codeprojecter_ wrote: Yes i am trying to say about the interpreted nature of IL. I understand the NGen's native code.
JITed code is native as well. Nothing is ever "interpreted" in .NET. It's always executed in the platforms native language. What's in question is when the code is transformed into this native language. It can actually happen at three different times: during compilation (hardly ever done), during installation (NGen) or during runtime (JIT). Once compiled, there's no overhead to the runtime beyond security.
codeprojecter_ wrote: The "only" overhead ?
Depending on how literally you mean that, yes. Obviously every API call has overhead associated with it, but between managed and unmanaged APIs, this is a level playing field.
codeprojecter_ wrote: In the scope of this article GC is a better "general purpose" solution
Not just in the scope of this article. It's well established that garbage collection provides a more efficient "general purpose" solution to memory management. A garbage collector can perform significant optimizations to both allocation as well as deallocation of memory. Don't take my word for it, search for the numerous scientific papers written on this subject.
codeprojecter_ wrote: Link seem to be not working
Seemed to work for me. http://www.yoda.arachsys.com/csharp/memory.html[^]
William E. Kempf
|
|
|
|
|
William E. Kempf wrote: It's well established that garbage collection provides a more efficient "general purpose" solution to memory management. A garbage collector can perform significant optimizations to both allocation as well as deallocation of memory. Don't take my word for it, search for the numerous scientific papers written on this subject.
Unfortunatelly, in practice it is simply not the case. I believe there was an article on "Lambda the Ultimate" explaining that you need a VM manager that cooperates with the GC in order to get better performance compared to native allocations.
|
|
|
|
|
I'd have to see a link to the article before I could comment.
William E. Kempf
|
|
|
|
|
|
I think this quote, found in the comments, by the author of the research paper himself, sums it up:
I think the paper highlights that, unless memory is an issue, GC is a reasonable choice for performance (and a clear win once software engineering is included).
In other words, manual memory management always has the potential to be the most efficient, but often requires significant engineering to do so. There are other trade offs, though, including memory consumption and determinism.
BTW, the paper also didn't evaluate the .NET collector or any collector using similar collection algorithms. I won't venture to guess if the concurrent collection improves or degrades the performance, though.
William E. Kempf
|
|
|
|
|
And I find your quote to sum it up even better:
William E. Kempf wrote: In other words, manual memory management always has the potential to be the most efficient
The simple truth is that a generic GC cannot know the internal logic of my software and cannot know the best strategy to manage memory (I am not going to even mention other resources, such as locks, files, handles...).
But theory aside, give me an example of a performant GC application. I have never tried one, and some that are "poster-boys" for GC performance such as Eclipse or Paint.NET are simply crawling compared to similar native applications.
|
|
|
|
|
Nemanja Trifunovic wrote: But theory aside, give me an example of a performant GC application. I have never tried one, and some that are "poster-boys" for GC performance such as Eclipse or Paint.NET are simply crawling compared to similar native applications.
Eclipse is certainly not performant. But then, I think Java in general doesn't do well in this arena. To be fair though, it doesn't perform significantly worse than VisualStudio, depending on which plug-ins you have active (emphasis on significantly, because there is a noticeable difference).
Paint.NET, OTOH, is a very nice example. I'm very curious what makes you claim it's "simply crawling compared to similar native applications"? I'm more than willing to bet the average user would be unable to differentiate this from a native application. In my experience, it loads images faster than similar applications that come with digital cameras. It applies filters faster than those applications. Really, if you make the claim that this application performs worse than comparable native applications, you'll either have to provide proof or I'm going to have to assume your perception is skewed by your expectations.
Other .NET applications I've used that perform well: RSSBandit, PowerShell and Expression Blend to name a few.
William E. Kempf
|
|
|
|
|
William E. Kempf wrote: But then, I think Java in general doesn't do well in this arena. To be fair though, it doesn't perform significantly worse than VisualStudio,
And VS is one of the rare MS desktop applications that use managed code
William E. Kempf wrote: Paint.NET, OTOH, is a very nice example.
Wow, you are the first person aside from the authors of Paint.NET that likes its performance. Although I hate to cite Slashdot in any seroius discussion, most people seem to have the same impression as I do[^].
modified on Monday, March 3, 2008 3:15 PM
|
|
|
|
|
Nemanja Trifunovic wrote: And VS is one of the rare MS desktop applications that use managed code
Very little.
Nemanja Trifunovic wrote: Wow, you are the first person aside from the authors of Paint.NET that like its performance.
And you're the first I've heard that didn't like the performance. Interestingly, in the Slashdot article you posted, I count more people saying the "fat brush" test is "silky smooth" than those claiming it performs badly. In my own testing, a brush width of 200 draws smoothly and doesn't touch the CPU, contrary to the few bad reports. Of course, this Slashdot post was from 2004, and there have been numerous updates to Paint.NET since then. When was the last time you looked at this application?
William E. Kempf
|
|
|
|
|
In my opinion, Paint.NET's page faults are far less when compared to other similar applications (same memory foot prints ).
In my machine, the number of PageFaults for PaintDotNet and Firefox, after running it for similar amount of time was very different. I tested it after running both applications for about 5 min. In firefox, I opened gmail, and many javascript intensive applications, and in paintdotnet I did a couple of renders (Pencil sketching a 8MP photo).
PaintDotNet's number of page faults was around 70,000 where as Firefox, it was 100,000 when it started ( I do have a lot of plugins) and after opening gmail and other such websites, it went up by a factor of 10! Though the memory occupied by Firefox and PaintDotNet were 80MB to 100 MB...
The point is, for the allocated 80 MB heap in PaintDotNet, due to GC, memory is freed resulting in lower page faults than firefox which also uses the same amount of memory.
Mugunth
Thanks & Regards,
M.Mugunth Kumar
M +65 82448625
W http://mugunth.kumar.googlepages.com
B http://tech-mugunthkumar.blogspot.com (Technology Blog) *NEW
Nanyang Technological University,
Wee Kim Wee School of Communication and Information,
31 Nanyang Link, Singapore - 637718.
|
|
|
|
|
Hello,
you comparing two absoluty different worlds which aren't comparable.
As you should know the virtual memory managment depends from many factors.
One point is the internal memory managment and an other the local available heap area (RAM).
All this points presents that this result isn't deterministic.
Ciao...
what*s up...
|
|
|
|
|
That paper is quite impressive, I already found links to it and have to read it. However, studies with opposite conclusions were done in the past - they did not benchmark applications without enough VM (and well, if you're swapping it's obvious that you're gonna be slow - reporting benchmark results is almost redundant on that, or might be useful to give more scary numbers ).
|
|
|
|
|
Thanks William for the answers and the link
|
|
|
|
|
Hey, nice to see you back at Code Project, Bill, although not sure why you are commenting this article which is very substandard and may be removed soon.
William E. Kempf wrote: The JIT (Just In Time) compilation doesn't happen entirely at start time. It literally happens "just in time". In addition, this can be done at installation time instead.
JIT happens whenever it decides it is a best time to happen, but in any case it is easy to observe and impacts performance. I have yet to try a .NET application that starts quickly - even a "hello world" takes a while.
William E. Kempf wrote: Finally, on this point, the IL is specifically designed to be fast to compile.
Which as you know is negatively impacting the optimization of the resulting code. In order to fully optimize the code, a compiler needs time, and JIT does not have time.
|
|
|
|
|
Nemanja Trifunovic wrote: JIT happens whenever it decides it is a best time to happen, but in any case it is easy to observe and impacts performance. I have yet to try a .NET application that starts quickly - even a "hello world" takes a while.
The most significant time spent at start up is just in loading the runtime, not in JIT compiling any code. This startup time is especially significant "the first time". I run a lot of different .NET code, and there's some much more complex applications than "hello world" that will under some circumstances load nearly instantaneously. In contrast, I've used some native applications that take a tremendous amount of time to load. This topic was discussed at length in that shoot-out series of articles I referenced, since load time is definitely a point where native code can almost always out perform, but it's not a cut-and-dried win.
Nemanja Trifunovic wrote: William E. Kempf wrote:
Finally, on this point, the IL is specifically designed to be fast to compile.
Which as you know is negatively impacting the optimization of the resulting code. In order to fully optimize the code, a compiler needs time, and JIT does not have time.
Again, don't focus to much on single variables in the equation. The majority of the optimizations can be performed during the "first compile" as the author calls it. Various optimizations such as loop unrolling, as just one example, can be performed when creating the IL. Higher level optimizations, at least in theory, are available to the JIT compiler, which has a "complete picture" view of the code and the platform. There's lots of material written on this subject as well. Theoretically, at least, you should be able to get better optimizations out of .NET code then with native compilers, despite the drawback you just noted.
There's just no "clear winner" when you talk about performance. There's too many factors to take into account. C++ will perform better in some cases. .NET in others. In theory, you can optimize the C++ code to outperform the .NET code in every case, because of the level of control you have at a low level, but as demonstrated in that shoot-out, the amount of effort is often astronomical and it's VERY unlikely anyone would go to those lengths for anything but the most absolutely time critical operation. I'm willing to bet that 99% of the people who enter these debates have never optimized code to those lengths.
William E. Kempf
|
|
|
|
|
William E. Kempf wrote: I run a lot of different .NET code, and there's some much more complex applications than "hello world" that will under some circumstances load nearly instantaneously.
I have yet to see such application.
William E. Kempf wrote: In contrast, I've used some native applications that take a tremendous amount of time to load.
Xemacs, for instance I never meant to say that it is impossible to make a native application that loads slowly - it is just much easier to write one that loads fast with the "native" language.
<blockquote class="FQ"><div class="FQA">William E. Kempf wrote:</div>Higher level optimizations, at least in theory, are available to the JIT compiler, which has a "complete picture" view of the code and the platform. There's lots of material written on this subject as well. Theoretically, at least, you should be able to get better optimizations out of .NET code then with native compilers, despite the drawback you just noted.</blockquote>
And in practice, you simply don't get good optimizations with JIT. The last time I was doing anything serious with .NET, it was not even able to inline the most obvious cases. There was a lot of marketing hype how JIT "could" produce better could becouse it "could" take into account the specific hardware it runs on. Well, it does not, at least not in practice
William E. Kempf wrote: In theory, you can optimize the C++ code to outperform the .NET code in every case, because of the level of control you have at a low level,
Nothing theoretical about it. If everything else fails, you can easily inline assembly. With C#, you can't inline even IL.
William E. Kempf wrote: I'm willing to bet that 99% of the people who enter these debates have never optimized code to those lengths.
I wouldn't be so sure. There are many areas of development where every cycle counts. Not to mention the memory consumption which is practically impossible to control with a language such as C#.
|
|
|
|
|
Nemanja Trifunovic wrote: Nothing theoretical about it. If everything else fails, you can easily inline assembly. With C#, you can't inline even IL.
Inline assembly is NOT a C++ language solution. That said, though, you're digging to deep into what I meant. When I said "theory", I meant only that there would be some code for which it's simply not possible to optimize beyond what you get out of C#. A long mathematical calculation on an integral type, for instance, is something that doesn't lend itself to the types of optimizations that would provide advantages to C++.
Nemanja Trifunovic wrote: I wouldn't be so sure. There are many areas of development where every cycle counts. Not to mention the memory consumption which is practically impossible to control with a language such as C#.
I figured I was taking this into account by stating 99% and not 100%. Folks who do have to optimize to this level probably aren't coding in either C++ or C#. They're likely coding in either C or ASM. They also have such a deep understanding of this topic, that they are not likely to read entries like this, much less comment on them. Have you read the shoot-out articles? Do you honestly think anybody commenting here has ever optimized their code to the extent that Raymond did?
William E. Kempf
|
|
|
|
|
William E. Kempf wrote: Inline assembly is NOT a C++ language solution.
Correct, but irrelevant. If I find that my C++ compiler is unable to do an optimization I know it is possible, I can easily inline the assembly and do the optimization manually. If I find myself in a similar situation with C#, I am stuck.
William E. Kempf wrote: I figured I was taking this into account by stating 99% and not 100%.
And how did you get to 99%? There are whole industries where native code is a must: embedded development, games, CAD, multimedia, you name it. I am not sure only 1% of the developers work in these industries.
In fact, until recently I worked on high-volume text processing (machine translation, translation memory, etc) and even there we just couldn't use managed code (Java or C#) even if some of us very *very* enthusiastic about it (including me for a period of time). The memory consumption was so high with any GC language we tried that it made our software unusable in practice.
William E. Kempf wrote: Have you read the shoot-out articles? Do you honestly think anybody commenting here has ever optimized their code to the extent that Raymond did?
I have read it. It is mostly about optimizing UI IO, which really shows little about the performance of the languages in which the code is written. There were similar benchmarks in the past "proving" that Java is faster than C++. In fact, it is no secret that the C++ standard IO is embarrassingly slow. Fortunatelly, it is fairly easy to use OS calls directly.
modified on Monday, March 3, 2008 1:48 PM
|
|
|
|
|
Nemanja Trifunovic wrote: Correct, but irrelevant. If I find that my C++ compiler is unable to do an optimization I know it is possible, I can easily inline the assembly and do the optimization manually. If I find myself in a similar situation with C#, I am stuck.
Not necessarily. First, you're wrong about not being able to inline IL. Reflection.Emit provides this sort of capability. This is still just IL, and not the final machine code, though. For that, you have options with P/Invoke. But at this point you've ventured into the realm of optimizations for which neither language is probably the correct one for your problem domain, IMO. Right tool for the right job, and all that.
Nemanja Trifunovic wrote: And how did you get to 99%? There are whole industries where native code is a must: embedded development, games, CAD, multimedia, you name it. I am not sure only 1% of the developers work in these industries.
As a wild guess, as clearly indicated by the "I bet" in the original statement. BTW, in none of the industries you reference is native code a "must". .NET and Java both have been successful in every single one of those industries. Specific applications within those industries I'd agree with you on, and those applications would have a much smaller percentage of developers who've worked on them. This percentage doesn't have to be 1%, for what I said to still hold true, as those developers would have had to participate in a discussion like this, and I suspect they'd have little desire to, since they already understand the concept much too deeply to care about the topic on the level that gets discussed here.
Nemanja Trifunovic wrote: I have read it. It is mostly about optimizing UI IO, which really shows little about the performance of the languages in which the code is written. There were similar benchmarks in the past "proving" that Java is faster than C++. In fact, it is no secret that the C++ standard IO is embarrassingly slow. Fortunatelly, it is fairly easy to use OS calls directly.
There was very little in those articles about IO, and certainly not in optimizing it. Read a little deeper.
William E. Kempf
|
|
|
|
|