www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - iPhone vs Android

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
next sibling parent Rikki Cattermole <alphaglosined gmail.com> writes:
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.


 Andrei
I 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
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
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 counting
I 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
next sibling parent Rikki Cattermole <alphaglosined gmail.com> writes:
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
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent Stefan Koch <uplink.coder googlemail.com> writes:
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
prev sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Tuesday, September 13, 2016 03:58:50 Walter Bright via Digitalmars-d wrote:
 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.
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 Davis
Sep 13 2016
parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
next sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
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
next sibling parent reply deadalnix <deadalnix gmail.com> writes:
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
parent reply John Colvin <john.loughran.colvin gmail.com> writes:
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:
 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.
Can you explain a bit more here? Do you mean in practice (I.e. in current implementation) or in theory?
Sep 14 2016
parent deadalnix <deadalnix gmail.com> writes:
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:
 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.
Can you explain a bit more here? Do you mean in practice (I.e. in current implementation) or in theory?
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.
Sep 14 2016
prev sibling parent Lurker <lurker gmail.com> writes:
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 Davis
Introduce 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
prev sibling next sibling parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
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
parent Walter Bright <newshound2 digitalmars.com> writes:
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
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/13/2016 6:09 PM, Andrei Alexandrescu wrote:
 On 09/13/2016 05:43 PM, Walter Bright wrote:
 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?
Yes we did. The design of Phobos would be better and more flexible if exceptions didn't rely on the GC.
Sep 13 2016
prev sibling parent reply Shachar Shemesh <shachar weka.io> writes:
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
next sibling parent reply Laeeth Isharc <laeethnospam nospamlaeeth.com> writes:
On Tuesday, 13 September 2016 at 11:59:46 UTC, Shachar Shemesh 
wrote:
 On 13/09/16 02:21, deadalnix wrote:
 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
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. Laeeth
Sep 13 2016
parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
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:
 On 13/09/16 02:21, deadalnix wrote:
 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
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.
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 Davis
Sep 13 2016
next sibling parent reply Laeeth Isharc <laeethnospam nospamlaeeth.com> writes:
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:
 On Tuesday, 13 September 2016 at 11:59:46 UTC, Shachar Shemesh

 wrote:
 On 13/09/16 02:21, deadalnix wrote:
 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
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.
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 Davis
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?
Sep 13 2016
parent reply Marco Leise <Marco.Leise gmx.de> writes:
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
parent Laeeth Isharc <laeethnospam nospamlaeeth.com> writes:
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 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. :)
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. Laeeth
Sep 13 2016
prev sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
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
parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
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:
 As I understand it, [snnip]
If you ever write a book, I would pre-order it.
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 Davis
Sep 13 2016
parent jmh530 <john.michael.hall gmail.com> writes:
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 Davis
Typos are for spellcheckers.
Sep 13 2016
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Tuesday, 13 September 2016 at 11:59:46 UTC, Shachar Shemesh 
wrote:
 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?
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.
 But first and foremost, it is a disaster for shared data.
Again, please elaborate.
For shared data, you need synchronized reference counting, which is prohibitively expensive.
 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
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.
Sep 13 2016
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
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
parent Jacob Carlborg <doob me.com> writes:
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
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
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
prev sibling parent reply finalpatch <fengli gmail.com> writes:
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
next sibling parent reply Laeeth Isharc <laeethnospam nospam.laeeth.com> writes:
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 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.
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.
Sep 14 2016
parent Chris Wright <dhasenan gmail.com> writes:
On Wed, 14 Sep 2016 13:37:03 +0000, Laeeth Isharc wrote:

 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 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.
Could you elaborate?
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.
Sep 15 2016
prev sibling parent deadalnix <deadalnix gmail.com> writes:
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 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.
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.
 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
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply Shachar Shemesh <shachar weka.io> writes:
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
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply Shachar Shemesh <shachar weka.io> writes:
On 14/09/16 09:05, Walter Bright wrote:
 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.
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). Shachar
Sep 13 2016
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
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
prev sibling parent reply Laeeth Isharc <laeethnospam nospam.laeeth.com> writes:
On Wednesday, 14 September 2016 at 06:33:59 UTC, Shachar Shemesh 
wrote:
 On 14/09/16 09:05, Walter Bright wrote:
 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.
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). Shachar
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?
Sep 14 2016
parent Shachar Shemesh <shachar weka.io> writes:
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.but
I 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
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Wednesday, 14 September 2016 at 05:38:38 UTC, Shachar Shemesh 
wrote:
 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
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.
Sep 14 2016
parent Paulo Pinto <pjmlp progtools.org> writes:
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:
 On 14/09/16 02:59, Walter Bright 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. 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
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.
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_1765837
Sep 14 2016
prev sibling next sibling parent reply Joakim <dlang joakim.fea.st> writes:
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
parent deadalnix <deadalnix gmail.com> writes:
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
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
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
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
next sibling parent Kagamin <spam here.lot> writes:
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. -- Andrei
IIRC there was a thread about GC here where somebody posted a bunch of links to resources and benchmarks.
Sep 13 2016
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
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. -- Andrei
http://sealedabstract.com/rants/why-mobile-web-apps-are-slow/ http://www-cs.canisius.edu/~hertzm/gcmalloc-oopsla-2005.pdf Probably these.
Sep 13 2016
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/13/16 11:58 AM, Kagamin wrote:
 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. -- Andrei
http://sealedabstract.com/rants/why-mobile-web-apps-are-slow/
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.” ====
 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
parent Kagamin <spam here.lot> writes:
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
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
On Tuesday, 13 September 2016 at 10:04:43 UTC, Andrei 
Alexandrescu wrote:
 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
I assume it is going to depend of the rate at which the application produces garbage.
Sep 13 2016
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/13/16 1:51 PM, deadalnix wrote:
 On Tuesday, 13 September 2016 at 10:04:43 UTC, Andrei Alexandrescu wrote:
 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
I assume it is going to depend of the rate at which the application produces garbage.
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. -- Andrei
Sep 13 2016
prev sibling next sibling parent Paulo Pinto <pjmlp progtools.org> writes:
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.


 Andrei
Just 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
prev sibling next sibling parent angel <andrey.gelman gmail.com> writes:
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
prev sibling next sibling parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
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: [...]

 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.)
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.
 [...]

 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.
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 Davis
Sep 14 2016
prev sibling next sibling parent reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
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:
 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.)
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.
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.
 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. [...]
 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 [...]
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.
 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
parent Kagamin <spam here.lot> writes:
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
prev sibling next sibling parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Wednesday, September 14, 2016 07:43:29 H. S. Teoh via Digitalmars-d wrote:
 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.
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 Davis
Sep 14 2016
prev sibling parent R <rjmcguire gmail.com> writes:
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.


 Andrei
I'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