digitalmars.D - iPhone vs Android
- Andrei Alexandrescu (22/22) Sep 12 2016 An interesting article written for laypeople:
- Rikki Cattermole (11/35) Sep 12 2016 I would interpret it quite differently to this.
- deadalnix (17/30) Sep 12 2016 I think the native part is fair, but the RC part maybe not. I
- Rikki Cattermole (17/24) Sep 12 2016 I quite agree with the hybrid approach.
- Walter Bright (4/6) Sep 13 2016 Interestingly, Warp (the C preprocessor I developed in D) used a hybrid
- Stefan Koch (3/6) Sep 13 2016 Manual Memory management is key for performance oriented code.
- Jonathan M Davis via Digitalmars-d (17/23) Sep 13 2016 Folks have posted here before about taking that approach with games and ...
- Walter Bright (7/22) Sep 13 2016 Case in point, exceptions. Currently exceptions are fairly wedded to bei...
- Jonathan M Davis via Digitalmars-d (22/29) Sep 13 2016 The big problem with exceptions being allocated by the GC isn't really t...
- deadalnix (6/8) Sep 13 2016 No the problem IS @nogc . Allocating with the GC is absolutely
- John Colvin (3/11) Sep 14 2016 Can you explain a bit more here? Do you mean in practice (I.e. in
- deadalnix (30/42) Sep 14 2016 My point is that if you have lifetime information for some data
- Lurker (8/14) Sep 13 2016 Introduce RefCountedException?
- H. S. Teoh via Digitalmars-d (22/29) Sep 13 2016 I don't see why pre-allocated exceptions would be less informative. You
- Walter Bright (3/7) Sep 13 2016 There's currently nothing that would prevent any handler code from savin...
- Andrei Alexandrescu (5/10) Sep 13 2016 Didn't we reach the agreement to closely investigate a reference counted...
- Walter Bright (3/9) Sep 13 2016 Yes we did. The design of Phobos would be better and more flexible if ex...
- Shachar Shemesh (13/18) Sep 13 2016 I will need explanation to those two. Assuming we have RAII, why doesn't...
- Laeeth Isharc (15/28) Sep 13 2016 Hi Shachar.
- Jonathan M Davis via Digitalmars-d (28/55) Sep 13 2016 As I understand it, the problem is that the length of time that the GC s...
- Laeeth Isharc (5/72) Sep 13 2016 Thanks you for the clear explanation. So if you don't have GC
- Marco Leise (26/29) Sep 13 2016
- Laeeth Isharc (38/65) Sep 13 2016 Thanks, Marco.
- jmh530 (3/4) Sep 13 2016 If you ever write a book, I would pre-order it.
- Jonathan M Davis via Digitalmars-d (6/10) Sep 13 2016 LOL. It's on my unfinished projects list, so I intend to complete it at ...
- jmh530 (3/9) Sep 13 2016 Typos are for spellcheckers.
- deadalnix (14/30) Sep 13 2016 With RC, the runtime needs to resume every frames. That makes
- Steven Schveighoffer (20/23) Sep 13 2016 Swift doesn't support exceptions AFAIK. It supports weird error handling...
- Jacob Carlborg (5/23) Sep 14 2016 Exactly and you're not supposed to catch exceptions in Objective-C. It's...
- Walter Bright (3/5) Sep 13 2016 Also, if you only use GC for exceptions, there isn't going to be much me...
- finalpatch (18/21) Sep 14 2016 This is simply not true.
- Laeeth Isharc (8/20) Sep 14 2016 Could you elaborate? I thought based on both personal experience
- Chris Wright (8/24) Sep 15 2016 You can store a pointer to a GC-owned memory block inside an RCed object...
- deadalnix (31/48) Sep 14 2016 No it has to scan the live set. If we assume we are ready to
- Walter Bright (4/9) Sep 13 2016 Memory allocated with malloc() is unknown to the GC. This works fine unl...
- Shachar Shemesh (7/10) Sep 13 2016 But if you do want to allow it, then my original problem comes back. You...
- Walter Bright (4/9) Sep 13 2016 If mallocing for types that are statically known at compile time, it sho...
- Shachar Shemesh (14/21) Sep 13 2016 I believe you are under the assumption that structs will not be GC
- Walter Bright (5/6) Sep 14 2016 It depends on how it is used. I was unclear about knowable, it is knowab...
- Laeeth Isharc (17/44) Sep 14 2016 In D code that I have read where people use RC types they have
- Shachar Shemesh (19/27) Sep 15 2016 I find the suggestion that the compiler make code generation decisions
- deadalnix (21/38) Sep 14 2016 Cool down, take a step back.
- Paulo Pinto (7/42) Sep 14 2016 As extra info, it was the approach taken by Cedar at Xerox PARC
- Joakim (9/13) Sep 12 2016 Completely agree, it's why I've been working on the Android port.
- deadalnix (4/6) Sep 12 2016 The battery industry is king to drum up various techs in very
- Kagamin (6/9) Sep 13 2016 The rule of thumb is that for efficient operation an advanced GC
- Andrei Alexandrescu (3/5) Sep 13 2016 Do you have a citation? The number I know is 3x from Emery Berger's
- Kagamin (4/6) Sep 13 2016 IIRC there was a thread about GC here where somebody posted a
- Kagamin (5/7) Sep 13 2016 http://sealedabstract.com/rants/why-mobile-web-apps-are-slow/
- Andrei Alexandrescu (16/22) Sep 13 2016 This suggests the ratio is 4x not 2x:
- Kagamin (4/6) Sep 15 2016 I didn't look into how he connects perceived application
- deadalnix (4/10) Sep 13 2016 I assume it is going to depend of the rate at which the
- Andrei Alexandrescu (4/13) Sep 13 2016 That's why Berger uses a relatively large battery of benchmark from
- Paulo Pinto (30/54) Sep 13 2016 Just some update on your information, the Android story is much
- angel (8/8) Sep 13 2016 I think the conclusions about iOS vs. Android OS-level memory
- Jonathan M Davis via Digitalmars-d (31/57) Sep 14 2016 As Walter points out, it's a problem if exceptions are ever saved (which
- H. S. Teoh via Digitalmars-d (41/87) Sep 14 2016 Honestly, I've never actually run across a real-life case where chained
- Kagamin (3/8) Sep 15 2016 See e.g.
- Jonathan M Davis via Digitalmars-d (28/35) Sep 14 2016 And how would you deal with the fact that the catching code is generally
- R (10/17) Sep 15 2016 I'm keen on reference counting because of embedded and bare-metal
An interesting article written for laypeople: http://www.theverge.com/2016/9/12/12886058/iphone-7-specs-competition One quote that may be of relevance to us: "As to the iPhone’s memory, this is more of a philosophical distinction between Apple and Google. The former is neurotic about killing background processes and dumping background apps from memory in iOS, whereas the latter is more liberal with app management in Android (though Google is gradually moving toward the Apple way of doing things). The upshot is that an iPhone can feel super smooth and responsive with half the RAM of an Android device. RAM consumes power, so having less of it is another factor contributing to the iPhone’s efficiency lead." This may be interpreted as follows: the iPhone uses native apps with reference counting whereas the Android uses a virtual machine with tracing garbage collection. It follows that the latter needs more memory for the same performance, and is more jerky in behavior than the former. Wondering to what extent this is true. If it is, that provides more impetus for reference counting for D by the following logic: (a) it is likely that in the future more code will run on portable, battery-powered systems; (b) battery power does not follow a Moore trajectory, so at this point in history demand for battery lifetime is elastic. Andrei
Sep 12 2016
On Monday, 12 September 2016 at 22:57:23 UTC, Andrei Alexandrescu wrote:An interesting article written for laypeople: http://www.theverge.com/2016/9/12/12886058/iphone-7-specs-competition One quote that may be of relevance to us: "As to the iPhone’s memory, this is more of a philosophical distinction between Apple and Google. The former is neurotic about killing background processes and dumping background apps from memory in iOS, whereas the latter is more liberal with app management in Android (though Google is gradually moving toward the Apple way of doing things). The upshot is that an iPhone can feel super smooth and responsive with half the RAM of an Android device. RAM consumes power, so having less of it is another factor contributing to the iPhone’s efficiency lead." This may be interpreted as follows: the iPhone uses native apps with reference counting whereas the Android uses a virtual machine with tracing garbage collection. It follows that the latter needs more memory for the same performance, and is more jerky in behavior than the former. Wondering to what extent this is true. If it is, that provides more impetus for reference counting for D by the following logic: (a) it is likely that in the future more code will run on portable, battery-powered systems; (b) battery power does not follow a Moore trajectory, so at this point in history demand for battery lifetime is elastic. AndreiI would interpret it quite differently to this. On iOS applications that are not currently in the foreground or are a service get killed unconditionally. On Android applications keep running even when they are no longer foreground but instead get 'paused'. Here is a handy little graph of the different events an Android app can be in[0]. Note the difference between onPause and onStop. [0] https://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
Sep 12 2016
On Monday, 12 September 2016 at 22:57:23 UTC, Andrei Alexandrescu wrote:This may be interpreted as follows: the iPhone uses native apps with reference countingI think the native part is fair, but the RC part maybe not. I know first hand that they have a fair amount of problem on the side.whereas the Android uses a virtual machine with tracing garbage collection.Dalvik's GC is truly horrible and Java is addicted to memory allocations, which makes it worse. A match made in hell.It follows that the latter needs more memory for the same performance, and is more jerky in behavior than the former.Putting a stop the world GC in a UI program is the worst idea ever. Doing this java is giving steroïd to the worse idea ever. I have no idea what Google was thnking here.Wondering to what extent this is true. If it is, that provides more impetus for reference counting for D by the following logic: (a) it is likely that in the future more code will run on portable, battery-powered systems; (b) battery power does not follow a Moore trajectory, so at this point in history demand for battery lifetime is elastic.RC itself is not panacea, it doesn't work well with exceptions, generate a huge amount of code bloat, hurt throughput, which you don't care in UI thread, but do care in the backend, and so on. But first and foremost, it is a disaster for shared data. I stay convinced that an hybrid approach is inevitable and am surprised why few are going there (hello PHP, here is a thing you get right).
Sep 12 2016
On Monday, 12 September 2016 at 23:21:12 UTC, deadalnix wrote:RC itself is not panacea, it doesn't work well with exceptions, generate a huge amount of code bloat, hurt throughput, which you don't care in UI thread, but do care in the backend, and so on. But first and foremost, it is a disaster for shared data. I stay convinced that an hybrid approach is inevitable and am surprised why few are going there (hello PHP, here is a thing you get right).I quite agree with the hybrid approach. My rule of thumb is if it is short lived its "managed" but if it can last a long time use the GC. Ok so my managed memory concept auto deallocates as any ref counting solution should do. So for short lived memory, this is perfect since it isn't being moved around much and you can afford it. But for long lived references such as a window you really want the default to be that you specifically tell it to deallocate at a set point in time you know it should. For reference, SPEW's UI creation manager[0] and screenshot feature[1]. [0] https://github.com/Devisualization/spew/blob/master/src/base/cf/spew/instance.d#L72 [1] https://github.com/Devisualization/spew/blob/master/src/base/cf/spew/ui/window/features/screenshot.d#L26
Sep 12 2016
On 9/12/2016 4:21 PM, deadalnix wrote:I stay convinced that an hybrid approach is inevitable and am surprised why few are going there (hello PHP, here is a thing you get right).Interestingly, Warp (the C preprocessor I developed in D) used a hybrid approach. The performance critical code was all hand-managed, while the rest was GC'd.
Sep 13 2016
On Tuesday, 13 September 2016 at 10:58:50 UTC, Walter Bright wrote:Interestingly, Warp (the C preprocessor I developed in D) used a hybrid approach. The performance critical code was all hand-managed, while the rest was GC'd.Manual Memory management is key for performance oriented code.
Sep 13 2016
On Tuesday, September 13, 2016 03:58:50 Walter Bright via Digitalmars-d wrote:On 9/12/2016 4:21 PM, deadalnix wrote:Folks have posted here before about taking that approach with games and the like that they've written. In a number cases, simply being careful about specific pieces of code and avoiding the GC in those cases was enough to get the required performance. In some cases, simply disabling the GC during a critical piece of code and re-enabling it afterwards fixes the performance problems trigged by the GC without even needing manual memory management or RC. In others, making sure that the critical thread (e.g. the rendering thread) was not GC-managed while letting the rest of the app us the GC takes care of the problem. We need reference counting to solve certain problems (e.g. cases where deterministic destruction of stuff on the heap is required), but other stuff (like array slices) work far better with a GC. So going either full-on RC or full-on GC is not going to be good move for most programs. I don't think that there's any question that we'll be best off by having both as solid options, and best practices can develop as to when to use one or the other. - Jonathan M DavisI stay convinced that an hybrid approach is inevitable and am surprised why few are going there (hello PHP, here is a thing you get right).Interestingly, Warp (the C preprocessor I developed in D) used a hybrid approach. The performance critical code was all hand-managed, while the rest was GC'd.
Sep 13 2016
On 9/13/2016 10:44 AM, Jonathan M Davis via Digitalmars-d wrote:Folks have posted here before about taking that approach with games and the like that they've written. In a number cases, simply being careful about specific pieces of code and avoiding the GC in those cases was enough to get the required performance. In some cases, simply disabling the GC during a critical piece of code and re-enabling it afterwards fixes the performance problems trigged by the GC without even needing manual memory management or RC. In others, making sure that the critical thread (e.g. the rendering thread) was not GC-managed while letting the rest of the app us the GC takes care of the problem. We need reference counting to solve certain problems (e.g. cases where deterministic destruction of stuff on the heap is required), but other stuff (like array slices) work far better with a GC. So going either full-on RC or full-on GC is not going to be good move for most programs. I don't think that there's any question that we'll be best off by having both as solid options, and best practices can develop as to when to use one or the other.Case in point, exceptions. Currently exceptions are fairly wedded to being GC allocated. Some people have opined that this is a major problem, and it is if the app is throwing a lot of exceptions. But exceptions should be exceptional. There is still a place for GC, even in a high performance app. The all-or-nothing approach to using the GC is as wrong as any programming methodology is.
Sep 13 2016
On Tuesday, September 13, 2016 14:43:09 Walter Bright via Digitalmars-d wrote:Case in point, exceptions. Currently exceptions are fairly wedded to being GC allocated. Some people have opined that this is a major problem, and it is if the app is throwing a lot of exceptions. But exceptions should be exceptional. There is still a place for GC, even in a high performance app. The all-or-nothing approach to using the GC is as wrong as any programming methodology is.The big problem with exceptions being allocated by the GC isn't really the GC but nogc. Obviously, a program that does not use the GC at all can't allocate an exception with the GC, but in general, I would fully expect that even a program that allows the GC but uses it minimally would have no problem with the garbage created by exceptions precisely because they should be rare. But none of the code that's marked nogc can throw an exception unless you're either dealing with pre-allocated exceptions (in which case, they're less informative), or you are _very_ careful with how you write that code so that you can get away with malloc-ing the exception (but that approach won't work in the general case unless you don't care about leaking the memory from the exception, since most code would assume that the exception was allocated by the GC and wouldn't know how to free it). So, nogc code is going to have a tendency to not use exceptions just because exceptions don't work well without the GC. And those who want to use exceptions and are willing to have their code not be nogc will forgo nogc even when the code could have been nogc otherwise. So, I really think that we need to find a way to make it so that exceptions aren't GC allocated normally anymore - or at least have a way to reasonably and easily not be GC allocated - but the problem is nogc, not the actual memory management or its cost. - Jonathan M Davis
Sep 13 2016
On Tuesday, 13 September 2016 at 22:19:54 UTC, Jonathan M Davis wrote:The big problem with exceptions being allocated by the GC isn't really the GC but nogc.No the problem IS nogc . Allocating with the GC is absolutely not a problem is you deallocate properly. What is a problem is when you leak (ie, when the ownership is transferred to the GC). If you don't leak, GC do not kicks in.
Sep 13 2016
On Tuesday, 13 September 2016 at 22:28:09 UTC, deadalnix wrote:On Tuesday, 13 September 2016 at 22:19:54 UTC, Jonathan M Davis wrote:Can you explain a bit more here? Do you mean in practice (I.e. in current implementation) or in theory?The big problem with exceptions being allocated by the GC isn't really the GC but nogc.No the problem IS nogc . Allocating with the GC is absolutely not a problem is you deallocate properly. What is a problem is when you leak (ie, when the ownership is transferred to the GC). If you don't leak, GC do not kicks in.
Sep 14 2016
On Wednesday, 14 September 2016 at 07:55:24 UTC, John Colvin wrote:On Tuesday, 13 September 2016 at 22:28:09 UTC, deadalnix wrote:My point is that if you have lifetime information for some data (and it looks like this is where we want to go with things like DIP25 and DIP1000, but let's not get lost in the specific of these proposal now) you know they are going to end up being freed without the GC having to do a collection cycle. Therefore, you know you'll not end up having to rely on the GC as long as you can track lifetime, even if you allocate with it. Now that this is established it follows that disallowing GC allocation in nogc code is needlessly restrictive and promote unsafe patterns (like allocating using malloc + giving the range to the GC, which is both slower than allocating on the GC directly and more error prone). A more sensible approach is to allow GC allocation in nogc code but disallow cases where GC's alloc lifetime cannot be tracked. Note that this isn't the case for most exceptions. For instance, when you do throw new Exception("tagada"); The compiler can deduce that the ownership of the exception is transferred to the runtime, which will transfers back to the catch block that gets it. Depending of what this catch block is doing, it may or may not be nogc, but there is no reason that for throw to not be allowed in nogc code. However, if you have something like throw e; With e a reference to an Exception who's lifetime cannot be tracked, then it makes sense to disallow it in nogc code. TL;DR : The problem is not new, the problem is the rhs of assignment operations.On Tuesday, 13 September 2016 at 22:19:54 UTC, Jonathan M Davis wrote:Can you explain a bit more here? Do you mean in practice (I.e. in current implementation) or in theory?The big problem with exceptions being allocated by the GC isn't really the GC but nogc.No the problem IS nogc . Allocating with the GC is absolutely not a problem is you deallocate properly. What is a problem is when you leak (ie, when the ownership is transferred to the GC). If you don't leak, GC do not kicks in.
Sep 14 2016
On Tuesday, 13 September 2016 at 22:19:54 UTC, Jonathan M Davis wrote:So, I really think that we need to find a way to make it so that exceptions aren't GC allocated normally anymore - or at least have a way to reasonably and easily not be GC allocated - but the problem is nogc, not the actual memory management or its cost. - Jonathan M DavisIntroduce RefCountedException? Also that the pattern almost always is "throw new" and *very* rarely it is "Exception e = new ...; throw e;". I think we might be able to take advantage of that (e.g. "throw new E" could be a special case of "new" that allocates on some sort of "Exception" heap that is manually managed, or recognize RefCountedException).
Sep 13 2016
On Tue, Sep 13, 2016 at 03:19:54PM -0700, Jonathan M Davis via Digitalmars-d wrote: [...]But none of the code that's marked nogc can throw an exception unless you're either dealing with pre-allocated exceptions (in which case, they're less informative),I don't see why pre-allocated exceptions would be less informative. You can always modify the exception object before throwing it, after all. In fact, I've always wondered about the feasibility of a nogc exception handling system where the exception is emplaced onto a fixed static buffer, so that no allocation (except at the start of the program) is actually necessary. Of course, chained exceptions throw(!) a monkey wrench into the works, but assuming we forego chained exceptions, wouldn't this work around the problem of being unable to allocate exceptions in nogc code? (Albeit with its own limitations, obviously. But it would be better than being unable to use exceptions at all in nogc code.) [...]So, I really think that we need to find a way to make it so that exceptions aren't GC allocated normally anymore - or at least have a way to reasonably and easily not be GC allocated - but the problem is nogc, not the actual memory management or its cost.[...] There's nothing about the 'throw' keyword that requires GC allocation. It's just that `throw new Exception(...)` has become a standard incantation. The exception object itself can, for example, be emplaced onto a static buffer as I propose above. T -- I think Debian's doing something wrong, `apt-get install pesticide', doesn't seem to remove the bugs on my system! -- Mike Dresser
Sep 13 2016
On 9/13/2016 4:13 PM, H. S. Teoh via Digitalmars-d wrote:There's nothing about the 'throw' keyword that requires GC allocation. It's just that `throw new Exception(...)` has become a standard incantation. The exception object itself can, for example, be emplaced onto a static buffer as I propose above.There's currently nothing that would prevent any handler code from saving a reference to the thrown exception. Statically allocating them would break that.
Sep 13 2016
On 09/13/2016 05:43 PM, Walter Bright wrote:The all-or-nothing approach to using the GC is as wrong as any programming methodology is.That's a bit much.There's currently nothing that would prevent any handler code from saving a reference to the thrown exception. Statically allocating them would break that.Didn't we reach the agreement to closely investigate a reference counted exceptions hierarchy? Andrei
Sep 13 2016
On 9/13/2016 6:09 PM, Andrei Alexandrescu wrote:On 09/13/2016 05:43 PM, Walter Bright wrote:Yes we did. The design of Phobos would be better and more flexible if exceptions didn't rely on the GC.There's currently nothing that would prevent any handler code from saving a reference to the thrown exception. Statically allocating them would break that.Didn't we reach the agreement to closely investigate a reference counted exceptions hierarchy?
Sep 13 2016
On 13/09/16 02:21, deadalnix wrote:RC itself is not panacea, it doesn't work well with exceptions, generate a huge amount of code bloat,I will need explanation to those two. Assuming we have RAII, why doesn't RC work well with exceptions? Also, please note that explicit memory management also means we support the equivalent of unique_ptr, which is what most memory allocations actually are.But first and foremost, it is a disaster for shared data.Again, please elaborate.I stay convinced that an hybrid approach is inevitable and am surprised why few are going there (hello PHP, here is a thing you get right).Here's my worries about the hybrid approach. The GC run time is proportional not to the amount of memory you manage with the GC, but to the amount of memory that might hold a pointer to a GC managed memory. In other words, if most of my memory is RC managed, but some of it is GC, I pay the price of both memory manager on most of my memory. Shachar
Sep 13 2016
On Tuesday, 13 September 2016 at 11:59:46 UTC, Shachar Shemesh wrote:On 13/09/16 02:21, deadalnix wrote:Hi Shachar. I hope you're well. Would you mind elaborating a bit on why the cost of GC managed memory is as high as you imply when combined with other approaches, at least on a 64 bit machine and presuming you have a degree of hygiene and don't directly use a pointer allowed to point to either. Eg if you use GC for long lived allocations and RC for short lived ones (and the RC constructor makes sure the thing is not registered with the GC so that takes care of short lived parts of long lived structures), how in practice would this be a problem ? I am no GC expert, but keen to update my mental model. LaeethI stay convinced that an hybrid approach is inevitable and am surprised why few are going there (hello PHP, here right).Here's my worries about the hybrid approach. The GC run time is proportional not to the amount of memory you manage with the GC, but to the amount of memory that might hold a pointer to a GC managed memory. In other words, if most of my memory is RC managed, but some of it is GC, I pay the price of both memory manager on most of my memory. Shachar
Sep 13 2016
On Tuesday, September 13, 2016 17:48:38 Laeeth Isharc via Digitalmars-d wrote:On Tuesday, 13 September 2016 at 11:59:46 UTC, Shachar Shemesh wrote:As I understand it, the problem is that the length of time that the GC scan takes - and therefore that the world is stopped - depends on how much memory it has to scan, not on how much memory has been allocated by the GC. In many cases, that's just the GC heap plus the stack, but if you're malloc-ing memory, and that memory can hold references to GC-allocated memory, then you have to tell the GC to scan that memory too in order to avoid having anything it references being prematurely collected. So, ultimately, how expensive the GC is in terms of performance generally depends on how much memory can hold referencs to GC-allocated objects and not how many such objects there are, meaning that avoiding allocating with the GC in a lot of your code doesn't necessarily save you from the performance cost of the GC. To avoid that cost, you'd need to either not have many places in malloc-ed memory which could refer to GC-allocated memory, or you'd need to write your code in a way that the it was guaranteed that the GC-allocated objects that were referenced in malloc-ed memory would have other references in memory that was scanned that lived longer htan the malloc-ed memory so that the malloc-ed memory wouldn't need to be scanned (which is quite possible in some circumstances but potentially risky). Using a 64-bit system significantly reduces the risk of false pointers, but it doesn't reduce the amount of memory that actually needs to be scanned. And whether using the GC for long-lived allocations and RC for short-lived ones would help would depend primarily on how many such objects would be around at any one time - and of course, whether they refer to GC-allocated memory and would thus need to be scanned. But reducing the amount of memory that the GC needs to scan and reduce how much is GC-allocated are two separate - albeit related - problems. - Jonathan M DavisOn 13/09/16 02:21, deadalnix wrote:Hi Shachar. I hope you're well. Would you mind elaborating a bit on why the cost of GC managed memory is as high as you imply when combined with other approaches, at least on a 64 bit machine and presuming you have a degree of hygiene and don't directly use a pointer allowed to point to either. Eg if you use GC for long lived allocations and RC for short lived ones (and the RC constructor makes sure the thing is not registered with the GC so that takes care of short lived parts of long lived structures), how in practice would this be a problem ? I am no GC expert, but keen to update my mental model.I stay convinced that an hybrid approach is inevitable and am surprised why few are going there (hello PHP, here right).Here's my worries about the hybrid approach. The GC run time is proportional not to the amount of memory you manage with the GC, but to the amount of memory that might hold a pointer to a GC managed memory. In other words, if most of my memory is RC managed, but some of it is GC, I pay the price of both memory manager on most of my memory. Shachar
Sep 13 2016
On Tuesday, 13 September 2016 at 18:04:19 UTC, Jonathan M Davis wrote:On Tuesday, September 13, 2016 17:48:38 Laeeth Isharc via Digitalmars-d wrote:Thanks you for the clear explanation. So if you don't have GC allocations within RC structures and pick one or the other, then the concern does not apply?On Tuesday, 13 September 2016 at 11:59:46 UTC, Shachar Shemesh wrote:As I understand it, the problem is that the length of time that the GC scan takes - and therefore that the world is stopped - depends on how much memory it has to scan, not on how much memory has been allocated by the GC. In many cases, that's just the GC heap plus the stack, but if you're malloc-ing memory, and that memory can hold references to GC-allocated memory, then you have to tell the GC to scan that memory too in order to avoid having anything it references being prematurely collected. So, ultimately, how expensive the GC is in terms of performance generally depends on how much memory can hold referencs to GC-allocated objects and not how many such objects there are, meaning that avoiding allocating with the GC in a lot of your code doesn't necessarily save you from the performance cost of the GC. To avoid that cost, you'd need to either not have many places in malloc-ed memory which could refer to GC-allocated memory, or you'd need to write your code in a way that the it was guaranteed that the GC-allocated objects that were referenced in malloc-ed memory would have other references in memory that was scanned that lived longer htan the malloc-ed memory so that the malloc-ed memory wouldn't need to be scanned (which is quite possible in some circumstances but potentially risky). Using a 64-bit system significantly reduces the risk of false pointers, but it doesn't reduce the amount of memory that actually needs to be scanned. And whether using the GC for long-lived allocations and RC for short-lived ones would help would depend primarily on how many such objects would be around at any one time - and of course, whether they refer to GC-allocated memory and would thus need to be scanned. But reducing the amount of memory that the GC needs to scan and reduce how much is GC-allocated are two separate - albeit related - problems. - Jonathan M DavisOn 13/09/16 02:21, deadalnix wrote:Hi Shachar. I hope you're well. Would you mind elaborating a bit on why the cost of GC managed memory is as high as you imply when combined with other approaches, at least on a 64 bit machine and presuming you have a degree of hygiene and don't directly use a pointer allowed to point to either. Eg if you use GC for long lived allocations and RC for short lived ones (and the RC constructor makes sure the thing is not registered with the GC so that takes care of short lived parts of long lived structures), how in practice would this be a problem ? I am no GC expert, but keen to update my mental model.I stay convinced that an hybrid approach is inevitable and am surprised why few are going there (hello PHP, here right).Here's my worries about the hybrid approach. The GC run time is proportional not to the amount of memory you manage with the GC, but to the amount of memory that might hold a pointer to a GC managed memory. In other words, if most of my memory is RC managed, but some of it is GC, I pay the price of both memory manager on most of my memory. Shachar
Sep 13 2016
Am Tue, 13 Sep 2016 18:16:27 +0000 schrieb Laeeth Isharc <laeethnospam nospamlaeeth.com>:Thanks you for the clear explanation. So if you don't have GC allocations within RC structures and pick one or the other, then the concern does not apply?That's right. Often such structures contain collections of things, not just plain fields. And a list or a hash map working in a nogc environment typically checks its contained type for any pointers with hasIndirections!T and if so adds its storage area to the GC scanned memory to be on the safe side. That means every collection needs a way to exempt its contents from GC scanning and the user needs to remember to tell it so. A practical example of that are the EMSI containers, but other containers, i.e. in my own private code look similar. https://github.com/economicmodeling/containers struct DynamicArray(T, Allocator = Mallocator, bool supportGC = shouldAddGCRange!T) { ... } Here, when you use a dynamic array you need to specify the type and allocator before you get to the point of opting out of GC scanning. Many will prefer concise code, go with GC scanning to be "better safe than sorry" or don't want to fiddle with the options as long as the program works. This is no complaint, I'm just trying to draw a picture of how people end up with more GC scanned memory than necessary. :) -- Marco
Sep 13 2016
On Tuesday, 13 September 2016 at 19:30:16 UTC, Marco Leise wrote:Am Tue, 13 Sep 2016 18:16:27 +0000 schrieb Laeeth Isharc <laeethnospam nospamlaeeth.com>:Thanks, Marco. So to a certain extent it's a problem of perception and of cognitive load when one is coming to the language - none of the steps taken together is necessarily difficult, but cumulatively it's a lot to take in or figure out yourself - then, as you say people do what's easy or manageable, and then those habits come to constitute ones sense of what's implied by the language and implementation when that's not necessarily right. There's a great blog post to be written on getting along with and without the GC for fun and profit - showing how to do the things you discussed,comparing the amount of GC D generates with eg Java to make vivid and concrete just how the situation is different, illustrating how one can use the allocator for significant allocations alongside the GC for trivial ones, illustrating how to pre allocate buffers, and finally demonstrating how in practice to use the GC profiling instrumentation we have. Or perhaps rather a series of blog posts. It would be helpful there to get across how the situation has improved. Because the topic is almost guaranteed to come up in social media discussions (which matter as when people Google for it that is often what they will find), and we live in an age where the complexity means people use heuristic thinking, and you can hardly blame them when there is no one place to point them too (as we have for ranges, slices etc). I would write it myself if I had time and understood better not just garbage collection techniques, but also how other languages are in practice. But it's not something for me at this point, and so someone else will have to do so. I will see when it is a bit quieter in a year or two if someone that works with me wants to do it, but in the meantime it's a great opportunity to improve the messaging. The wiki could also be a bit clearer last I looked on low-GC solutions. Eg you won't easily find EMSI containers from a casual browse. Walter has mentioned the value as a technology professional from blogging and having a personal page and I think that is right. LaeethThanks you for the clear explanation. So if you don't have GC allocations within RC structures and pick one or the other, then the concern does not apply?That's right. Often such structures contain collections of things, not just plain fields. And a list or a hash map working in a nogc environment typically checks its contained type for any pointers with hasIndirections!T and if so adds its storage area to the GC scanned memory to be on the safe side. That means every collection needs a way to exempt its contents from GC scanning and the user needs to remember to tell it so. A practical example of that are the EMSI containers, but other containers, i.e. in my own private code look similar. https://github.com/economicmodeling/containers struct DynamicArray(T, Allocator = Mallocator, bool supportGC = shouldAddGCRange!T)a certain { ... } Here, when you use a dynamic array you need to specify the type and allocator before you get to the point of opting out of GC scanning. Many will prefer concise code, go with GC scanning to be "better safe than sorry" or don't want to fiddle with the options as long as the program works. This is no complaint, I'm just trying to draw a picture of how people end up with more GC scanned memory than necessary. :)
Sep 13 2016
On Tuesday, 13 September 2016 at 18:04:19 UTC, Jonathan M Davis wrote:As I understand it, [snnip]If you ever write a book, I would pre-order it.
Sep 13 2016
On Tuesday, September 13, 2016 18:50:20 jmh530 via Digitalmars-d wrote:On Tuesday, 13 September 2016 at 18:04:19 UTC, Jonathan M Davis wrote:LOL. It's on my unfinished projects list, so I intend to complete it at some point, but unfortunately, it's been on the backburner for a while. Still, it's funny that you say that considering how many typos were in that post, since I neglected to reread it before sending it. :) - Jonathan M DavisAs I understand it, [snnip]If you ever write a book, I would pre-order it.
Sep 13 2016
On Tuesday, 13 September 2016 at 20:19:40 UTC, Jonathan M Davis wrote:LOL. It's on my unfinished projects list, so I intend to complete it at some point, but unfortunately, it's been on the backburner for a while. Still, it's funny that you say that considering how many typos were in that post, since I neglected to reread it before sending it. :) - Jonathan M DavisTypos are for spellcheckers.
Sep 13 2016
On Tuesday, 13 September 2016 at 11:59:46 UTC, Shachar Shemesh wrote:On 13/09/16 02:21, deadalnix wrote:With RC, the runtime needs to resume every frames. That makes exception very slow. Plus you need to generate a bunch of unwinding code + LSDA infos, and it clusters like crazy when you have destructor that can throw. This is why ObjC exeption handling and ARC never worked well together. This is why C++ exception are dog slow and this is why Swift is nothrow by default.RC itself is not panacea, it doesn't work well with exceptions, generate a huge amount of code bloat,I will need explanation to those two. Assuming we have RAII, why doesn't RC work well with exceptions?For shared data, you need synchronized reference counting, which is prohibitively expensive.But first and foremost, it is a disaster for shared data.Again, please elaborate.Here's my worries about the hybrid approach. The GC run time is proportional not to the amount of memory you manage with the GC, but to the amount of memory that might hold a pointer to a GC managed memory. In other words, if most of my memory is RC managed, but some of it is GC, I pay the price of both memory manager on most of my memory. ShacharNo you don't, as how often the GC kicks in depend of the rate at which you produce garbage, which is going to be very low with an hybrid approach.
Sep 13 2016
On 9/13/16 2:24 PM, deadalnix wrote:This is why ObjC exeption handling and ARC never worked well together. This is why C++ exception are dog slow and this is why Swift is nothrow by default.Swift doesn't support exceptions AFAIK. It supports weird error handling that looks similar to exceptions, but is really just a standard return. i.e. this: do { try someFunctionThatErrors(arg) } catch(Exception ex) { // handle ex } really compiles like this: var _err : Error? someFunctionThatErrors(arg, &_err) if(_err != nil) { let ex = _err!.exception } -Steve
Sep 13 2016
On 2016-09-13 20:40, Steven Schveighoffer wrote:Swift doesn't support exceptions AFAIK. It supports weird error handling that looks similar to exceptions, but is really just a standard return. i.e. this: do { try someFunctionThatErrors(arg) } catch(Exception ex) { // handle ex } really compiles like this: var _err : Error? someFunctionThatErrors(arg, &_err) if(_err != nil) { let ex = _err!.exception }Exactly and you're not supposed to catch exceptions in Objective-C. It's more like Errors in D. -- /Jacob Carlborg
Sep 14 2016
On 9/13/2016 11:24 AM, deadalnix wrote:No you don't, as how often the GC kicks in depend of the rate at which you produce garbage, which is going to be very low with an hybrid approach.Also, if you only use GC for exceptions, there isn't going to be much memory it needs to scan.
Sep 13 2016
On Tuesday, 13 September 2016 at 18:24:26 UTC, deadalnix wrote:No you don't, as how often the GC kicks in depend of the rate at which you produce garbage, which is going to be very low with an hybrid approach.This is simply not true. Assume in a pure GC program the GC heap can grow up to X Mb before a collection cycle happens, which has to scan X Mb of memory. Now let's say we have a hybrid program that uses 0.5X Mb of RCed memory and 0.5X Mb of GC memory so the total memory consumption is still X Mb. When the GC heap reaches 0.5X Mb, it has to scan both RC and GC memory. It's quite obvious that the time(t) it takes for program 1 to produce X Mb of garbage is the same as program 2 to produce 0.5X Mb of garbage, and after time t, both program have to scan X Mb of memory. However program 2 also has to pay the cost of reference counting on top of that. When you say hybrid program should trigger GC at a lower rate, you are actually assuming the hybrid program also has X Mb of GC heap, which makes total memory consumption 1.5X Mb, therefore it is not a fair comparison anymore.
Sep 14 2016
On Wednesday, 14 September 2016 at 13:28:45 UTC, finalpatch wrote:On Tuesday, 13 September 2016 at 18:24:26 UTC, deadalnix wrote:Could you elaborate? I thought based on both personal experience and the papers referred to that it's uncontroversial a GC program to run efficiently will need a multiple of actually used memory as available memory. Thus the hybrid program should require less total memory than the pure GC program, meaning at the same total memory consumption there is less GC pressure, which I understood to be part of deadalnix point.No you don't, as how often the GC kicks in depend of the rate at which you produce garbage, which is going to be very low with an hybrid approach.This is simply not true. Assume in a pure GC program the GC heap can grow up to X Mb before a collection cycle happens, which has to scan X Mb of memory. Now let's say we have a hybrid program that uses 0.5X Mb of RCed memory and 0.5X Mb of GC memory so the total memory consumption is still X Mb. When the GC heap reaches 0.5X Mb, it has to scan both RC and GC memory.
Sep 14 2016
On Wed, 14 Sep 2016 13:37:03 +0000, Laeeth Isharc wrote:On Wednesday, 14 September 2016 at 13:28:45 UTC, finalpatch wrote:You can store a pointer to a GC-owned memory block inside an RCed object, just like how you can store a pointer to a GC-owned memory block on the stack. There are three ways to handle this: * Keep a pointer to the GCed object inside GCed memory. * Tell the GC to pin the object, preventing it from being collected. * Have the GC scan RCed memory as well as GC-owned memory.On Tuesday, 13 September 2016 at 18:24:26 UTC, deadalnix wrote:Could you elaborate?No you don't, as how often the GC kicks in depend of the rate at which you produce garbage, which is going to be very low with an hybrid approach.This is simply not true. Assume in a pure GC program the GC heap can grow up to X Mb before a collection cycle happens, which has to scan X Mb of memory. Now let's say we have a hybrid program that uses 0.5X Mb of RCed memory and 0.5X Mb of GC memory so the total memory consumption is still X Mb. When the GC heap reaches 0.5X Mb, it has to scan both RC and GC memory.
Sep 15 2016
On Wednesday, 14 September 2016 at 13:28:45 UTC, finalpatch wrote:On Tuesday, 13 September 2016 at 18:24:26 UTC, deadalnix wrote:No it has to scan the live set. If we assume we are ready to accept a 2X overhead in the GC heap in that program, the collection cycle needs to scan X/2 Mb of memory. We are for a bad start here.No you don't, as how often the GC kicks in depend of the rate at which you produce garbage, which is going to be very low with an hybrid approach.This is simply not true. Assume in a pure GC program the GC heap can grow up to X Mb before a collection cycle happens, which has to scan X Mb of memory.Now let's say we have a hybrid program that uses 0.5X Mb of RCed memory and 0.5X Mb of GC memory so the total memory consumption is still X Mb. When the GC heap reaches 0.5X Mb, it has to scan both RC and GC memory.Your assumption that there are 2 heap is bogus, your 2 programs have different live sets (A has 500kb and B 750ko of live sets). In addition, why the fuck is your RC system only able to reclaim 50% of the garbage emitted ? Even with such stupids humber, you end up with program A able to manage 500kb with 100% overhead, and program B able to manage 750ko with 33% overhead, which completely proves my point: the hybrid approach is far superior. Now let's get an appropriate model of how thing work in the real world. Let's assume we have a program that emit 1Mb of garbage per second, has a live set of 1Mb and we assume we can accept a 2X memory overhead for the GC. With the pure GC approach, we emit 1Mb of garbage per second on top of our live set of 1Mb, so we need one collection cycle per second. This collection cycle has to scan the living set, namely 1Mb of data. With the hybrid approach, we still emit 1Mb of garbage per second, but the RC system can reclaim 90% of it. We end up with a rate of garbage for the GC to collect of 100ko per second. If we allow the same memory overhead, we end up with a collection cycle every 10s. The live set still has the same size, so the GC still has to scan 1Mb of data. Therefore, we effectively divided by 10 the resource we needed to allocate to the GC.It's quite obvious that the time(t) it takes for program 1 to produce X Mb of garbage is the same as program 2 to produce 0.5X Mb of garbage, and after time t, both program have to scan X Mb of memory. However program 2 also has to pay the cost of reference counting on top of that.Rule of thumb, when someone start by "it's obvious that" you can be sure that 99% of the time, what follows is confirmation bias rather than anything cogent. I think we've established this is the case here.
Sep 14 2016
On 9/13/2016 4:59 AM, Shachar Shemesh wrote:Here's my worries about the hybrid approach. The GC run time is proportional not to the amount of memory you manage with the GC, but to the amount of memory that might hold a pointer to a GC managed memory. In other words, if most of my memory is RC managed, but some of it is GC, I pay the price of both memory manager on most of my memory.Memory allocated with malloc() is unknown to the GC. This works fine unless a reference to the GC memory is inserted into malloc'd data, which is why there's an API to the GC to let it know about such things.
Sep 13 2016
On 14/09/16 02:59, Walter Bright wrote:Memory allocated with malloc() is unknown to the GC. This works fine unless a reference to the GC memory is inserted into malloc'd data, which is why there's an API to the GC to let it know about such things.But if you do want to allow it, then my original problem comes back. You have to scan the malloced memory because you are not sure where that memory might contain pointers to GC managed memory. And the hybrid hybrid approach (i.e. - only some of the memory allocated by malloc is scanned) is a wasp nest of potential bugs and problems. Shachar
Sep 13 2016
On 9/13/2016 10:38 PM, Shachar Shemesh wrote:But if you do want to allow it, then my original problem comes back. You have to scan the malloced memory because you are not sure where that memory might contain pointers to GC managed memory.If mallocing for types that are statically known at compile time, it should be knowable if they need scanning or not.And the hybrid hybrid approach (i.e. - only some of the memory allocated by malloc is scanned) is a wasp nest of potential bugs and problems.True. Manual memory allocation is that way. Hopefully RC will be better.
Sep 13 2016
On 14/09/16 09:05, Walter Bright wrote:On 9/13/2016 10:38 PM, Shachar Shemesh wrote:I believe you are under the assumption that structs will not be GC allocated. I don't think it is a good assumption to make. Even if it is, however: struct SomeStruct { string something; } Please let me know if scanning this struct for GC pointers is necessary or not. Also, even if this is knowable, I'm not sure how you are suggesting we mange it. The only practical approach I see is that if any RC managed memory might contain pointers to GC managed memory, then all RC managed memory needs to be scanned (unless you think the compiler can help out with that). ShacharBut if you do want to allow it, then my original problem comes back. You have to scan the malloced memory because you are not sure where that memory might contain pointers to GC managed memory.If mallocing for types that are statically known at compile time, it should be knowable if they need scanning or not.
Sep 13 2016
On 9/13/2016 11:33 PM, Shachar Shemesh wrote:Please let me know if scanning this struct for GC pointers is necessary or not.It depends on how it is used. I was unclear about knowable, it is knowable if you segregate types based on whether they could be gc'd or not. I.e. it is a good program design idea to use different types for different allocation methods - don't mix them.
Sep 14 2016
On Wednesday, 14 September 2016 at 06:33:59 UTC, Shachar Shemesh wrote:On 14/09/16 09:05, Walter Bright wrote:In D code that I have read where people use RC types they have different names making it quite clear - eg RCString.but If you're worrying about GC presumably you have a decent size problem anyway (and I admire the ambition of weka in this respect). So then seems to me that yes, there is a tax in writing code that uses the language in a way that a minority of D users are using it in. The generation after the pioneers, if they avoid the arrows of the prior generation, at least have a lot more hard work than subsequent generations. But on the other hand it is a package deal, and initial costs amortise. How would you end up with a GC allocated struct by mistake (presuming you think it through first) at the size you are at? 200k lines and 30 people is a lot, but it's also not Windows scale. And if you did, and it mattered, wouldn't you pick it up quickly with GC profiling?On 9/13/2016 10:38 PM, Shachar Shemesh wrote:I believe you are under the assumption that structs will not be GC allocated. I don't think it is a good assumption to make. Even if it is, however: struct SomeStruct { string something; } Please let me know if scanning this struct for GC pointers is necessary or not. Also, even if this is knowable, I'm not sure how you are suggesting we mange it. The only practical approach I see is that if any RC managed memory might contain pointers to GC managed memory, then all RC managed memory needs to be scanned (unless you think the compiler can help out with that). ShacharBut if you do want to allow it, then my original problem comes back. You have to scan the malloced memory because you are not sure where that memory might contain pointers to GC managed memory.If mallocing for types that are statically known at compile time, it should be knowable if they need scanning or not.
Sep 14 2016
On 14/09/16 16:49, Laeeth Isharc wrote:In D code that I have read where people use RC types they have different names making it quite clear - eg RCString.butI find the suggestion that the compiler make code generation decisions based on type names not one I would gladly see happen.If you're worrying about GC presumably you have a decent size problem anyway (and I admire the ambition of weka in this respect).Not everything a Weka employee says on this forum is about what Weka is doing.How would you end up with a GC allocated struct by mistake (presuming you think it through first) at the size you are at? 200k lines and 30 people is a lot, but it's also not Windows scale. And if you did, and it mattered, wouldn't you pick it up quickly with GC profiling?We didn't end up with a struct that was allocated by mistake. In fact, I do not consider what we're doing to be a hybrid approach. More of a "use GC only when the language leaves us no other choice" approach, which is far from being the same. With the hybrid approach, getting there is far from difficult. struct SomeRCNonGCDataStructure { } ... class SomethingUseful { private SomeRCNonGCDataStructure dataStructure; } Unless you suggest that people implement each algorithm twice, having structs on the heap may be hard to avoid. Shachar
Sep 15 2016
On Wednesday, 14 September 2016 at 05:38:38 UTC, Shachar Shemesh wrote:On 14/09/16 02:59, Walter Bright wrote:Cool down, take a step back. There are memory management technique that can give you good result in most case, but will degenerate is few others. For instance RC doesn't handle cycles, plays poorly with exceptions, and so on. There are ways to make RC work in all these case, but it is has severe drawbacks. Now, if you allocate using a GC, and use RC on top of it, you get 99% of the garbage cleaned up as you expect. But it allows the RC system to just delegate to the GC for cases it is not good at. That way you get very occasional collection cycles to the point where it is usually not a problem, and if you are smart about it, you can even trigger them yourself at appropriate time. If 99% of the garbage is cleanup up by the RC mechanism, the the garbage accumulate at 1% the rate of what it would with a 100% GC system, and, consequently, you can run collection 1/100 time what you would with a pure GC system with the same memory overhead. Now you may ask, how am I so sure that this is working great ? The short answer is PHP.Memory allocated with malloc() is unknown to the GC. This works fine unless a reference to the GC memory is inserted into malloc'd data, which is why there's an API to the GC to let it know about such things.But if you do want to allow it, then my original problem comes back. You have to scan the malloced memory because you are not sure where that memory might contain pointers to GC managed memory. And the hybrid hybrid approach (i.e. - only some of the memory allocated by malloc is scanned) is a wasp nest of potential bugs and problems. Shachar
Sep 14 2016
On Wednesday, 14 September 2016 at 07:16:04 UTC, deadalnix wrote:On Wednesday, 14 September 2016 at 05:38:38 UTC, Shachar Shemesh wrote:As extra info, it was the approach taken by Cedar at Xerox PARC as well. RC for almost everything, with a local tracing GC for collecting cycles. https://archive.org/details/bitsavers_xeroxparcteCedarProgrammingEnvironmentAMidtermRepo_13518000 https://archive.org/details/bitsavers_xeroxparctddingGarbageCollectionandRuntimeTypestoa_1765837On 14/09/16 02:59, Walter Bright wrote:Cool down, take a step back. There are memory management technique that can give you good result in most case, but will degenerate is few others. For instance RC doesn't handle cycles, plays poorly with exceptions, and so on. There are ways to make RC work in all these case, but it is has severe drawbacks. Now, if you allocate using a GC, and use RC on top of it, you get 99% of the garbage cleaned up as you expect. But it allows the RC system to just delegate to the GC for cases it is not good at. That way you get very occasional collection cycles to the point where it is usually not a problem, and if you are smart about it, you can even trigger them yourself at appropriate time. If 99% of the garbage is cleanup up by the RC mechanism, the the garbage accumulate at 1% the rate of what it would with a 100% GC system, and, consequently, you can run collection 1/100 time what you would with a pure GC system with the same memory overhead. Now you may ask, how am I so sure that this is working great ? The short answer is PHP.[...]But if you do want to allow it, then my original problem comes back. You have to scan the malloced memory because you are not sure where that memory might contain pointers to GC managed memory. And the hybrid hybrid approach (i.e. - only some of the memory allocated by malloc is scanned) is a wasp nest of potential bugs and problems. Shachar
Sep 14 2016
On Monday, 12 September 2016 at 22:57:23 UTC, Andrei Alexandrescu wrote:(a) it is likely that in the future more code will run on portable, battery-powered systems;Completely agree, it's why I've been working on the Android port.(b) battery power does not follow a Moore trajectory, so at this point in history demand for battery lifetime is elastic.Not Moore, but you never know what is around the bend: https://www.engadget.com/2016/08/19/smartphone-batteries-with-twice-the-life-may-arrive-in-2017/ https://www.engadget.com/2016/04/22/accidental-discovery-batteries-last-years-longer/ But yes, Moore's law is hitting fundamental limits and batteries will never match that growth curve, so efficiency will be at a premium in the coming years.
Sep 12 2016
On Tuesday, 13 September 2016 at 01:04:06 UTC, Joakim wrote:https://www.engadget.com/2016/08/19/smartphone-batteries-with-twice-the-life-may-arrive-in-2017/ https://www.engadget.com/2016/04/22/accidental-discovery-batteries-last-years-longer/The battery industry is king to drum up various techs in very misleading ways. What you want is higher power density, and this is specifically the metric that hasn't been improving that much.
Sep 12 2016
On Monday, 12 September 2016 at 22:57:23 UTC, Andrei Alexandrescu wrote:It follows that the latter needs more memory for the same performance, and is more jerky in behavior than the former. Wondering to what extent this is true.The rule of thumb is that for efficient operation an advanced GC consumes twice the used memory. Also without card marking D GC scans entire heap every collection, which adds to energy consumption. I'm leaning towards arena allocator.
Sep 13 2016
On 9/13/16 3:53 AM, Kagamin wrote:The rule of thumb is that for efficient operation an advanced GC consumes twice the used memory.Do you have a citation? The number I know is 3x from Emery Berger's (old) work. -- Andrei
Sep 13 2016
On Tuesday, 13 September 2016 at 10:04:43 UTC, Andrei Alexandrescu wrote:Do you have a citation? The number I know is 3x from Emery Berger's (old) work. -- AndreiIIRC there was a thread about GC here where somebody posted a bunch of links to resources and benchmarks.
Sep 13 2016
On Tuesday, 13 September 2016 at 10:04:43 UTC, Andrei Alexandrescu wrote:Do you have a citation? The number I know is 3x from Emery Berger's (old) work. -- Andreihttp://sealedabstract.com/rants/why-mobile-web-apps-are-slow/ http://www-cs.canisius.edu/~hertzm/gcmalloc-oopsla-2005.pdf Probably these.
Sep 13 2016
On 9/13/16 11:58 AM, Kagamin wrote:On Tuesday, 13 September 2016 at 10:04:43 UTC, Andrei Alexandrescu wrote:This suggests the ratio is 4x not 2x: ==== What this chart says is “As long as you have about 6 times as much memory as you really need, you’re fine. But woe betide you if you have less than 4x the required memory.” ====Do you have a citation? The number I know is 3x from Emery Berger's (old) work. -- Andreihttp://sealedabstract.com/rants/why-mobile-web-apps-are-slow/http://www-cs.canisius.edu/~hertzm/gcmalloc-oopsla-2005.pdf Probably these.This is Berger's paper I was referring to. It concludes the ratio is 3x not 2x: ==== With only three times as much memory, the collector runs on average 17% slower than explicit memory management. However, with only twice as much memory, garbage collection degrades performance by nearly 70%. ==== So do you agree you were wrong in positing 2x as the rule of thumb? Andrei
Sep 13 2016
On Tuesday, 13 September 2016 at 17:59:52 UTC, Andrei Alexandrescu wrote:So do you agree you were wrong in positing 2x as the rule of thumb?I didn't look into how he connects perceived application performance with collection frequency.
Sep 15 2016
On Tuesday, 13 September 2016 at 10:04:43 UTC, Andrei Alexandrescu wrote:On 9/13/16 3:53 AM, Kagamin wrote:I assume it is going to depend of the rate at which the application produces garbage.The rule of thumb is that for efficient operation an advanced GC consumes twice the used memory.Do you have a citation? The number I know is 3x from Emery Berger's (old) work. -- Andrei
Sep 13 2016
On 9/13/16 1:51 PM, deadalnix wrote:On Tuesday, 13 September 2016 at 10:04:43 UTC, Andrei Alexandrescu wrote:That's why Berger uses a relatively large battery of benchmark from multiple domains. See http://www-cs.canisius.edu/~hertzm/gcmalloc-oopsla-2005.pdf. -- AndreiOn 9/13/16 3:53 AM, Kagamin wrote:I assume it is going to depend of the rate at which the application produces garbage.The rule of thumb is that for efficient operation an advanced GC consumes twice the used memory.Do you have a citation? The number I know is 3x from Emery Berger's (old) work. -- Andrei
Sep 13 2016
On Monday, 12 September 2016 at 22:57:23 UTC, Andrei Alexandrescu wrote:An interesting article written for laypeople: http://www.theverge.com/2016/9/12/12886058/iphone-7-specs-competition One quote that may be of relevance to us: "As to the iPhone’s memory, this is more of a philosophical distinction between Apple and Google. The former is neurotic about killing background processes and dumping background apps from memory in iOS, whereas the latter is more liberal with app management in Android (though Google is gradually moving toward the Apple way of doing things). The upshot is that an iPhone can feel super smooth and responsive with half the RAM of an Android device. RAM consumes power, so having less of it is another factor contributing to the iPhone’s efficiency lead." This may be interpreted as follows: the iPhone uses native apps with reference counting whereas the Android uses a virtual machine with tracing garbage collection. It follows that the latter needs more memory for the same performance, and is more jerky in behavior than the former. Wondering to what extent this is true. If it is, that provides more impetus for reference counting for D by the following logic: (a) it is likely that in the future more code will run on portable, battery-powered systems; (b) battery power does not follow a Moore trajectory, so at this point in history demand for battery lifetime is elastic. AndreiJust some update on your information, the Android story is much more complicated than having VM. They had a VM up to version 5.0, afterwards Java bytecode (actually Dex) is compiled to native code at installation time, then there is just the language runtime, just like D. Now with Android 7, due to the big compilation times, specially when large applications need to be updated, they have an hybrid design. An interpreter written in Assembly that makes use of a JIT for hot code, then the JIT makes use of PGO and when the device is plugged and charging, the hot code will be AOT compiled to native code and never JITed or interpreted again until a new update takes place. Likewise the GC algorithm in Dalvik is pretty lame, even some J2ME JVMs do better than it. However that was changed in ART, updated in Android 6.0 and changed again in Android 7.0. So it is not easy just to say Android works like X, because X depends on the Android version and OEM build, as some of them do also change the AOSP runtime and compilers behaviors. Also for additional comparison, the Windows Phone also has a mix of RC (WinRT now renamed as UWP) and GC (.NET Native / Chackra JavaScript VM), yet the devices perform much better than similar Android devices. Also Microsoft does a full AOT build to native code on the WP Store, instead of using the consumer devices for AOT compilation like Google does. So it is not that easy to generalize the OS behaviors like the article does.
Sep 13 2016
I think the conclusions about iOS vs. Android OS-level memory collection are not applicable to D GC discussion. An OS collects all the memory pages allocated for a process upon exit - no heap scan, no RC. It more resembles a one huge free() call. The discussion is mainly about eager vs. less-eager not-currently-running process killing strategy. D's GC lies in a different plane ...
Sep 13 2016
On Tuesday, September 13, 2016 16:13:05 H. S. Teoh via Digitalmars-d wrote:On Tue, Sep 13, 2016 at 03:19:54PM -0700, Jonathan M Davis via Digitalmars-d wrote: [...]As Walter points out, it's a problem if exceptions are ever saved (which some code does need to do). The fact that you lose chaining as you pointed out is also a problem. You also have problems because the file, line, and message of the exception either aren't going to be specific to when that exception is thrown, or you have to set them all before throwing, in which case you have issues with if/when the exception is reused. And regardless of all of that, the fact that string is used for the message throws a wrench in things for nogc, since that's going to require GC allocation unless you cast something to string, and then you have serious problems if you need to mutate it later, since you'll end up violating the compiler guarantees for immutable.But none of the code that's marked nogc can throw an exception unless you're either dealing with pre-allocated exceptions (in which case, they're less informative),I don't see why pre-allocated exceptions would be less informative. You can always modify the exception object before throwing it, after all. In fact, I've always wondered about the feasibility of a nogc exception handling system where the exception is emplaced onto a fixed static buffer, so that no allocation (except at the start of the program) is actually necessary. Of course, chained exceptions throw(!) a monkey wrench into the works, but assuming we forego chained exceptions, wouldn't this work around the problem of being unable to allocate exceptions in nogc code? (Albeit with its own limitations, obviously. But it would be better than being unable to use exceptions at all in nogc code.)[...]Yes, there are ways to work around allocating an exception with new right before throwing it, but that's really how things are designed to work, and there are serious problems with any attempt to work around it. At minimum, it makes throwing exceptions to be a lot more of a pain then it is when using the GC (meaning that plenty of folks will just happily use the GC when they wouldn't need it aside from the exception, which then renders their code unable to be nogc), and really, that's enough to be a serious problem. But the fact that the workarounds either require that you don't have unique, independent exceptions or that you know that you need to manually free the exception after catching it is a serious problem. And that's without even taking the exception chaining into account. At this point, I'd say that exceptions can be used in nogc in rare circumstances where you're very careful about what you're doing, but in the general case, it's really not an option. Realistically, if we want folks to be using exceptions in nogc in general, I think that it needs to be about as simple as throw new Exception(message); is, and we're not even close to that. Without that, we're likely to end up with a divide between code that uses the GC and code that uses exceptions. - Jonathan M DavisSo, I really think that we need to find a way to make it so that exceptions aren't GC allocated normally anymore - or at least have a way to reasonably and easily not be GC allocated - but the problem is nogc, not the actual memory management or its cost.[...] There's nothing about the 'throw' keyword that requires GC allocation. It's just that `throw new Exception(...)` has become a standard incantation. The exception object itself can, for example, be emplaced onto a static buffer as I propose above.
Sep 14 2016
On Wed, Sep 14, 2016 at 05:19:45AM -0700, Jonathan M Davis via Digitalmars-d wrote:On Tuesday, September 13, 2016 16:13:05 H. S. Teoh via Digitalmars-d wrote:Honestly, I've never actually run across a real-life case where chained exceptions matter. Most of the code (that I work with, anyway) involve simply throwing an exception when some problem occurs, and the catch block simply prints the error message and aborts the current operation. I agree that chained exceptions are theoretically cool and everything, but I haven't actually found myself needing them.On Tue, Sep 13, 2016 at 03:19:54PM -0700, Jonathan M Davis via Digitalmars-d wrote: [...]As Walter points out, it's a problem if exceptions are ever saved (which some code does need to do). The fact that you lose chaining as you pointed out is also a problem.But none of the code that's marked nogc can throw an exception unless you're either dealing with pre-allocated exceptions (in which case, they're less informative),I don't see why pre-allocated exceptions would be less informative. You can always modify the exception object before throwing it, after all. In fact, I've always wondered about the feasibility of a nogc exception handling system where the exception is emplaced onto a fixed static buffer, so that no allocation (except at the start of the program) is actually necessary. Of course, chained exceptions throw(!) a monkey wrench into the works, but assuming we forego chained exceptions, wouldn't this work around the problem of being unable to allocate exceptions in nogc code? (Albeit with its own limitations, obviously. But it would be better than being unable to use exceptions at all in nogc code.)You also have problems because the file, line, and message of the exception either aren't going to be specific to when that exception is thrown, or you have to set them all before throwing, in which case you have issues with if/when the exception is reused.Clearly, if a static buffer is to be used for emplacing the exception, you'll have to sacrifice some things. But I'm just saying that the limitations aren't as onerous as it may seem at first, and in fact covers a lot of common use cases.And regardless of all of that, the fact that string is used for the message throws a wrench in things for nogc, since that's going to require GC allocation unless you cast something to string, and then you have serious problems if you need to mutate it later, since you'll end up violating the compiler guarantees for immutable.Most uses of exceptions in code that I've seen involve setting a static string as the message. This does not require GC allocation. Granted, it's also relatively common to make the exception message more verbose / informative, e.g. using format() to embed specific details about the problem besides the static message string. My own code uses this idiom quite often. This would have to be sacrificed, or some other workaround found, of course. [...]I disagree. There is nothing about 'throw' that requires the use of 'new'. A further development of the emplacement idea is to pre-initialize a region allocator specifically for throwing exceptions, then you can write: throw makeException("Error occurred", ...); where makeException is a global function that allocates the exception using the region allocator (which is initialized at startup). The catch block then deallocates the region and re-initializes it. This is not that much more painful than writing: throw new Exception("Error occurred", ...); This is just a quick-n-dirty example, of course. In an actual implementation you'd templatize makeException() so that you can create different exception types, e.g.: throw make!UserDefinedException("...", ...); Filename, line numbers, etc., can be easily accomodated the same way they're currently handled in exception ctors.There's nothing about the 'throw' keyword that requires GC allocation. It's just that `throw new Exception(...)` has become a standard incantation. The exception object itself can, for example, be emplaced onto a static buffer as I propose above.Yes, there are ways to work around allocating an exception with new right before throwing it, but that's really how things are designed to work, and there are serious problems with any attempt to work around it. At minimum, it makes throwing exceptions to be a lot more of a pain then it is when using the GC [...]But the fact that the workarounds either require that you don't have unique, independent exceptions or that you know that you need to manually free the exception after catching it is a serious problem. And that's without even taking the exception chaining into account.[...] Using a preinitialized region allocator, we no longer have such limitations. T -- GEEK = Gatherer of Extremely Enlightening Knowledge
Sep 14 2016
On Wednesday, 14 September 2016 at 14:43:29 UTC, H. S. Teoh wrote:Honestly, I've never actually run across a real-life case where chained exceptions matter. Most of the code (that I work with, anyway) involve simply throwing an exception when some problem occurs, and the catch block simply prints the error message and aborts the current operation.See e.g. https://github.com/dlang/druntime/blob/master/src/core/thread.d#L783
Sep 15 2016
On Wednesday, September 14, 2016 07:43:29 H. S. Teoh via Digitalmars-d wrote:And how would you deal with the fact that the catching code is generally going to assume that it has a GC-allocated exception? It's not going to do anything to free the exception when it's done with it, and it could keep the exception around for an indeterminate amount of time. So, having the code that manages the allocator later assume that the exception was freed would be unsafe. I don't see how it's going to work in the general case to have a an exception class which is anything other than GC allocated - not as long as it can't be wrapped in a struct that knows how to deal with freeing its memory when it's done. Because you either end up with an exception that gets leaked, because the catching code doesn't know that it needs to do something to free it, or you run the risk of it being freed prematurely when the code that manages its memory assumes that the code that caught it didn't keep it. Obviously, if you're talking about a smaller application that isn't sharing code with anything, you have more control over what's going on, and you can afford to make assumptions about what is happening with exceptions and are thus more likely to get away with stuff that won't work in the general case. But libraries definitely have to care, and larger applications are going to tend to have to care, because if there's enough code, it simply isn't going to work to assume that it all behaves in a way that differs from how exceptions normally work. Someone else is going to come onto the project and write perfectly normal D code that then has nasty bugs when an exception gets thrown, because other code within that large application was doing something with exceptions that didn't work with normal D code (like allocating them with a different allocator that won't allow you to hold onto the exception for an arbitrary amount of time without it being mutated out from under you or even outright freed). - Jonathan M DavisBut the fact that the workarounds either require that you don't have unique, independent exceptions or that you know that you need to manually free the exception after catching it is a serious problem. And that's without even taking the exception chaining into account.[...] Using a preinitialized region allocator, we no longer have such limitations.
Sep 14 2016
On Monday, 12 September 2016 at 22:57:23 UTC, Andrei Alexandrescu wrote:[snip] If it is, that provides more impetus for reference counting for D by the following logic: (a) it is likely that in the future more code will run on portable, battery-powered systems; (b) battery power does not follow a Moore trajectory, so at this point in history demand for battery lifetime is elastic. AndreiI'm keen on reference counting because of embedded and bare-metal programming so I'm super keen on D having a short reference long garbage standard. I guess we already do this to some extent with scope etc. Battery life can last for years in some of the new embedded devices but most languages targeting the M0 etc are really archaic, I have seen a rust port somewhere... but if I'm honest I only really care for D so I really want LDC -> ARM M0 etc... :D
Sep 15 2016