digitalmars.D - Optimizing Immutable and Purity
- Walter Bright (4/4) Dec 22 2008 I've been working on improving the optimizer to take advantage of
- bearophile (6/7) Dec 22 2008 Better link:
- Denis Koroskin (4/10) Dec 22 2008 Here is correct link:
- bearophile (15/18) Dec 22 2008 Multiplication and pointer operations are both very common operation in ...
- Walter Bright (6/20) Dec 22 2008 I doubt it. There isn't any other language with D's mix of imperative
- bearophile (103/105) Dec 22 2008 It seems to work:
- Bill Baxter (3/11) Dec 22 2008 Does GCC complain if you do something clearly impure inside bar?
- Walter Bright (6/19) Dec 22 2008 I got:
- Dave (17/20) Dec 24 2008 I was on a large project not too long ago which used some formal eval
- Jerry Quinn (3/9) Dec 22 2008 This was an interesting read. It would be nice to see a discussion of h...
- Bill Baxter (7/15) Dec 22 2008 It's basically useless for optimizations I think.
- Walter Bright (4/15) Dec 22 2008 Right. It's useless.
- Andrei Alexandrescu (4/22) Dec 23 2008 Const is still useful because inside a function you know for sure that
- Walter Bright (2/19) Dec 23 2008 I think you meant immutable.
- Jarrett Billingsley (4/5) Dec 23 2008 Are there going to be docs on this "immutable" soon? It's been around
- Andrei Alexandrescu (3/23) Dec 23 2008 I meant const.
- Walter Bright (3/26) Dec 23 2008 In the future, of course, "shared const" means another thread can modify...
- Andrei Alexandrescu (16/44) Dec 24 2008 Here's an example:
- Walter Bright (8/38) Dec 24 2008 I see what you mean, now. I thought you were talking about inside foo()....
- Jason House (2/52) Dec 24 2008 You have to be extremely careful with this kind of thing. If any calls ...
- Andrei Alexandrescu (3/51) Dec 24 2008 Care goes without saying.
- Jason House (2/25) Dec 28 2008 The underlying question the optimizer must answer when doing this kind o...
- KennyTM~ (3/28) Dec 24 2008 I think const means readonly in C# which means a huge glass wall is put
- Jason House (4/14) Dec 24 2008 At least for the current D2, your statement is very wrong. For function ...
- Andrei Alexandrescu (16/41) Dec 24 2008 In D2, threads will be effectively memory-isolated. Walter, Bartosz, and...
I've been working on improving the optimizer to take advantage of immutability and purity. http://www.reddit.com/r/reddit.com/comments/7l5x4/optimizing_immutable_and_purity/ http://dobbscodetalk.com/index.php?option=com_myblog&show=Optimizing-Immutable-and-Purity.html&Itemid=29
Dec 22 2008
Walter Bright:http://dobbscodetalk.com/index.php?option=com_myblog&show=Optimizing-Immutable-and-Purity.html&Itemid=29Better link: http://dobbscodetalk.com/index.php?option=com_myblog&show=Optimizing-Immutable-and-Purity.html&Itemid=29 (Not read yet). Bye, bearophile
Dec 22 2008
On Tue, 23 Dec 2008 01:10:52 +0300, Walter Bright <newshound1 digitalmars.com> wrote:I've been working on improving the optimizer to take advantage of immutability and purity. http://www.reddit.com/r/reddit.com/comments/7l5x4/optimizing_immutable_and_purity/ http://dobbscodetalk.com/index.php?option=com_myblog&show=Optimizing-Immutable-and-Purity.html&Itemid=29Your link is wrong - '&' is replaced with '&' and thus following the link gives the error below:You are not authorised to view this resource. You need to login.Here is correct link: http://dobbscodetalk.com/index.php?option=com_myblog&show=Optimizing-Immutable-and-Purity.html&Itemid=29
Dec 22 2008
Multiplication and pointer operations are both very common operation in C code, so this code shows well why I don't like them to be represented by the same symbol. Pascal uses ^ for poinetr operation (and ^ isn't used for the bitwise operation): int foo(int* a, int* b) { int i = *a * *b; int j = *a * *b; return i + j; }By the very definition of purity, you won't be able to to ever notice the absent call unless you are willing to place a precise thermal probe on the processor and notice a drop in the heat produced.<This sounds a little silly :-]one rule that is fairly consistent is that fewer instructions execute faster.<Generally this isn't much true anymore.On a real program, how much faster is my code going to get, if I maximize use of pure functions and immutable data? I don't know. I don't have any experience with it on a large program.<Maybe some programmer already used to pure functional programming can give you some answer. Is GCC able to perform similar optimizations (some of them, not all of them) when you use the "pure" attribute to functions? See int square (int) __attribute__ ((pure)); in this page: http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html A very readable article, but I don't have much other comments to add on-topic. Bye, bearophile
Dec 22 2008
bearophile wrote:It is <g>. Try it.one rule that is fairly consistent is that fewer instructions execute faster.<Generally this isn't much true anymore.I doubt it. There isn't any other language with D's mix of imperative and functional such that you can do a reasonable comparative study.On a real program, how much faster is my code going to get, if I maximize use of pure functions and immutable data? I don't know. I don't have any experience with it on a large program.<Maybe some programmer already used to pure functional programming can give you some answer.Is GCC able to perform similar optimizations (some of them, not all of them) when you use the "pure" attribute to functions? See int square (int) __attribute__ ((pure)); in this page: http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.htmlI didn't know gcc had pure functions. It doesn't have immutable data. If it does optimize with it, you can try it and see!
Dec 22 2008
Walter Bright:I didn't know gcc had pure functions. It doesn't have immutable data. If it does optimize with it, you can try it and see!It seems to work: // test1 int bar(int); int foo(int i) { return bar(i) + bar(i); } Asm with no optimization and default CPU, GCC 4.2.1: .file "test1.c" .text .globl _foo .def _foo; .scl 2; .type 32; .endef _foo: pushl %ebp movl %esp, %ebp pushl %ebx subl $4, %esp movl 8(%ebp), %eax movl %eax, (%esp) call _bar movl %eax, %ebx movl 8(%ebp), %eax movl %eax, (%esp) call _bar leal (%ebx,%eax), %eax addl $4, %esp popl %ebx popl %ebp ret .def _bar; .scl 2; .type 32; .endef With -O2: .file "test1.c" .text .p2align 4,,15 .globl _foo .def _foo; .scl 2; .type 32; .endef _foo: pushl %ebp movl %esp, %ebp subl $24, %esp movl %ebx, -8(%ebp) movl 8(%ebp), %ebx movl %esi, -4(%ebp) movl %ebx, (%esp) call _bar movl %ebx, (%esp) movl %eax, %esi call _bar movl -8(%ebp), %ebx addl %esi, %eax movl -4(%ebp), %esi movl %ebp, %esp popl %ebp ret .def _bar; .scl 2; .type 32; .endef // test2 int bar(int) __attribute__ ((pure)); int foo(int i) { return bar(i) + bar(i); } Asm with no optimization: .file "test2.c" .text .globl _foo .def _foo; .scl 2; .type 32; .endef _foo: pushl %ebp movl %esp, %ebp pushl %ebx subl $4, %esp movl 8(%ebp), %eax movl %eax, (%esp) call _bar movl %eax, %ebx movl 8(%ebp), %eax movl %eax, (%esp) call _bar leal (%ebx,%eax), %eax addl $4, %esp popl %ebx popl %ebp ret .def _bar; .scl 2; .type 32; .endef With -O2: .file "test2.c" .text .p2align 4,,15 .globl _foo .def _foo; .scl 2; .type 32; .endef _foo: pushl %ebp movl %esp, %ebp subl $8, %esp movl 8(%ebp), %eax movl %eax, (%esp) call _bar leave addl %eax, %eax ret .def _bar; .scl 2; .type 32; .endef As you can see now there's just one call to bar. Bye, bearophile
Dec 22 2008
On Tue, Dec 23, 2008 at 12:10 PM, bearophile <bearophileHUGS lycos.com> wrote:Walter Bright:Does GCC complain if you do something clearly impure inside bar? --bbI didn't know gcc had pure functions. It doesn't have immutable data. If it does optimize with it, you can try it and see!It seems to work: [...] As you can see now there's just one call to bar. Bye, bearophile
Dec 22 2008
Bill Baxter wrote:On Tue, Dec 23, 2008 at 12:10 PM, bearophile <bearophileHUGS lycos.com> wrote:I got: error: attributes are not allowed on a function-definition Oh well. It looks like a 25% implemented feature. It also only worked with g++. gcc wouldn't accept it at all. Without some sort of immutability, also, purity cannot be checked anyway.Walter Bright:Does GCC complain if you do something clearly impure inside bar?I didn't know gcc had pure functions. It doesn't have immutable data. If it does optimize with it, you can try it and see!It seems to work: [...] As you can see now there's just one call to bar. Bye, bearophile
Dec 22 2008
I was on a large project not too long ago which used some formal eval questionaires to gauge quality (much of it subjective). Long story short, the overall "quality" rating went up significantly after the only thing that changed was a few passes through the bottlenecks to improve performance in those areas. Say, 2% of the code. Slow areas in any program really bring down the overall user opinion of said program I think. So, since the bottlenecks usually come down to just a few lines of code, the big advantage of the optimizations for immutable and pure to me would be avoiding having to often "drop down" into asm., manually re-writing to "hoist" duplicative code out of tight loops or experimenting with load -> update -> store patterns to get the compiler to spit out the best code. All this can be time-consuming and error-prone so I would think that for some programs your work here would be very valuable, and save quite a bit of development time and cost _if_ the developer took advantage of pure and immutable, consistently, where applicable. Especially in libraries. - DaveOn a real program, how much faster is my code going to get, if I maximize use of pure functions and immutable data? I don't know. I don't have any experience with it on a large program.<
Dec 24 2008
Walter Bright Wrote:I've been working on improving the optimizer to take advantage of immutability and purity. http://www.reddit.com/r/reddit.com/comments/7l5x4/optimizing_immutable_and_purity/ http://dobbscodetalk.com/index.php?option=com_myblog&show=Optimizing-Immutable-and-Purity.html&Itemid=29This was an interesting read. It would be nice to see a discussion of how const is going to fit in in terms of optimization potential, since you can always cast it away. Jerry
Dec 22 2008
On Tue, Dec 23, 2008 at 11:30 AM, Jerry Quinn <jlquinn optonline.net> wrote:Walter Bright Wrote:It's basically useless for optimizations I think. Even if the view of the data you have is const, someone else might have a non-const view of the same data. So for instance, if you call any function, your "const" data could have been changed via non-const global pointers to the same data. --bbI've been working on improving the optimizer to take advantage of immutability and purity. http://www.reddit.com/r/reddit.com/comments/7l5x4/optimizing_immutable_and_purity/ http://dobbscodetalk.com/index.php?option=com_myblog&show=Optimizing-Immutable-and-Purity.html&Itemid=29This was an interesting read. It would be nice to see a discussion of how const is going to fit in in terms of optimization potential, since you can always cast it away.
Dec 22 2008
Bill Baxter wrote:On Tue, Dec 23, 2008 at 11:30 AM, Jerry Quinn <jlquinn optonline.net> wrote:Right. It's useless. Casting away const and immutable also puts one into undefined behavior territory.This was an interesting read. It would be nice to see a discussion of how const is going to fit in in terms of optimization potential, since you can always cast it away.It's basically useless for optimizations I think. Even if the view of the data you have is const, someone else might have a non-const view of the same data. So for instance, if you call any function, your "const" data could have been changed via non-const global pointers to the same data.
Dec 22 2008
Bill Baxter wrote:On Tue, Dec 23, 2008 at 11:30 AM, Jerry Quinn <jlquinn optonline.net> wrote:Const is still useful because inside a function you know for sure that another thread can't modify the data. AndreiWalter Bright Wrote:It's basically useless for optimizations I think. Even if the view of the data you have is const, someone else might have a non-const view of the same data. So for instance, if you call any function, your "const" data could have been changed via non-const global pointers to the same data. --bbI've been working on improving the optimizer to take advantage of immutability and purity. http://www.reddit.com/r/reddit.com/comments/7l5x4/optimizing_immutable_and_purity/ http://dobbscodetalk.com/index.php?option=com_myblog&show=Optimizing-Immutable-and-Purity.html&Itemid=29This was an interesting read. It would be nice to see a discussion of how const is going to fit in in terms of optimization potential, since you can always cast it away.
Dec 23 2008
Andrei Alexandrescu wrote:Bill Baxter wrote:I think you meant immutable.On Tue, Dec 23, 2008 at 11:30 AM, Jerry Quinn <jlquinn optonline.net> wrote:Const is still useful because inside a function you know for sure that another thread can't modify the data.This was an interesting read. It would be nice to see a discussion of how const is going to fit in in terms of optimization potential, since you can always cast it away.It's basically useless for optimizations I think. Even if the view of the data you have is const, someone else might have a non-const view of the same data. So for instance, if you call any function, your "const" data could have been changed via non-const global pointers to the same data. --bb
Dec 23 2008
On Tue, Dec 23, 2008 at 3:23 PM, Walter Bright <newshound1 digitalmars.com> wrote:I think you meant immutable.Are there going to be docs on this "immutable" soon? It's been around for two months now..
Dec 23 2008
Walter Bright wrote:Andrei Alexandrescu wrote:I meant const. AndreiBill Baxter wrote:I think you meant immutable.On Tue, Dec 23, 2008 at 11:30 AM, Jerry Quinn <jlquinn optonline.net> wrote:Const is still useful because inside a function you know for sure that another thread can't modify the data.This was an interesting read. It would be nice to see a discussion of how const is going to fit in in terms of optimization potential, since you can always cast it away.It's basically useless for optimizations I think. Even if the view of the data you have is const, someone else might have a non-const view of the same data. So for instance, if you call any function, your "const" data could have been changed via non-const global pointers to the same data. --bb
Dec 23 2008
Andrei Alexandrescu wrote:Walter Bright wrote:In the future, of course, "shared const" means another thread can modify it, but "const" means it cannot. Is that what you meant?Andrei Alexandrescu wrote:I meant const.Bill Baxter wrote:I think you meant immutable.On Tue, Dec 23, 2008 at 11:30 AM, Jerry Quinn <jlquinn optonline.net> wrote:Const is still useful because inside a function you know for sure that another thread can't modify the data.This was an interesting read. It would be nice to see a discussion of how const is going to fit in in terms of optimization potential, since you can always cast it away.It's basically useless for optimizations I think. Even if the view of the data you have is const, someone else might have a non-const view of the same data. So for instance, if you call any function, your "const" data could have been changed via non-const global pointers to the same data. --bb
Dec 23 2008
Walter Bright wrote:Andrei Alexandrescu wrote:Here's an example: int foo(const int*); void bar() { int a = 5; foo(&a); // can assume a is unmodified? } There are two issues here. One is that the const guarantees that foo does not legally change a, so it is useful for an optimization (e.g. assume that a == 5 after the call to foo). The second issue is that compilers often assume that a function call may change the stack of the caller in an arbitrary way. I think it is safe to lift that assumption for D programs and consider a functions' automatic variables as private to the function. AndreiWalter Bright wrote:In the future, of course, "shared const" means another thread can modify it, but "const" means it cannot. Is that what you meant?Andrei Alexandrescu wrote:I meant const.Bill Baxter wrote:I think you meant immutable.On Tue, Dec 23, 2008 at 11:30 AM, Jerry Quinn <jlquinn optonline.net> wrote:Const is still useful because inside a function you know for sure that another thread can't modify the data.This was an interesting read. It would be nice to see a discussion of how const is going to fit in in terms of optimization potential, since you can always cast it away.It's basically useless for optimizations I think. Even if the view of the data you have is const, someone else might have a non-const view of the same data. So for instance, if you call any function, your "const" data could have been changed via non-const global pointers to the same data. --bb
Dec 24 2008
Andrei Alexandrescu wrote:Walter Bright wrote:I see what you mean, now. I thought you were talking about inside foo(). You're right that as far as bar() goes, foo() will not change a. C and C++ optimizers assume that for locals which never have their address taken, function calls will not change them. This assumption must be valid otherwise locals could never be assigned to registers. If the address is taken, it must be assumed that calling a function will modify them.Andrei Alexandrescu wrote:Here's an example: int foo(const int*); void bar() { int a = 5; foo(&a); // can assume a is unmodified? } There are two issues here. One is that the const guarantees that foo does not legally change a, so it is useful for an optimization (e.g. assume that a == 5 after the call to foo). The second issue is that compilers often assume that a function call may change the stack of the caller in an arbitrary way. I think it is safe to lift that assumption for D programs and consider a functions' automatic variables as private to the function.In the future, of course, "shared const" means another thread can modify it, but "const" means it cannot. Is that what you meant?I meant const.Const is still useful because inside a function you know for sure that another thread can't modify the data.I think you meant immutable.
Dec 24 2008
Andrei Alexandrescu Wrote:Walter Bright wrote:You have to be extremely careful with this kind of thing. If any calls are made with a mutable &a before the call to foo, that optimization can no longer be performed. Also, if a's type changes and used a custom constructor, then that optimization is unreliable for anything other than taking the object's address. If a mutable reference is leaked, all function calls become suspect...Andrei Alexandrescu wrote:Here's an example: int foo(const int*); void bar() { int a = 5; foo(&a); // can assume a is unmodified? } There are two issues here. One is that the const guarantees that foo does not legally change a, so it is useful for an optimization (e.g. assume that a == 5 after the call to foo). The second issue is that compilers often assume that a function call may change the stack of the caller in an arbitrary way. I think it is safe to lift that assumption for D programs and consider a functions' automatic variables as private to the function. AndreiWalter Bright wrote:In the future, of course, "shared const" means another thread can modify it, but "const" means it cannot. Is that what you meant?Andrei Alexandrescu wrote:I meant const.Bill Baxter wrote:I think you meant immutable.On Tue, Dec 23, 2008 at 11:30 AM, Jerry Quinn <jlquinn optonline.net> wrote:Const is still useful because inside a function you know for sure that another thread can't modify the data.This was an interesting read. It would be nice to see a discussion of how const is going to fit in in terms of optimization potential, since you can always cast it away.It's basically useless for optimizations I think. Even if the view of the data you have is const, someone else might have a non-const view of the same data. So for instance, if you call any function, your "const" data could have been changed via non-const global pointers to the same data. --bb
Dec 24 2008
Jason House wrote:Andrei Alexandrescu Wrote:Care goes without saying. AndreiWalter Bright wrote:You have to be extremely careful with this kind of thing. If any calls are made with a mutable &a before the call to foo, that optimization can no longer be performed. Also, if a's type changes and used a custom constructor, then that optimization is unreliable for anything other than taking the object's address. If a mutable reference is leaked, all function calls become suspect...Andrei Alexandrescu wrote:Here's an example: int foo(const int*); void bar() { int a = 5; foo(&a); // can assume a is unmodified? } There are two issues here. One is that the const guarantees that foo does not legally change a, so it is useful for an optimization (e.g. assume that a == 5 after the call to foo). The second issue is that compilers often assume that a function call may change the stack of the caller in an arbitrary way. I think it is safe to lift that assumption for D programs and consider a functions' automatic variables as private to the function. AndreiWalter Bright wrote:In the future, of course, "shared const" means another thread can modify it, but "const" means it cannot. Is that what you meant?Andrei Alexandrescu wrote:I meant const.Bill Baxter wrote:I think you meant immutable.On Tue, Dec 23, 2008 at 11:30 AM, Jerry Quinn <jlquinn optonline.net> wrote:Const is still useful because inside a function you know for sure that another thread can't modify the data.This was an interesting read. It would be nice to see a discussion of how const is going to fit in in terms of optimization potential, since you can always cast it away.It's basically useless for optimizations I think. Even if the view of the data you have is const, someone else might have a non-const view of the same data. So for instance, if you call any function, your "const" data could have been changed via non-const global pointers to the same data. --bb
Dec 24 2008
Andrei Alexandrescu wrote:Jason House wrote:The underlying question the optimizer must answer when doing this kind of optimization is "are there any other mutable references"? My whole set of caveats above is all about answering that question. Once upon a time, I had convinced myself that a complete const system would address that. Maybe when it's time to come back and do a complete solution to scope delegates and escape analysis, this kind of thing could be explored further.Andrei Alexandrescu Wrote:Care goes without saying. AndreiThere are two issues here. One is that the const guarantees that foo does not legally change a, so it is useful for an optimization (e.g. assume that a == 5 after the call to foo). The second issue is that compilers often assume that a function call may change the stack of the caller in an arbitrary way. I think it is safe to lift that assumption for D programs and consider a functions' automatic variables as private to the function. AndreiYou have to be extremely careful with this kind of thing. If any calls are made with a mutable &a before the call to foo, that optimization can no longer be performed. Also, if a's type changes and used a custom constructor, then that optimization is unreliable for anything other than taking the object's address. If a mutable reference is leaked, all function calls become suspect...
Dec 28 2008
Andrei Alexandrescu wrote:Walter Bright wrote:in front of you so only you can't mess with the variable?Andrei Alexandrescu wrote:I meant const. AndreiBill Baxter wrote:I think you meant immutable.On Tue, Dec 23, 2008 at 11:30 AM, Jerry Quinn <jlquinn optonline.net> wrote:Const is still useful because inside a function you know for sure that another thread can't modify the data.This was an interesting read. It would be nice to see a discussion of how const is going to fit in in terms of optimization potential, since you can always cast it away.It's basically useless for optimizations I think. Even if the view of the data you have is const, someone else might have a non-const view of the same data. So for instance, if you call any function, your "const" data could have been changed via non-const global pointers to the same data. --bb
Dec 24 2008
Andrei Alexandrescu Wrote:Walter Bright wrote:At least for the current D2, your statement is very wrong. For function calls, const is merely a promise by the callee to not modify the data or call non-const member functions. Any data can be passed into the function. That means that mutable references can exist through other threads, global variables, or through other input parameters. Const data can change at any time. Even if we jump forward to a D2 where only shared const can be modified by other threads, the guarantees are not much better. Every impure function call can modify the data. That includes const member functions of const data! I've complained about that last bit many times. The bottom line is that const gives no guarantees.Andrei Alexandrescu wrote:I meant const. AndreiConst is still useful because inside a function you know for sure that another thread can't modify the data.I think you meant immutable.
Dec 24 2008
Jason House wrote:Andrei Alexandrescu Wrote:Yah.Walter Bright wrote:At least for the current D2, your statement is very wrong.Andrei Alexandrescu wrote:I meant const. AndreiConst is still useful because inside a function you know for sure that another thread can't modify the data.I think you meant immutable.For function calls, const is merely a promise by the callee to not modify the data or call non-const member functions. Any data can be passed into the function. That means that mutable references can exist through other threads, global variables, or through other input parameters. Const data can change at any time.In D2, threads will be effectively memory-isolated. Walter, Bartosz, and I are convinced that this is a very solid model to start with. Sharing among threads will be explicit by means of a "shared" type constructor. Everything else will be unshared. This is in contrast with the C, C++, and Java model in which all threads share memory indiscriminately (and it's up to the programmer to painstakingly ensure that no undue sharing is happening and that all sharing is properly synchronized). I think that model will go the way of the dinosaur. For const, this means that const data can be assumed to be modified through aliases in the current thread, but not in other threads. So if the compiler proves no aliasing for a code region, const is as good as immutable.Even if we jump forward to a D2 where only shared const can be modified by other threads, the guarantees are not much better. Every impure function call can modify the data. That includes const member functions of const data! I've complained about that last bit many times. The bottom line is that const gives no guarantees.See the example in my other post. Andrei
Dec 24 2008