digitalmars.D - gc attribute for bypassign nogc
- bitwise (42/42) Jul 24 2016 Any thoughts on an @gc attribute for bypassing @nogc?
- ketmar (5/7) Jul 24 2016 that's what i ended up with: not using @nogc. it is pure
- ketmar (1/1) Jul 24 2016 pure *marketing* thing, lol.
- bitwise (14/22) Jul 24 2016 I don't understand what you mean, saying it's useless.
- ketmar (9/10) Jul 24 2016 exactly that. in the end i can't mark any code @nogc except very
- Lodovico Giaretta (9/51) Jul 24 2016 In this kind of situation, the solution is to not use @nogc and
- Dicebot (3/3) Jul 24 2016 @nogc functions must never ever trigger GC collection cycle, not
- bitwise (13/16) Jul 24 2016 The fact that you can use malloc() in a @nogc function
- rikki cattermole (8/47) Jul 24 2016 I've been saying for a very long time we need @assumenogc attribute like...
- Jonathan Marler (6/15) Jul 24 2016 I havent seen this assumegc propsal before, could you provide the
- rikki cattermole (6/22) Jul 25 2016 I've mostly kept it off hand for other regulars as I'm not really the
- bitwise (10/13) Jul 25 2016 So I'm not crazy then ;)
- Chris Wright (6/21) Jul 25 2016 @nogc conflates "doesn't allocate memory from the GC heap because I don'...
- bitwise (16/40) Jul 25 2016 Fair point.
- ketmar (6/9) Jul 25 2016 i don't think that it will be added, though. but you can emulate
- jmh530 (5/10) Jul 26 2016 For whatever reason, I like the idea of annotations behaving like
- bitwise (14/26) Jul 26 2016 Chris is right that @safe/@trusted is not analogous to
- Danni Coy via Digitalmars-d (10/39) Jul 27 2016 I am not convinced this is the best way to go although it would be a
- Guillaume Piolat (5/10) Jul 27 2016 FWIW I've removed every use of that bypassing (was used for
- bitwise (28/43) Jul 27 2016 The point is though, that I WANT to use the GC. I want the memory
- Lodovico Giaretta (9/33) Jul 28 2016 If @assumegc has to be manually checked to see if it is
- bitwise (22/62) Jul 28 2016 It's not about running out of memory. It's a performance issue.
- Guillaume Piolat (4/9) Jul 28 2016 Vladimir implemented counting in -profile=gc, it gives you the
- bitwise (10/22) Jul 28 2016 I'm not sure if this point is meant to be for or against what I'm
- default0 (30/55) Jul 28 2016 Just my 2 cents on naming: what you want sounds a lot more like
- bitwise (15/74) Jul 28 2016 I think you're complicating the issue quite a bit here.
- Lodovico Giaretta (13/33) Jul 28 2016 Well, here in my opinion there's the wrong attitude of profiling
- Meta (5/10) Jul 28 2016 It sounds like -vgc and --profile=gc are exactly what you want.
- bitwise (13/25) Jul 28 2016 I understand that @assumenogc may not be exactly the right
- Lodovico Giaretta (10/35) Jul 28 2016 Also, @assumenogc or whatever does not play well with public
- jdfgjdf (4/5) Jul 28 2016 I like the typo in the title. Let's make a game:
- jdfgjdf (27/32) Jul 28 2016 Entry one:
Any thoughts on an gc attribute for bypassing nogc? ignore my level of productivity, as it compares to projects I've done in C++. If I had to write a butter-smooth AAA game, it may be a problem, but at present, my thoughts on a few small jitters here and there are....who cares? As long as GC usage is kept to a minimum, things will usually work ok fine. For example, in a game, I may create a script with an "update" method that gets called each frame. I wouldn't want people(or myself) accidentally allocating memory here, possible 30-60 times per second, so I would make that function nogc. But, there *will* be cases where I actually want to allocate something, for example, to spawn a piece of cake. Example: class Cake{} class MyScript { SysTime when; this() { when = Clock.currTime + 5.seconds; } void update() nogc { // ... if(Clock.currTime >= when) { gc { Cake c = new Cake(); } } } } void main(string[] args) { MyScript script = new MyScript(); foreach(i; 0..10) { script.update(); Thread.sleep(1.seconds); } } There is the following, which is clever. But if it came down to having to do this to bypass nogc, I simply wouldn't use nogc. https://p0nce.github.io/d-idioms/#Bypassing- nogc When you have to do it thousands of times throughout your codebase, then yes, it's that bad. Bit
Jul 24 2016
On Sunday, 24 July 2016 at 22:13:02 UTC, bitwise wrote:There is the following, which is clever. But if it came down to having to do this to bypass nogc, I simply wouldn't use nogc.that's what i ended up with: not using nogc. it is pure parketing thing. for real world using it adds more troubles than it ever solved (and did it solve at least something?!). i'd say: "don't bother with nogc, it is mostly useless."
Jul 24 2016
On Sunday, 24 July 2016 at 22:21:51 UTC, ketmar wrote:On Sunday, 24 July 2016 at 22:13:02 UTC, bitwise wrote:I don't understand what you mean, saying it's useless. I intend to do this: class Script { nogc void update(){} } class CustomScript : Script { override void update(){} } If I did this, it would act as a safety net, and prevent a lot of accidental allocations. Keep in mind, "update" is meant to run 30-60 times per second, so allocations would add up extremely fast. BitThere is the following, which is clever. But if it came down to having to do this to bypass nogc, I simply wouldn't use nogc.that's what i ended up with: not using nogc. it is pure parketing thing. for real world using it adds more troubles than it ever solved (and did it solve at least something?!). i'd say: "don't bother with nogc, it is mostly useless."
Jul 24 2016
On Sunday, 24 July 2016 at 23:14:37 UTC, bitwise wrote:I don't understand what you mean, saying it's useless.exactly that. in the end i can't mark any code nogc except very trivial, where it doesn't matter at all (primitive getters and setters). in other code i ocasionally need to allocate or throw. so you have to ditch nogc anyway. and yes, i'm talking about engines that should maintain solid 60 FPS. and for "safety nets" i prefer to use "-vgc" after i done some amount of work to see if i accidentally missed something.
Jul 24 2016
On Sunday, 24 July 2016 at 22:13:02 UTC, bitwise wrote:Any thoughts on an gc attribute for bypassing nogc? can't ignore my level of productivity, as it compares to projects I've done in C++. If I had to write a butter-smooth AAA game, it may be a problem, but at present, my thoughts on a few small jitters here and there are....who cares? As long as GC usage is kept to a minimum, things will usually work ok fine. For example, in a game, I may create a script with an "update" method that gets called each frame. I wouldn't want people(or myself) accidentally allocating memory here, possible 30-60 times per second, so I would make that function nogc. But, there *will* be cases where I actually want to allocate something, for example, to spawn a piece of cake. Example: class Cake{} class MyScript { SysTime when; this() { when = Clock.currTime + 5.seconds; } void update() nogc { // ... if(Clock.currTime >= when) { gc { Cake c = new Cake(); } } } } void main(string[] args) { MyScript script = new MyScript(); foreach(i; 0..10) { script.update(); Thread.sleep(1.seconds); } } There is the following, which is clever. But if it came down to having to do this to bypass nogc, I simply wouldn't use nogc. https://p0nce.github.io/d-idioms/#Bypassing- nogc When you have to do it thousands of times throughout your codebase, then yes, it's that bad. BitIn this kind of situation, the solution is to not use nogc and use the built-in gc profiler to decide which functions need memory usage optimizations. We should be very careful, that using nogc is not the aim. It is just one of the available tools to avoid our application randomly freezing due to collections. That is the aim. And there are other tools to achieve it: the allocators library and the built-in gc profiler.
Jul 24 2016
nogc functions must never ever trigger GC collection cycle, not under any possible circumstances. Otherwise the attribute serves no purpose.
Jul 24 2016
On Sunday, 24 July 2016 at 23:10:18 UTC, Dicebot wrote:nogc functions must never ever trigger GC collection cycle, not under any possible circumstances. Otherwise the attribute serves no purpose.The fact that you can use malloc() in a nogc function invalidates this argument. There are many ways for someone publishing a piece of code or DUB package to be irresponsible about memory management. Adding this would not make it any more likely. Adding gc to a piece of code to bypass nogc is not something that could be done by accident. Imagine though, if there was a DUB package that provided some base class that had its virtual methods annotated with nogc. If I downloaded the package, and decided that using GC was perfectly fine in my application, I would be screwed if I wanted to inherit one of the classes from that package. Bit
Jul 24 2016
On Sunday, 24 July 2016 at 23:30:37 UTC, bitwise wrote:On Sunday, 24 July 2016 at 23:10:18 UTC, Dicebot wrote:malloc is not even on the same order of magnitude of impact as GC. nogc is primarily about latency and preventing unwanted stop the world cycle, not about performance or allocation count per se.nogc functions must never ever trigger GC collection cycle, not under any possible circumstances. Otherwise the attribute serves no purpose.The fact that you can use malloc() in a nogc function invalidates this argument.
Jul 24 2016
On Sunday, 24 July 2016 at 23:30:37 UTC, bitwise wrote:On Sunday, 24 July 2016 at 23:10:18 UTC, Dicebot wrote:nope. `malloc()` has nothing to do with garbage collection. what ` nogc` means is "i won't use built-in allocator with garbage collection in this code", not "i won't do any memory allocations in this code".nogc functions must never ever trigger GC collection cycle, not under any possible circumstances. Otherwise the attribute serves no purpose.The fact that you can use malloc() in a nogc function invalidates this argument.
Jul 24 2016
On Monday, 25 July 2016 at 00:05:16 UTC, ketmar wrote:On Sunday, 24 July 2016 at 23:30:37 UTC, bitwise wrote:If someone knows all their code is nogc, they can disable the GC. If they do that, and then someone GC allocates anyways, it's a leak. Based on this, an argument could be made that nogc should *never* be bypassed. But that argument is made on the false premise that it's fool-proof in it's current condition. It's not, because you can already use malloc() in a nogc function and leak that memory instead. BitOn Sunday, 24 July 2016 at 23:10:18 UTC, Dicebot wrote:nope. `malloc()` has nothing to do with garbage collection. what ` nogc` means is "i won't use built-in allocator with garbage collection in this code", not "i won't do any memory allocations in this code".nogc functions must never ever trigger GC collection cycle, not under any possible circumstances. Otherwise the attribute serves no purpose.The fact that you can use malloc() in a nogc function invalidates this argument.
Jul 24 2016
On Monday, 25 July 2016 at 00:26:05 UTC, bitwise wrote:If someone knows all their code is nogc, they can disable the GC. If they do that, and then someone GC allocates anyways, it's a leak. Based on this, an argument could be made that nogc should *never* be bypassed. But that argument is made on the false premise that it's fool-proof in it's current condition. It's not, because you can already use malloc() in a nogc function and leak that memory instead.` nogc` should not be bypassed due to completely different reasons. while compiler is not doing any optimizations or generating any GC helpers for gc code now, it *can* do that in the future, so cheating the compiler is bad idea. otherwise, ` nogc` doesn't really guarantee absence of memory leaks, and it wasn't designed to do so.
Jul 24 2016
On 25/07/2016 10:13 AM, bitwise wrote:Any thoughts on an gc attribute for bypassing nogc? my level of productivity, as it compares to projects I've done in C++. If I had to write a butter-smooth AAA game, it may be a problem, but at present, my thoughts on a few small jitters here and there are....who cares? As long as GC usage is kept to a minimum, things will usually work ok fine. For example, in a game, I may create a script with an "update" method that gets called each frame. I wouldn't want people(or myself) accidentally allocating memory here, possible 30-60 times per second, so I would make that function nogc. But, there *will* be cases where I actually want to allocate something, for example, to spawn a piece of cake. Example: class Cake{} class MyScript { SysTime when; this() { when = Clock.currTime + 5.seconds; } void update() nogc { // ... if(Clock.currTime >= when) { gc { Cake c = new Cake(); } } } } void main(string[] args) { MyScript script = new MyScript(); foreach(i; 0..10) { script.update(); Thread.sleep(1.seconds); } } There is the following, which is clever. But if it came down to having to do this to bypass nogc, I simply wouldn't use nogc. https://p0nce.github.io/d-idioms/#Bypassing- nogc When you have to do it thousands of times throughout your codebase, then yes, it's that bad. BitI've been saying for a very long time we need assumenogc attribute like we have trusted for safe. I have not been taken very seriously about this... Although I see no reason to allow GC in assumenogc as long as it does not trigger scan/collect phase of it. After all, why don't we have a hint on allocation if we do or do not want it to trigger a scan? Or even better, a thread local stack to specify this!
Jul 24 2016
On Monday, 25 July 2016 at 03:18:17 UTC, rikki cattermole wrote:On 25/07/2016 10:13 AM, bitwise wrote:I havent seen this assumegc propsal before, could you provide the definition you had in mind for it?[...]I've been saying for a very long time we need assumenogc attribute like we have trusted for safe.I have not been taken very seriously about this... Although I see no reason to allow GC in assumenogc as long as it does not trigger scan/collect phase of it. After all, why don't we have a hint on allocation if we do or do not want it to trigger a scan?If the GC supported this mode (NoCollectionMode), what should the GC do when it is in this mode and an allocation is requested that can't be done until a collection is done?
Jul 24 2016
On 25/07/2016 5:16 PM, Jonathan Marler wrote:On Monday, 25 July 2016 at 03:18:17 UTC, rikki cattermole wrote:I've mostly kept it off hand for other regulars as I'm not really the best person to run with it and make it happen.On 25/07/2016 10:13 AM, bitwise wrote:I havent seen this assumegc propsal before, could you provide the definition you had in mind for it?[...]I've been saying for a very long time we need assumenogc attribute like we have trusted for safe.Fail. On Linux this should almost never happen and Windows should in theory be the same way.I have not been taken very seriously about this... Although I see no reason to allow GC in assumenogc as long as it does not trigger scan/collect phase of it. After all, why don't we have a hint on allocation if we do or do not want it to trigger a scan?If the GC supported this mode (NoCollectionMode), what should the GC do when it is in this mode and an allocation is requested that can't be done until a collection is done?
Jul 25 2016
On Monday, 25 July 2016 at 07:43:34 UTC, rikki cattermole wrote:I've been saying for a very long time we need assumenogc attribute like we have trusted for safe.So I'm not crazy then ;) I'm wondering if Andrei and Walter consider trusted a win though. They seem to have such firm stances on certain issues that it makes me wonder if they consider things like trusted a liability. Personally, I lean way to the side of flexibility, and believe a good language shouldn't force you to code a certain way(within reason). I feel like this type of feature is very reasonable. Bit
Jul 25 2016
On Mon, 25 Jul 2016 15:46:54 +0000, bitwise wrote:On Monday, 25 July 2016 at 07:43:34 UTC, rikki cattermole wrote:nogc conflates "doesn't allocate memory from the GC heap because I don't want my application to use the GC at all" with "doesn't cause GC collection pauses". The latter can have a assumenogc annotation that works -- you call GC.disable and GC.enable as appropriate. The former can't.I've been saying for a very long time we need assumenogc attribute like we have trusted for safe.So I'm not crazy then ;) I'm wondering if Andrei and Walter consider trusted a win though. They seem to have such firm stances on certain issues that it makes me wonder if they consider things like trusted a liability. Personally, I lean way to the side of flexibility, and believe a good language shouldn't force you to code a certain way(within reason). I feel like this type of feature is very reasonable. Bit
Jul 25 2016
On Tuesday, 26 July 2016 at 01:07:27 UTC, Chris Wright wrote:On Mon, 25 Jul 2016 15:46:54 +0000, bitwise wrote:Fair point. You got me thinking though. For my intended usage, I don't actually need errors for GC allocation, and that may actually be inappropriate. I just need to make a best effort to avoid allocations. Something like warngc could work nicely. It could function exactly as nogc with the exception that it issued warnings instead of errors. I feel like some people reading this would be very quick to scold me for "premature optimization", and recommend a profiler, but in the case of 30-60 fps games, it's practically guaranteed that you will eventually run into performance problems. Especially on mobile devices. So proactively writing good code can save you a lot of headache. BitOn Monday, 25 July 2016 at 07:43:34 UTC, rikki cattermole wrote:nogc conflates "doesn't allocate memory from the GC heap because I don't want my application to use the GC at all" with "doesn't cause GC collection pauses". The latter can have a assumenogc annotation that works -- you call GC.disable and GC.enable as appropriate. The former can't.I've been saying for a very long time we need assumenogc attribute like we have trusted for safe.So I'm not crazy then ;) I'm wondering if Andrei and Walter consider trusted a win though. They seem to have such firm stances on certain issues that it makes me wonder if they consider things like trusted a liability. Personally, I lean way to the side of flexibility, and believe a good language shouldn't force you to code a certain way(within reason). I feel like this type of feature is very reasonable. Bit
Jul 25 2016
On Tuesday, 26 July 2016 at 02:42:52 UTC, bitwise wrote:Something like warngc could work nicely. It could function exactly as nogc with the exception that it issued warnings instead of errors.i don't think that it will be added, though. but you can emulate it with external utility: either with dscanner (writing your own linter), or with "-vgc" and then using simple regexp to find in which function the reported line is in. somewhat messy, but it is the way to get the work done without waiting for new attr. ;-)
Jul 25 2016
p.s. probably even with -vgc to list line numbers and dscanner to find function names/signatures. "-vgc" has the advantage of reporting closuses, while with "handmade" linter you'll have to track that by yourself.
Jul 25 2016
On Tuesday, 26 July 2016 at 02:49:59 UTC, ketmar wrote:On Tuesday, 26 July 2016 at 02:42:52 UTC, bitwise wrote:Actually, thinking about this a bit more, I think warngc would be bad anyways. Code that was basically which worked exactly as is was designed to would issue errors, which would be bad. Writing a custom linter is not an option. Not only because of the work/maintainence involved, but because it would complicate workflow. What I want is easily achieved during compilation. My goal is to proactively deal with allocations that are in places that they shouldn't be 90% of the time, like per-frame updates in a real-time application or game. BitSomething like warngc could work nicely. It could function exactly as nogc with the exception that it issued warnings instead of errors.i don't think that it will be added, though. but you can emulate it with external utility: either with dscanner (writing your own linter), or with "-vgc" and then using simple regexp to find in which function the reported line is in. somewhat messy, but it is the way to get the work done without waiting for new attr. ;-)
Jul 26 2016
On Tuesday, 26 July 2016 at 01:07:27 UTC, Chris Wright wrote:nogc conflates "doesn't allocate memory from the GC heap because I don't want my application to use the GC at all" with "doesn't cause GC collection pauses". The latter can have a assumenogc annotation that works -- you call GC.disable and GC.enable as appropriate. The former can't.For whatever reason, I like the idea of annotations behaving like enums. So instead of gc or assumenogc, you could have something like nogc.false or nogc.assume. You wouldn't add new annotations, just new behavior for existing annotations.
Jul 26 2016
On Tuesday, 26 July 2016 at 14:51:21 UTC, jmh530 wrote:On Tuesday, 26 July 2016 at 01:07:27 UTC, Chris Wright wrote:Chris is right that safe/ trusted is not analogous to nogc/ assumenogc, but I still think assumenogc is a good idea..or maybe nogc(false) to offer the opposite behaviour of nogc. There are arguments that can be made against this idea, but IMO, it's really hard to screw this up unintentionally. It's not like it's an invisible implicit conversion. There are plenty of valid use cases. One, like I mentioned, about strongly deterring allocations in certain contexts instead of completely disallowing them. Also, deferring garbage collection until the end of a performance sensitive algorithm that may still allocate, so that GC.collect can be called manually afterward. Bit.nogc conflates "doesn't allocate memory from the GC heap because I don't want my application to use the GC at all" with "doesn't cause GC collection pauses". The latter can have a assumenogc annotation that works -- you call GC.disable and GC.enable as appropriate. The former can't.For whatever reason, I like the idea of annotations behaving like enums. So instead of gc or assumenogc, you could have something like nogc.false or nogc.assume. You wouldn't add new annotations, just new behavior for existing annotations.
Jul 26 2016
I am not convinced this is the best way to go although it would be a relatively easy solution. What I would personally prefer was if there was a language mechanism to mark theAllocator, processAllocator (iAllocator) to be nogc as long as the allocator in question is not the GCAllocator. I am thinking specifically of the situation where vendor A can create a dynamic library in D that uses theAllocator and vendor B uses that library without necessarily having the source code. On Wed, Jul 27, 2016 at 7:05 AM, bitwise via Digitalmars-d <digitalmars-d puremagic.com> wrote:On Tuesday, 26 July 2016 at 14:51:21 UTC, jmh530 wrote:On Tuesday, 26 July 2016 at 01:07:27 UTC, Chris Wright wrote:Chris is right that safe/ trusted is not analogous to nogc/ assumenogc, but I still think assumenogc is a good idea..or maybe nogc(false) to offer the opposite behaviour of nogc. There are arguments that can be made against this idea, but IMO, it's really hard to screw this up unintentionally. It's not like it's an invisible implicit conversion. There are plenty of valid use cases. One, like I mentioned, about strongly deterring allocations in certain contexts instead of completely disallowing them. Also, deferring garbage collection until the end of a performance sensitive algorithm that may still allocate, so that GC.collect can be called manually afterward. Bit.nogc conflates "doesn't allocate memory from the GC heap because I don't want my application to use the GC at all" with "doesn't cause GC collection pauses". The latter can have a assumenogc annotation that works -- you call GC.disable and GC.enable as appropriate. The former can't.For whatever reason, I like the idea of annotations behaving like enums. So instead of gc or assumenogc, you could have something like nogc.false or nogc.assume. You wouldn't add new annotations, just new behavior for existing annotations.
Jul 27 2016
On Sunday, 24 July 2016 at 22:13:02 UTC, bitwise wrote:There is the following, which is clever. But if it came down to having to do this to bypass nogc, I simply wouldn't use nogc. https://p0nce.github.io/d-idioms/#Bypassing- nogc When you have to do it thousands of times throughout your codebase, then yes, it's that bad.FWIW I've removed every use of that bypassing (was used for runtime initialization or semaphores locks). You can also use emplace/destroy like in: https://github.com/d-gamedev-team/gfm/blob/master/core/gfm/core/memory.d#L238
Jul 27 2016
On Wednesday, 27 July 2016 at 20:42:01 UTC, Guillaume Piolat wrote:On Sunday, 24 July 2016 at 22:13:02 UTC, bitwise wrote:The point is though, that I WANT to use the GC. I want the memory cleaned up for me, and I don't mind little pauses once in a while. I just don't want careless allocations to happen in certain performance-sensitive contexts, like per-frame updates. While working on a past project(C++), I found this little gem: void draw() { Font* f = new Font("arial.ttf", 16); drawText(f, "hello world"); } As utterly moronic as this seems, this was a real bug that I had to fix. Our game was literally topping out at 2GB of memory usage after ~30 seconds and crashing. Note: it wasn't my code ;) If that code was written in D with the feature I'm asking for, draw() would have been marked with nogc. The person who wrote the above code would have either had to store the font somewhere else, or insert a assumenogc{} section to actually do that. So it either would not have happened, or would have been much easier to find. If you found that your game/app was using too much GC, searching for " assumenogc" would likely uncover the cause, as long as your root classes were annotated correctly. The assumenogc annotation would plainly show where allocations were happening that maybe shouldn't be. Bit BitThere is the following, which is clever. But if it came down to having to do this to bypass nogc, I simply wouldn't use nogc. https://p0nce.github.io/d-idioms/#Bypassing- nogc When you have to do it thousands of times throughout your codebase, then yes, it's that bad.FWIW I've removed every use of that bypassing (was used for runtime initialization or semaphores locks). You can also use emplace/destroy like in: https://github.com/d-gamedev-team/gfm/blob/master/core/gfm/core/memory.d#L238
Jul 27 2016
On Thursday, 28 July 2016 at 00:23:57 UTC, bitwise wrote:The point is though, that I WANT to use the GC. I want the memory cleaned up for me, and I don't mind little pauses once in a while. I just don't want careless allocations to happen in certain performance-sensitive contexts, like per-frame updates. While working on a past project(C++), I found this little gem: void draw() { Font* f = new Font("arial.ttf", 16); drawText(f, "hello world"); } As utterly moronic as this seems, this was a real bug that I had to fix. Our game was literally topping out at 2GB of memory usage after ~30 seconds and crashing. Note: it wasn't my code ;) If that code was written in D with the feature I'm asking for, draw() would have been marked with nogc. The person who wrote the above code would have either had to store the font somewhere else, or insert a assumenogc{} section to actually do that. So it either would not have happened, or would have been much easier to find. If you found that your game/app was using too much GC, searching for " assumenogc" would likely uncover the cause, as long as your root classes were annotated correctly. The assumenogc annotation would plainly show where allocations were happening that maybe shouldn't be.If assumegc has to be manually checked to see if it is over-allocating whenever the application is going out of memory, then it is no more useful than running the gc-profiler when the application is over-allocating. The profiler is even better, because with assumegc you have to check ALL marked functions to find the leaking one, while the gc-profiler would just put it on top of the report, making your job easier. So IMHO we already have an instrument to solve these problems.
Jul 28 2016
On Thursday, 28 July 2016 at 07:12:06 UTC, Lodovico Giaretta wrote:On Thursday, 28 July 2016 at 00:23:57 UTC, bitwise wrote:It's not about running out of memory. It's a performance issue. Example: In the following class, it would be perfectly fine, and even expected to allocate in start() but not in update(). This is because start() gets called once on object initialization, but update() would get called every frame. class NPC { // .... void start() { this.hat = new Hat(); } void update() nogc { this.timer += Clock.currTime; check(this.timer); updateUI(); } } Finally, the use of a profiler, and nogc/ assumenogc wouldn't be mutually exclusive. If a profiler had a filter-by-attribute functionality, you could set it to nogc functions, and it would narrow down the results to the functions where allocations actually matter. BitThe point is though, that I WANT to use the GC. I want the memory cleaned up for me, and I don't mind little pauses once in a while. I just don't want careless allocations to happen in certain performance-sensitive contexts, like per-frame updates. While working on a past project(C++), I found this little gem: void draw() { Font* f = new Font("arial.ttf", 16); drawText(f, "hello world"); } As utterly moronic as this seems, this was a real bug that I had to fix. Our game was literally topping out at 2GB of memory usage after ~30 seconds and crashing. Note: it wasn't my code ;) If that code was written in D with the feature I'm asking for, draw() would have been marked with nogc. The person who wrote the above code would have either had to store the font somewhere else, or insert a assumenogc{} section to actually do that. So it either would not have happened, or would have been much easier to find. If you found that your game/app was using too much GC, searching for " assumenogc" would likely uncover the cause, as long as your root classes were annotated correctly. The assumenogc annotation would plainly show where allocations were happening that maybe shouldn't be.If assumegc has to be manually checked to see if it is over-allocating whenever the application is going out of memory, then it is no more useful than running the gc-profiler when the application is over-allocating. The profiler is even better, because with assumegc you have to check ALL marked functions to find the leaking one, while the gc-profiler would just put it on top of the report, making your job easier. So IMHO we already have an instrument to solve these problems.
Jul 28 2016
On Thursday, 28 July 2016 at 15:24:10 UTC, bitwise wrote:It's not about running out of memory. It's a performance issue. Example: In the following class, it would be perfectly fine, and even expected to allocate in start() but not in update(). This is because start() gets called once on object initialization, but update() would get called every frame.Vladimir implemented counting in -profile=gc, it gives you the number of allocations and the amount allocated for each allocation point.
Jul 28 2016
On Thursday, 28 July 2016 at 16:15:04 UTC, Guillaume Piolat wrote:On Thursday, 28 July 2016 at 15:24:10 UTC, bitwise wrote:I'm not sure if this point is meant to be for or against what I'm suggesting, but still, I'm thinking in terms of *proactively* writing efficient code, not allowing an app get to the point where you need to run a profiler. The situation is similar to using safe. You *could* just write code however you want, wait until it crashes, then try to find the problem using Valgrind or something, but that's bad for obvious reasons. BitIt's not about running out of memory. It's a performance issue. Example: In the following class, it would be perfectly fine, and even expected to allocate in start() but not in update(). This is because start() gets called once on object initialization, but update() would get called every frame.Vladimir implemented counting in -profile=gc, it gives you the number of allocations and the amount allocated for each allocation point.
Jul 28 2016
On Thursday, 28 July 2016 at 16:45:05 UTC, bitwise wrote:On Thursday, 28 July 2016 at 16:15:04 UTC, Guillaume Piolat wrote:Just my 2 cents on naming: what you want sounds a lot more like warngc than assumenogc or whatever was floating around before. What such an attribute should do and if its worth implementing is hard to figure out, though. Presumably you'd have your update() method marked warngc but then how is the compiler supposed to know that an allocation like this: class A { void update() warngc { if(rareCondition()) { // something that allocates } } } is perfectly fine, but something like this class B { void update() warngc { if(almostAlwaysTrue()) { // something that allocates } } } is not? That issue aside, what exactly do you envision the compiler to tell you (examples of error messages and code patterns it should detect, examples of code patterns that it should NOT detect and are fine) incase it automagically finds problematic code? I'm having trouble putting a thumb on what you want following this thread, because what you are describing feels a bit vague to me.On Thursday, 28 July 2016 at 15:24:10 UTC, bitwise wrote:I'm not sure if this point is meant to be for or against what I'm suggesting, but still, I'm thinking in terms of *proactively* writing efficient code, not allowing an app get to the point where you need to run a profiler. The situation is similar to using safe. You *could* just write code however you want, wait until it crashes, then try to find the problem using Valgrind or something, but that's bad for obvious reasons. BitIt's not about running out of memory. It's a performance issue. Example: In the following class, it would be perfectly fine, and even expected to allocate in start() but not in update(). This is because start() gets called once on object initialization, but update() would get called every frame.Vladimir implemented counting in -profile=gc, it gives you the number of allocations and the amount allocated for each allocation point.
Jul 28 2016
On Thursday, 28 July 2016 at 16:58:14 UTC, default0 wrote:On Thursday, 28 July 2016 at 16:45:05 UTC, bitwise wrote:I think you're complicating the issue quite a bit here. It's very simple: nogc { /* in this scope, compiler disallows GC allocations. */ } nogc { assumenogc { /* here, GC allocations are allowed */ } } assumenogc would simply reverse the effects of the nogc flag on a given scope. So nogc could be applied to performance critical scopes, as it is now. The exception would be, that if I as a programmer knew that I was only making a small one-time allocation, and that the GC was still enabled, I could do so by surrounding the allocation with assumenogc. BitOn Thursday, 28 July 2016 at 16:15:04 UTC, Guillaume Piolat wrote:Just my 2 cents on naming: what you want sounds a lot more like warngc than assumenogc or whatever was floating around before. What such an attribute should do and if its worth implementing is hard to figure out, though. Presumably you'd have your update() method marked warngc but then how is the compiler supposed to know that an allocation like this: class A { void update() warngc { if(rareCondition()) { // something that allocates } } } is perfectly fine, but something like this class B { void update() warngc { if(almostAlwaysTrue()) { // something that allocates } } } is not? That issue aside, what exactly do you envision the compiler to tell you (examples of error messages and code patterns it should detect, examples of code patterns that it should NOT detect and are fine) incase it automagically finds problematic code? I'm having trouble putting a thumb on what you want following this thread, because what you are describing feels a bit vague to me.On Thursday, 28 July 2016 at 15:24:10 UTC, bitwise wrote:I'm not sure if this point is meant to be for or against what I'm suggesting, but still, I'm thinking in terms of *proactively* writing efficient code, not allowing an app get to the point where you need to run a profiler. The situation is similar to using safe. You *could* just write code however you want, wait until it crashes, then try to find the problem using Valgrind or something, but that's bad for obvious reasons. BitIt's not about running out of memory. It's a performance issue. Example: In the following class, it would be perfectly fine, and even expected to allocate in start() but not in update(). This is because start() gets called once on object initialization, but update() would get called every frame.Vladimir implemented counting in -profile=gc, it gives you the number of allocations and the amount allocated for each allocation point.
Jul 28 2016
On Thursday, 28 July 2016 at 16:45:05 UTC, bitwise wrote:On Thursday, 28 July 2016 at 16:15:04 UTC, Guillaume Piolat wrote:Well, here in my opinion there's the wrong attitude of profiling only when it becomes necessary (i.e. the app is slow or uses too much ram). This is wrong. You should profile before this happens; you should profile to see if the time/memory is spent in the parts of the application that should spend it and you should profile whenever you care about making good code and not just "code that works". You should profile while you add features, to see their impact on the overall performance. Profiling at the end, when you have a 100K LOC codebase deployed, because a user ran out of memory is too late: too late to allow to easily spot the problem and too late to think an alternative approach/algorithm/design, instead of just patching the problem.On Thursday, 28 July 2016 at 15:24:10 UTC, bitwise wrote:I'm not sure if this point is meant to be for or against what I'm suggesting, but still, I'm thinking in terms of *proactively* writing efficient code, not allowing an app get to the point where you need to run a profiler.It's not about running out of memory. It's a performance issue. Example: In the following class, it would be perfectly fine, and even expected to allocate in start() but not in update(). This is because start() gets called once on object initialization, but update() would get called every frame.Vladimir implemented counting in -profile=gc, it gives you the number of allocations and the amount allocated for each allocation point.
Jul 28 2016
On Thursday, 28 July 2016 at 00:23:57 UTC, bitwise wrote:While working on a past project(C++), I found this little gem: void draw() { Font* f = new Font("arial.ttf", 16); drawText(f, "hello world"); }It sounds like -vgc and --profile=gc are exactly what you want. nogc is meant to *guarantee* that the GC will not be called within a function or any other functions called by that function. Taking that guarantee away makes it effectively useless.
Jul 28 2016
On Thursday, 28 July 2016 at 18:53:35 UTC, Meta wrote:On Thursday, 28 July 2016 at 00:23:57 UTC, bitwise wrote:I understand that assumenogc may not be exactly the right approach, but the underlying idea is sound, which is to have the compiler to disallow all GC allocations in some annotated scope, just like nogc, but to allow the programmer to override the nogc restriction in certain cases. There may be alternative approaches, and the warngc idea was just one random suggestion. The point is, a mixture of nogc and assumenogc would achieve exactly what I'm looking for. The only problem is that it may cause issues for people that are using nogc under a different set of assumptions. BitWhile working on a past project(C++), I found this little gem: void draw() { Font* f = new Font("arial.ttf", 16); drawText(f, "hello world"); }It sounds like -vgc and --profile=gc are exactly what you want. nogc is meant to *guarantee* that the GC will not be called within a function or any other functions called by that function. Taking that guarantee away makes it effectively useless.
Jul 28 2016
On Thursday, 28 July 2016 at 20:32:18 UTC, bitwise wrote:On Thursday, 28 July 2016 at 18:53:35 UTC, Meta wrote:Also, assumenogc or whatever does not play well with public APIs: if a library function is marked nogc, its user can no longer know if it is really nogc or if it does allocate via assumenogc. This is not a good thing, as the user may want *absolutely* no GC allocation in his program, and may even have disabled the GC at program startup. Also, the code of that maybe-not- nogc library may not be available to check for this thing. Maybe the user doesn't want to trust the library writer, and so wants the compiler to guarantee no allocations at all.On Thursday, 28 July 2016 at 00:23:57 UTC, bitwise wrote:I understand that assumenogc may not be exactly the right approach, but the underlying idea is sound, which is to have the compiler to disallow all GC allocations in some annotated scope, just like nogc, but to allow the programmer to override the nogc restriction in certain cases. There may be alternative approaches, and the warngc idea was just one random suggestion. The point is, a mixture of nogc and assumenogc would achieve exactly what I'm looking for. The only problem is that it may cause issues for people that are using nogc under a different set of assumptions.While working on a past project(C++), I found this little gem: void draw() { Font* f = new Font("arial.ttf", 16); drawText(f, "hello world"); }It sounds like -vgc and --profile=gc are exactly what you want. nogc is meant to *guarantee* that the GC will not be called within a function or any other functions called by that function. Taking that guarantee away makes it effectively useless.
Jul 28 2016
On 07/28/2016 10:46 PM, Lodovico Giaretta wrote:Also, the code of that maybe-not- nogc library may not be available to check for this thing. Maybe the user doesn't want to trust the library writer, and so wants the compiler to guarantee no allocations at all.If you can't check the code, you have to trust the library writer. One can hack around nogc as it is. It's not like dmd checks the object file for GC allocations.
Jul 28 2016
On Thursday, 28 July 2016 at 21:07:22 UTC, ag0aep6g wrote:On 07/28/2016 10:46 PM, Lodovico Giaretta wrote:Yeah... So on one hand, currently, you could potentially have some random hack misbehaving inside nogc code with no way to detect it, whereas a simple search for assumenogc would immediately tell you if the nogc convention was being broken for any reason. On the other hand, adding assumenogc may increase the amount of instances where this is happening, cause this search to be mandatory for every package you decide to download. Maybe if there were 3 variations, this could work: // use current convention. 100% guarantee, no allocations. nogc // same as current, but restriction can be broken by nogc(off) nogc(weak) // allows allocations. Can only override nogc(weak), but not nogc. nogc(off) Example: class NPC { Cake cake; void start() { cake = new Cake(); // OK } void update() nogc(weak) { cake = new Cake(); // error: cannot allocate here nogc(off) { cake = new Cake(); // ok: alloc allowed in nogc(off) } } void draw() nogc { nogc(off) { // error: nogc(off) not legal inside nogc cake = new Cake(); } bar(); // error: nogc(weak) not callable here } void bar() nogc(weak) { } }Also, the code of that maybe-not- nogc library may not be available to check for this thing. Maybe the user doesn't want to trust the library writer, and so wants the compiler to guarantee no allocations at all.If you can't check the code, you have to trust the library writer. One can hack around nogc as it is. It's not like dmd checks the object file for GC allocations.
Jul 28 2016
On Sunday, 24 July 2016 at 22:13:02 UTC, bitwise wrote:...I like the typo in the title. Let's make a game: "write the `bypassign` function, its ddoc, and its unittests" :)
Jul 28 2016
On Thursday, 28 July 2016 at 17:54:20 UTC, jdfgjdf wrote:On Sunday, 24 July 2016 at 22:13:02 UTC, bitwise wrote:Entry one: /** * Bypassign is a struct wrapper that bypasses the original type's `opAssign()`, * thus any assignation to the wrapped type is a noop. */ struct Bypassign(T) if (is(T == struct)) { private T _bypassigned; alias _bypassigned this; void opAssign(T)(auto ref T t) {/*bypassignation*/} } /// unittest { static struct Foo { int i; alias i this; } Bypassign!Foo bpaFoo; bpaFoo = 1; assert(bpaFoo == 0); }...I like the typo in the title. Let's make a game: "write the `bypassign` function, its ddoc, and its unittests" :)
Jul 28 2016