views:

416

answers:

5

(This was meant to be a general hypothetical question, me whining that .NET was a pig and begging for reasons. It was not really meant to be a question about my specific app.)

Currently I am rewriting some old C++ code in C#. We are porting over all legacy applications. I have C++ applications that take MAX 3% CPU. Mostly they use none. I then take the code, copy and paste, then reformat to C# syntax and .NET libraries, and BAM! 50% CPU. Whats the reason for this? I thought at first it was JIT, but even after each code path has been exercises, and the whole thing has been JIT ed, same issue.

I have also noticed huge memory increases. Apps that took 9 MB running a full load now start at 10 MB and run at 50 MB. I realize hardware is cheap, but I want to understand what causes this. Is it a cause for alarm, or is .NET just that much the pig?

Update 1 Answer to Skeet

I am familiar with C#. I change things to Linq, and so on. I typically take code and reduce the number of lines, and so on. Could you give some more examples of what a C++ person my do wrong in .NET?

Update 2

This was meant to be a general question, but the specific app that has the issue is as follows.

It has a thread that uses and ODBC driver to get data from a paradox db. It then uses Linq to transform this to a SQL db and post it. I have run it through ANTS profiler, and it seems the data set filling take the most time. Followed by Linq posting. I know some of my areas are reflection usage, but I don't see how to do what I need to with out this. I plan to change my string to string builders. Is there any difference between these two?

(int)datarow["Index"]

and

ConvertTo.Int32(datarow["Index"])

I changed all string concatenation to format strings. That didn't reduce over head. Does any one know the difference between a data reader vs data adapter and datasets?

+16  A: 

How familiar are you with C# and .NET? If you're just porting over the legacy code keeping C++ idioms, I'm not at all surprised that it's being a hog. Porting applications verbatim from one platform to another is almost never a good idea. (Of course, you haven't said that you've definitely done that.) Also, if you're expert C++ developers but novice .NET developers, you should expect your code to perform as if you're novices on the platform.

We can't really tell what's taking the performance without knowing more about the app - although I wouldn't be surprised to hear that string concatenation was the culprit. How many processors do you have on the box? If it's 2, then the app is basically taking up everything it can for a single thread...

.NET is generally going to be heavier in terms of memory than a C++ app, but should be at least comparable in terms of speed for most tasks. Taking 50MB instead of 9MB sounds like more than I'd expect, but I wouldn't immediately be too worried.

Both the memory and the CPU performance should be investigated with the use of a good profiler. I can recommend JetBrains dotTrace Profiler, but there are plenty of others out there.

Jon Skeet
Could you give some more examples?
Anthony D
Like what would be a novice .NET thing a C++ guy might do?
Anthony D
Examples of what? Without knowing anything about your app, it would be *very* difficult to guess at where the bottlenecks might be. Even just using LINQ could lead to a bottleneck if you're not careful. I would really go for a profiler - anything else will just be guesswork.
Jon Skeet
The first thing I would do is look for numerous string concats and change them to use the `System.Text.StringBuilder` class.
Josh Stodola
Oh, I see. I think it's just a case of approaching things differently. I've seen some horrible .NET code written by C++ developers who are used to passing everything by ref, for example. That wouldn't kill the CPU, but it would be very unidiomatic, and would suggest a lack of understanding of reference types.
Jon Skeet
Even without a proper profiler, you may be able to track down some of the bottlenecks just using logging.
Jon Skeet
I have run it through the Red Ants profile. See update to question.
Anthony D
A: 

I would say that the memory usage is probably in line, but the CPU usage is not.

Sounds like you have a thread that is not yielding.

Moose
+1  A: 

You should see some increase in CPU usage. 3% to 50% sounds like too much, what kind of code is this?

The memory footprint is just the unavoidable cost. Any thing between 30-50 MB for a .NET app is normal. Typically, the actual memory usage of your .NET application is very small, but there's a sizable runtime overhead which you can not avoid (this is a one-time cost, but it's there) and it is very noticeable if you references tonnes of assemblies.

John Leidegren
A: 

I can think of a few conjectures:

1) Memory - C++ does not have managed memory. So, it frees memory incrementally and at (if programmed well) optimal times.

With managed memory, the program will basically "leak" memory until such a time as it chooses to do garbage coilection. The time is probably dependent on how much memory was allocated to the process. There's probably a way to change the default behavior, but a smaller memory size means that garbage collection collection takes place sooner and more often, which affects processing time. If enough memo9ry is allocated then gc may not need to be inv9ked.

2) Does the program run in the same time, or less? If it uses 5 times as much processor power but completes in 1/5 the time then the CPU used is basically equivalent.

3) Yes, .NET is probably a pig

Larry Watanabe
If you are calling .Net a pig your name is very fitting
Matthew Whited
Didn't get it :) Personally I don't see anything wrong with being a "pig" nowadays .. I like VB .NET, it's the best programming environment I've had since interlisp in the late 80's, and it's backed by a framework that can be used to deliver commercial applicatoins instead of just cool demos/research/proof of concept. I think Java's main lesson was "it's ok to be a pig now .. we have enough processing power" which Microsoft took to heart and re-implemented, in my mind, in a much better way (better IDE, better more efficient generated code). It's a pig but a very FAST pig :)
Larry Watanabe
+4  A: 

AFAIK there is litte difference between (int)datarow["Index"] and ConvertTo.Int32(datarow["Index"]). However there is a big difference if you use stream mode data readers:

int orderIndex = <order of Index column in projection list>;
using (OdbcDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
  int Index = rdr.GetInt32(orderIndex);
}

The SeqentialAccess command behavior is the fastes way to process SQL results, because it does eliminate extra caching needed for random access.

A second notice is that is seems you're using Data sets. Data sets are easy to use, but they are very very far from what anyone can call 'fast'. With data sets you are basically running an in memory storage engine (I think is based on Rushmore). If you want to squeeze every CPU cycle and all the 1s from every bit of RAM, then you'll have to use leaner components (eg. raw arrays of structs instead of Datasets and DataTables).

When you compare apples to apples CLR can hold its ground against native code. IL code can be nativized at deployment time with NGEN. Typical CLR overheads like bounds checks can be avoided . GC pre-emption 'pause' happens only if you're careless with your allocation (just because you have GC doesn't mean you should allocate left and right). And CLR actually has some aces up its sleve when it comes to memory layout since it can rearange object in memory to fit access patterns and improve TLB and L2 locality.

BTW, if you think the debate 'C++ can run circles around C#' is something new, I remember a time when C could run circles around C++ ('virtual calls are impossibly slow' they were saying) and I hear there was a time assembly was running circles around C.

Remus Rusanu