News for hackers. Stuff that matters.
Re:Classes vs. Structs in .NET. How not to teach about perfo... by leetcrew on Saturday November 04, 2023 @08:20PM (#38146652)
this whole post is kinda confusing to me. I know barely anything about c# under the hood. the only language I've ever used in performance sensitive use cases is c++.

to me, all of the benchmark code looks like an obvious opportunity for dead store elimination. especially this loop in the second round:

  for (var i = 0; i < classes.Count(); i++)
  {
      var x = classes.ElementAt(i).Name;
  }
it doesn't look like any side effects are possible there and x is never referenced outside of the loop. can anyone ELI5 why the compiler generates any code for that snippet?
Re:Classes vs. Structs in .NET. How not to teach about perfo... by idonttalkenough on Saturday November 04, 2023 @08:42PM (#38146796)
https://stackoverflow.com/questions/3202464/garbage-collecti...

Extrapolating it to a larger sense, this SO thread explains it a little bit.

The GC since the top answer has changed quite a bit; I'd read about the changes to the .net clr/framework since v5/6

Re:Classes vs. Structs in .NET. How not to teach about perfo... by leetcrew on Saturday November 04, 2023 @09:19PM (#38147019)
interesting thread, but doesn't really answer my question.

as a human, it is obvious from that snippet alone that the variable x is never read. therefore, unless `classes.ElementAt(i).Name` has some side effect, the entire loop could be replaced with a no-op without changing the program semantics.

so my question isn't about GC behavior at all. I expect the entire loop to be optimized away (no code emitted). why doesn't c# make this optimization? is it something subtle about how properties work, or does the compiler not attempt these optimizations in general?

Re:Classes vs. Structs in .NET. How not to teach about perfo... by jkulubya on Saturday November 04, 2023 @09:37PM (#38147131)
Property accessors `.name` and methods `ElementAt(i)` can have side-effects. From just eyeballing the code, that together with the gc issue would make the compiler in my brain wary of removing the loop. I don't personally know if it's possible to convince the C# compiler that it's safe.
Re:Classes vs. Structs in .NET. How not to teach about perfo... by to11mtm on Sunday November 05, 2023 @11:27AM (#38152561)
... I could be wrong, but I -thought- it was possible for the JIT to see there are no side effects and inline on property access (so long as the property is not a virtual call or otherwise able to devirt.)

.ElementAt() OTOH has a chance to throw in most implementations AFAIR so yeah, a bit of a moot point in this case.

Edited to add:

Actually, there -could- still be side effects in the case of .Name on a class, specifically, it's possible that .ElementAt() could return a null. I'm not sure what cases (if any) that the JIT could get around that.

OTOH, in the case of a struct, as long as .ElementAt() -doesn't- throw, .Name will always return regardless of if it is a property or field, and as part of a struct the compiler should do a good job of inlining as long as the access has no side effects (and you don't have too many fields on the struct!)

Re:Classes vs. Structs in .NET. How not to teach about perfo... by mumblemumble on Saturday November 04, 2023 @09:49PM (#38147204)
Just taking a stab at it; this might not be exactly right --

It's kind of down to C# being compiled into bytecode and then JIT compiled at run-time. During the initial compilation phase, the compiler doesn't necessarily have enough information to know whether `ElementAt()` or `Name` has side effects. (I assume here that Name is a property getter and not a field, in keeping with .NET conventions.) And then at run time the JIT compiler isn't as aggressive as an AOT compiler would typically be about optimization, so it may be less likely to do any dead store elimination.

Re:Classes vs. Structs in .NET. How not to teach about perfo... by idonttalkenough on Saturday November 04, 2023 @11:16PM (#38147731)
Pretty much correct from a historical sense.

On top of this recent advancements in .net have lead to native AOT.

Something to look into.

Re:Classes vs. Structs in .NET. How not to teach about perfo... by idonttalkenough on Saturday November 04, 2023 @11:26PM (#38147784)
Now a days the major performance difference between languages is memory handling and allocation.

Microsoft has been making major moves in how c# gets compiled (AOT/JIT/Native). This is a concurrent effort to cross-platform support.

In doing going so they've minimized performance differences with other languages. The only thing they've yet to completely tackle is memory handling, so in reality, while it might not seem like it at first, your question is asking about that subject.

The GC is responsible for allocation and destruction.

Re:Classes vs. Structs in .NET. How not to teach about perfo... by to11mtm on Sunday November 05, 2023 @11:46AM (#38152791)
> Now a days the major performance difference between languages is memory handling and allocation.

And thread management.

> The only thing they've yet to completely tackle is memory handling,

And thread management.

Async/Await did a whole lot to help with concurrency, IValueTaskSource and IThreadPoolWorkItem helped bring the allocation cost for that back down...

But I still don't have a good way to, say, hint to the scheduler that 'these async work loops are important enough that I want them to always run in this dedicated group of threads'.

Also, having a way to get high precision Sleep() without hacks that have impact on the rest of the system would be nice too.

Re:Classes vs. Structs in .NET. How not to teach about perfo... by tubthumper8 on Sunday November 05, 2023 @01:12AM (#38148466)
Similar to javac, the C# compiler barely does any optimizations at all ahead of time. Optimizations are generally done at runtime by the JIT compiler in the CLR virtual machine
Re:Classes vs. Structs in .NET. How not to teach about perfo... by nyssos on Sunday November 05, 2023 @01:42AM (#38148901)
> it doesn't look like any side effects are possible there

Putting side effects in an `ElementAt` implementation would be an extremely bad idea, but C# won't actually stop you.

Re:Classes vs. Structs in .NET. How not to teach about perfo... by rozab on Sunday November 05, 2023 @03:09AM (#38149262)
As the author says, the list of names is actually read from file every single iteration because `classes` is a LINQ query. So there's all sorts of potential exceptions etc
Re:Classes vs. Structs in .NET. How not to teach about perfo... by kevingadd on Sunday November 05, 2023 @08:28AM (#38150945)
It's impossible to guarantee that count and elementat have no side effects unless you fully devirtualize everything, which can't be done at compile time since the application's dependencies (SDK/runtime, third party libraries) could be swapped out before it runs.

So these optimizations would have to occur in the JIT and might come at the cost of worse startup time or memory usage.

Fwiw modern .net is getting pretty good at devirt but I don't expect it would optimize all this out.