Structs and GC vs RC ripple effects

  Рет қаралды 10,075

Context Free

Context Free

Күн бұрын

Code: github.com/con...
Further analysis by Matheus C. França: gist.github.co...

Пікірлер: 73
@loipesmas
@loipesmas 4 ай бұрын
Very interesting insight! I wouldn't consider that GC can make some things simpler, although now it totally makes sense. Thanks for sharing!
@stercorarius
@stercorarius 4 ай бұрын
The entire point of gc is to make things simpler
@loipesmas
@loipesmas 4 ай бұрын
@@stercorarius right, I meant simpler for the compiler/CPU, as in it has to do less work (at given time, because obviously it will have to do the work later)
@Nerthym
@Nerthym 4 ай бұрын
Nice and to the point comparison. Usually though you are not supposed to pass shared_ptr unless you actually want to share ownership. In adequate cpp codebases about 95% of ptrs are unique (or bound to an arena) and parameters passed by ptr or ref most of the time. Plus shared_ptr's ref counter is atomic, which adds overhead. While ago I had to optimize iphone 4 game where like 20% of frametime was spent copying pointers arround 'cause people who developed it were used to garbage collected languages. If used naively RC can absolutely affect performance negatively.
@von_nobody
@von_nobody 4 ай бұрын
Yes, in some cases if we have predefined lifetime, `ptr*` will be best solution (probably in some wrapper).
@jonas1ara
@jonas1ara 4 ай бұрын
I have been preparing a series of posts on my blog about memory and this helps me a lot to understand and complement it, it is great.
@maxrinehart4177
@maxrinehart4177 4 ай бұрын
would help a lot if you tell us what your blog name or url
@anasssoulimani9288
@anasssoulimani9288 4 ай бұрын
Hey, can you share your blog?
@contextfree
@contextfree 4 ай бұрын
I chatted a bit with Jonas and confirmed that this is his blog. It's still brand new, but he has some additional posts planned, such as he mentioned above. jonas1ara.github.io/
@cole-nyc
@cole-nyc 4 ай бұрын
This is not a perfect comparison. In your C++ example, there's no need for the Seq struct to be copied when it can be passed as a reference. The refcount increment op of shared_ptr is expensive because it is atomic, therefore passing it to every function that operates on the underlying object will slow things down considerably. Generally, the use of shared_ptr is relatively rare, but if you do use it, it shouldn't be passed by value to any entity that does not require ownership of the memory.
@contextfree
@contextfree 4 ай бұрын
Thanks for the comment! Yeah, I purposely passed by reference to the main printing function in both C++ and Rust to have examples of pass by reference here in addition to the examples of passing by copy/clone.
@contextfree
@contextfree 4 ай бұрын
I just didn't mention it in verbal discussion, and maybe I should have.
@overloader7900
@overloader7900 4 ай бұрын
Fun fact: writing is cheaper than reading. Also modifying has nearly same cost as writing; higher if anything because you need to read a cache line first to modify it. However, the problem comes if the new value should be seen by 2+ objects simultaneously.
@japedr
@japedr 4 ай бұрын
So I take that your argument is that multi-owner semantics is easier to describe in C# than C++ (and perhaps Rust). This is of course true, given that there is no concept of ownership in GC languages. But I would argue that multi-owner is something that should be avoided if possible, as there are many pitfalls; and in particular shallow copies are more surprising and difficult to understand than deep copies (e.g. why is the int is different but the list isn't?). I don't buy though the performance argument though: shared ptr needs to do a lot more stuff so that 1. it is thread-safe to some extent, and 2. it does need to keep track of the weak ptr bookkeeping. The performance hit is translated to the GC with its own set of tradeoffs (you probably implied this), so there's no free lunch. That's not to dismiss the amazing work of the C# compiler devs, of course.
@PhthaloJohnson
@PhthaloJohnson 4 ай бұрын
Data is ownership is a thing in GC languages, including C#, they're just not exposed to the programmer, but the GC algorithm needs to know who owns the data and for how long so that it can `safely` drop objects. This process can be quite fast and efficient, the problem is that reference counting and data dropping is not done eagerly for a lot of reasons, so you end up with these performance dips that can be unpredictable.
@japedr
@japedr 4 ай бұрын
@@PhthaloJohnson Oh sure, you're right. I should have specified *user-facing* existence of it. Of course that will matter in implementation details, for performance, etc.
@insertpenguin8443
@insertpenguin8443 4 ай бұрын
​@@japedrEven as a user you still have to think about ownership sometimes. For example when you have to ask yourself, should this be a regular HashMap or a WeakHashMap? And if you guess wrong your objects either spontaneously disappear or start hogging up your memory.
@xelaxander
@xelaxander 4 ай бұрын
I disagree. Shared ownership and mutability should be used very sparingly. Shared ownership itself is absolutely fine and often a nice tool to keep track of context.
@Hazanko83
@Hazanko83 4 ай бұрын
The comparison shouldn't come close though... Shared pointer is literally just an atomic size_t variable that gets incremented and decremented, and deletes the pointer to the held object if the reference hits 0; that's incredible cheap to the point of being almost zero-cost. Garbage collection has MUCH more work to do with walking through the list of items and checking to see if an object is still "reachable" from the programs root. I've personally built my own custom "shared_ptr" type that offers additional functionality from the standard library, and it's much much easier to implement than even a custom container type would be, let alone writing anything resembling competent garbage collection.
@sirhenrystalwart8303
@sirhenrystalwart8303 4 ай бұрын
Turning off optimizations makes zero sense. It also seems odd to say the c++ was less efficient when your own timing shows it's 3x faster.
@contextfree
@contextfree 4 ай бұрын
The timing includes compile time, because I care about that also. One viewer did some actual timing analysis with fuller optimizations, though, using Rust, C++, and D (in multiple configurations). See the link above in the description.
@contextfree
@contextfree 4 ай бұрын
Worth noting that even the benchmarking linked in the description is still limited to this simple program, which is a micro benchmark. Hopefully the measurements manage to exclude IO time as well, but I didn't ask that.
@spicybaguette7706
@spicybaguette7706 4 ай бұрын
I really like the copy/clone distinction in Rust. Is there any particular language that this idea came from or is it new?
@contextfree
@contextfree 4 ай бұрын
One place I've seen `clone` before Rust is Java, where they say that "by convention" the cloned object "should be independent" of the original object, meaning deep copy of anything mutable, and I suspect the Java method name may have influenced Rust's naming, but I don't know what predates Java in that, nor have I dug up conversations from Rust development. And of course, Java still has no value/copy types outside of primitives quite yet, although possibly coming soonish.
@krystofjakubek9376
@krystofjakubek9376 4 ай бұрын
**I was wrong here its really is displaying the actual x86 assembly, appologies** In the C# case you are not looking at x86 assembly. Instead its .NET interpreted code. They just happen to look very similar in this case.
@contextfree
@contextfree 4 ай бұрын
Are you sure? I also don't really know CIL, but .NET has AOT compilation sometimes, and those registers and instructions look like x86-64 and don't look like this example of cil here: en.wikipedia.org/wiki/Common_Intermediate_Language#Example
@contextfree
@contextfree 4 ай бұрын
Or rather .NET supports AOT compilation these days, and I suspect that's what they've configured on Compiler Explorer. See also: github.com/compiler-explorer/compiler-explorer/pull/3168
@krystofjakubek9376
@krystofjakubek9376 4 ай бұрын
@@contextfree oh nice didnt know that!
@JorgetePanete
@JorgetePanete 4 ай бұрын
it's*
@viktorstojanovic9007
@viktorstojanovic9007 4 ай бұрын
​@@contextfreeThose are assembly instructions, but you don't need aot for assembly instructions
@sanderbos4243
@sanderbos4243 4 ай бұрын
Very cool
@MrNathanShow
@MrNathanShow 4 ай бұрын
Nice to see the Godot ;)
@JasonL220
@JasonL220 4 ай бұрын
why are you invoking the toolchain as part of a benchmark, just run the outputted binary
@contextfree
@contextfree 4 ай бұрын
When I remember, I always measure cli time in my videos. My videos are edited, but I try not to edit command execution, and keeping the time there is part of that. I'm also interested in compiler speed. I'm not benchmarking here. But a viewer did do some benchmarking, even if this still is just a micro benchmark. I've linked to that in the video description.
@kamertonaudiophileplayer847
@kamertonaudiophileplayer847 4 ай бұрын
It looks like VScode wants to update.
@logangrosz6529
@logangrosz6529 4 ай бұрын
Very nice video!
@init1508
@init1508 4 ай бұрын
nice nice nice
@sporefergieboy10
@sporefergieboy10 4 ай бұрын
luv me float * ‘ate reference counting and GC simple as
@deltapi8859
@deltapi8859 4 ай бұрын
I used to say for a while GC languages solved some memory and reference issues decades ago that rust and c++ try to find sophisticated solutions for. However the concept of GC is elegant compared to what you do in these other languages. It just doesn't have optimal control and runtime performance. I think though that if people were serious about performant GC code then they would find ways to make it 90% the speed with some exceptions.
@contextfree
@contextfree 4 ай бұрын
Trade-offs exist for most things.
@vlc-cosplayer
@vlc-cosplayer 4 ай бұрын
Semi-serious question: would it be possible to provide hardware acceleration for GC? ("Semi-serious" because I don't know exactly how GC works, and if it would make sense at all to do this. But I'm guessing that if it hasn't been done yet, especially given how common GC languages are, then it's probably a silly idea. Or maybe it's not a silly idea, and we can get by fine by just throwing more powerful generic hardware at the problem... 🤔)
@contextfree
@contextfree 4 ай бұрын
@@vlc-cosplayer No immediate answer from me. I'd have to study that for a while.
@deltapi8859
@deltapi8859 4 ай бұрын
@@vlc-cosplayer good question, I think the overhead wouldn't be worth it, because the best solution is to keep as much memory as possible for as long as you don't need it for something else. Really memory management is only necessary for Operating Systems with concurrent applications that need your memory. If you manage memory for your own application you can just keep the memory address to a large piece of memory and return the last the end of the piece of memory and assign on top of that. That is how arenas do it. So all this memory management issue is largely a multiprocess issue.
@andrewgr144
@andrewgr144 4 ай бұрын
Speed isn't necessarily the issue with GC languages, and in fact I think it might not even be the issue the majority of the time. The other issues are predictability and constancy of execution time. For example, say you're writing the back end for a massively multiplayer game of some sort. It could be the case that the mean, median, and modal performance averages are all plenty fast enough, yet your decision to use GC dooms your game to poor reviews and player retention, because some small percentage of the time, the GC runs and sees that something can be deleted, but by deleting that thing, it now sees that some other stuff can be deleted, etc., in a cascading effect that leads to a noticeable lag in the game. The conditions for creating this lag may be incredibly rare as a percentage of the number of times the GC runs, but the GC may run often enough that the lag is still occurring every five or ten minutes of real time. (I think maybe a high-volume day-trading stock system might have made a more compelling illustration, but my mind immediately goes to games, and I'm sure anyone who reads this comment can see how performance lags due to GC would be disastrous in that scenario-- if the GC is fast enough for 999/1000 trades to get executed flawlessly, but 1/1000 times there's a half-second delay, allowing the many competing auto-trading bots to make their trades first, those delayed trades might completely wipe out the profit margin made by the other 999.)
@stevenhe3462
@stevenhe3462 4 ай бұрын
Makes little sense to me… All examples are single-threaded.
@contextfree
@contextfree 4 ай бұрын
What adjustments would you like to make for a multithreaded look at the topic?
@stevenhe3462
@stevenhe3462 4 ай бұрын
@@contextfree What happens when you mutate your struct from different threads? In Cpp it works (except it rarely causes data races?), in Rust it doesn't (Rc is not Send, have to use Arc instead), in C# I don't know… Also, C# tracing GC stops all (most) threads when it runs but the other two guys don't?
@metaltyphoon
@metaltyphoon 4 ай бұрын
Why dotnet 7? Should try this with dotnet 8 AOT.
@contextfree
@contextfree 4 ай бұрын
It's what's currently handy on Compiler Explorer. They also have an unclear "main" option. I suspect 8.0 is coming there sometime.
@metaltyphoon
@metaltyphoon 4 ай бұрын
@@contextfree aaa nice to know
@Liphi
@Liphi 4 ай бұрын
dotnet 7 also supports AOT
@metaltyphoon
@metaltyphoon 4 ай бұрын
@@Liphi yes but codegen for 8 is much better as libraries get more annotated for AOT
@Liphi
@Liphi 4 ай бұрын
@@metaltyphoon I mean, that's just a basic struct manipulation. Doubt that .net 8 can change something here
@OCTAGRAM
@OCTAGRAM 4 ай бұрын
Not structs, but records
@contextfree
@contextfree 3 ай бұрын
Mind explaining more?
@OCTAGRAM
@OCTAGRAM 3 ай бұрын
@@contextfree We don't put structs into database tables. We put records into database tables. They are records
@contextfree
@contextfree 3 ай бұрын
So you would prefer if these languages had used the term "record" instead of "struct", if I understand correctly. Interestingly, C# has a language feature called "record" these days, and it means something different than "struct" there. More to what seems to be your main point, long ago I learned C before learning Pascal, so I learned the term "struct" first. Although I think you're right that "record" has a longer history in such usage.
@OCTAGRAM
@OCTAGRAM 3 ай бұрын
@@contextfree Yes. Ada, Modula, Oberon, Oxygene, Icon, they all have records. But whatever Haskell you take from outside the family, it also has records
@RoughB8
@RoughB8 4 ай бұрын
Interesting video but I am missing the point of the video. Your comparison of C#'s CLR instructions with C++'s x86 assembly is just unfair. It seems you dislike the extra syntax that rust adds on you when you want to copy an object. It would have also been interesting to compare a 'real' application (in the 3 languages) with full optimization instead of a minimal program that you manually need to prevent inlining.
@contextfree
@contextfree 4 ай бұрын
Yeah, I rarely express opinions directly in my videos (although I actually like Rust clone vs C++ implicit copy constructors, but don't tell anyone). I usually just explore stuff. And RC optimizations are definitely an interesting topic that I avoided discussing here.
@contextfree
@contextfree 4 ай бұрын
One of many interesting video topics could be exploring heavily compiler-optimized C++ and/or Rust and/or Swift RC in simple cases vs say Perceus RC such as in Roc or Koka. Haven't explored that yet, though.
@RoughB8
@RoughB8 4 ай бұрын
@@contextfree After a few years of C++ i love to remove implicitly as this leads to the worst errors. At some point I created a hardware interface implicitly from string which caused havoc :)
@RoughB8
@RoughB8 4 ай бұрын
@@contextfree It could be as simple as reading numbers from file, adding them up and printing the sum to terminal. With godbolt its great that you can compare different optimization levels and see when the compiler starts using SSE instructions.
@Liphi
@Liphi 4 ай бұрын
C# app was also in x86 assembly (aot or after jit). IL looks different
@yuan.pingchen3056
@yuan.pingchen3056 4 ай бұрын
I prefer Rust, the Rust language is not only a memory-safe language, but it simplifies the complexity of C++ syntax that is overextended due to modern language features, but what about C#? It's a copycat of Microsoft's special version of Java, it runs in a VM, and garbage collection cannot be removed...
@andrewgr144
@andrewgr144 4 ай бұрын
I abandoned learning Rust because there are so few jobs in it, and getting a job as a programmer at a quality company when you're in your mid-late 50s is hard enough as it is. I didn't get to the point in my Rust journey where it ever felt like I wasn't fighting the language, but I truly believe that I would have, eventually. The main thing that I love about Rust is the way enums are first-class data objects, and the way the compiler makes sure you're covering every possible value that can be returned (if the return type is an enum). It feels so natural, and I wound up writing functions that looked a lot like finite state machines, which I find particularly easy to understand and reason about correctly. It is my understanding that this feature is common in functional languages; even if that's the case (pun not intended but duly noted), Rust is the first time I remember encountering it in a C-derived language. (Actually, now that I think about it, I also really miss that attribute system, which took a while to wrap my head around, but has profoundly changed how I think about many problems, to the point that I've become really interested in tagging systems in contexts other than programming. I know Rust isn't the first language, or even C-derived language, to use something like attributes, but it's the first time I encountered it as a core language feature.)
@yuan.pingchen3056
@yuan.pingchen3056 4 ай бұрын
@@andrewgr144 You are right, Rust is not a good choice for work reasons, but I only learned it because of its modern features. I worked for a company that made set-top boxes, and the original code of the company's product had a lot of unused annotations. And a large number of global static variables, and the inexplicable insistence on using the ANSIC standard makes the original code messy and difficult to maintain. I don’t understand why the company insists on using the C language. Obviously the tool chain provided by the set-top box supplier provides g++ related files. There is nothing missing. Using C++'s data encapsulation function and construction and destruction function can enhance the readability of the code and simplify a lot of complexity. Of course, this is a story later. The company's programmers do not have the ability to C++. they can't even understand the construction and deconstruction functions provided by the C++ language. This is a company where engineers insist on only doing their own part to clean up the trouble. After many years, I learned that the internal state of this kind of company is very important to a China mainland company. The company is the norm. Fortunately, I left my job early. At that time, I still had the enthusiasm for new technologies and the insistence that the code should be beautifully designed. I was not suitable to stay in such an aging and decadent company.
Rust: When C Code Isn't Enough
8:26
CodeAhead
Рет қаралды 162 М.
Starting my own hobby language (again)
13:17
Context Free
Рет қаралды 7 М.
ПРИКОЛЫ НАД БРАТОМ #shorts
00:23
Паша Осадчий
Рет қаралды 6 МЛН
How To Get Married:   #short
00:22
Jin and Hattie
Рет қаралды 13 МЛН
Win This Dodgeball Game or DIE…
00:36
Alan Chikin Chow
Рет қаралды 30 МЛН
Constructors Are Broken
18:16
Logan Smith
Рет қаралды 108 М.
Metaprogramming and JIT Compilers - A Brief Overview
15:59
VoxelRifts
Рет қаралды 26 М.
Coding raw WebAssembly Text - Dive into Wat
9:25
Context Free
Рет қаралды 7 М.
The 3 Laws of Writing Readable Code
5:28
Kantan Coding
Рет қаралды 563 М.
The Death of Monads? Direct Style Algebraic Effects
17:13
Impure Pics
Рет қаралды 18 М.
6 Programming Languages in 1 Godot Game! Trying out GDExtension!
19:22
Arenas, strings and Scuffed Templates in C
12:28
VoxelRifts
Рет қаралды 86 М.
Making a language: Pretty if/else branching
9:55
Context Free
Рет қаралды 4,2 М.
Teaching myself C so I can build a particle simulation
11:52
Gradience
Рет қаралды 255 М.
Comparing C to Assembly
10:50
The Builder
Рет қаралды 6 М.
ПРИКОЛЫ НАД БРАТОМ #shorts
00:23
Паша Осадчий
Рет қаралды 6 МЛН