Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #13209 > unrolled thread
| Started by | AD <isquat@gmail.com> |
|---|---|
| First post | 2012-01-10 04:35 -0800 |
| Last post | 2012-01-17 02:31 -0800 |
| Articles | 20 on this page of 81 — 24 participants |
Back to article view | Back to comp.lang.c++
Oozing poison AD <isquat@gmail.com> - 2012-01-10 04:35 -0800
Re: Oozing poison Leigh Johnston <leigh@i42.co.uk> - 2012-01-10 15:19 +0000
Re: Oozing poison AD <isquat@gmail.com> - 2012-01-11 00:43 -0800
Re: Oozing poison "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2012-01-11 10:01 +0100
Re: Oozing poison Ian Collins <ian-news@hotmail.com> - 2012-01-11 22:09 +1300
Re: Oozing poison AD <isquat@gmail.com> - 2012-01-11 01:42 -0800
Re: Oozing poison Leigh Johnston <leigh@i42.co.uk> - 2012-01-11 13:36 +0000
Re: Oozing poison John Bokma <john@castleamber.com> - 2012-01-11 10:08 -0600
Re: Oozing poison AD <isquat@gmail.com> - 2012-01-12 06:08 -0800
Re: Oozing poison Leigh Johnston <leigh@i42.co.uk> - 2012-01-12 14:13 +0000
Re: Oozing poison AD <isquat@gmail.com> - 2012-01-17 02:08 -0800
Re: Oozing poison Henrik Faber <hfaber@invalid.net> - 2012-01-17 12:50 +0100
Re: Oozing poison Nick Keighley <nick_keighley_nospam@hotmail.com> - 2012-01-13 02:18 -0800
Re: Oozing poison AD <isquat@gmail.com> - 2012-01-17 02:24 -0800
Re: Oozing poison Jorgen Grahn <grahn+nntp@snipabacken.se> - 2012-01-11 16:50 +0000
Re: Oozing poison AD <isquat@gmail.com> - 2012-01-12 06:04 -0800
Re: Oozing poison Victor Bazarov <v.bazarov@comcast.invalid> - 2012-01-12 10:13 -0500
Re: Oozing poison AD <isquat@gmail.com> - 2012-01-17 02:19 -0800
Re: Oozing poison Victor Bazarov <v.bazarov@comcast.invalid> - 2012-01-17 08:04 -0500
Re: Oozing poison Miles Bader <miles@gnu.org> - 2012-01-18 13:51 +0900
Re: Oozing poison AD <isquat@gmail.com> - 2012-01-21 04:40 -0800
Re: Oozing poison Quint Rankid <qbr567@gmail.com> - 2012-01-21 09:05 -0800
Re: Oozing poison Wil Evers <bouncer@dev.null> - 2012-01-21 18:52 +0000
Re: Oozing poison Quint Rankid <qbr567@gmail.com> - 2012-01-21 11:33 -0800
Re: Oozing poison AD <isquat@gmail.com> - 2012-01-25 02:23 -0800
Re: Oozing poison AD <isquat@gmail.com> - 2012-01-25 02:07 -0800
Re: Oozing poison Victor Bazarov <v.bazarov@comcast.invalid> - 2012-01-25 07:59 -0500
Re: Oozing poison Ian Collins <ian-news@hotmail.com> - 2012-01-26 07:54 +1300
Re: Oozing poison Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2012-01-21 22:43 -0500
Re: Oozing poison Ian Collins <ian-news@hotmail.com> - 2012-01-22 21:05 +1300
Re: Oozing poison Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2012-01-22 18:21 -0500
Re: Oozing poison Jorgen Grahn <grahn+nntp@snipabacken.se> - 2012-01-23 15:55 +0000
Re: Oozing poison gwowen <gwowen@gmail.com> - 2012-01-23 08:37 -0800
Re: Oozing poison Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2012-01-24 22:48 -0500
Re: Oozing poison Jorgen Grahn <grahn+nntp@snipabacken.se> - 2012-01-25 19:44 +0000
Re: Oozing poison Ian Collins <ian-news@hotmail.com> - 2012-01-26 08:56 +1300
Re: Oozing poison 88888 Dihedral <dihedral88888@googlemail.com> - 2012-01-25 23:04 -0800
Re: Oozing poison Nick Keighley <nick_keighley_nospam@hotmail.com> - 2012-01-26 03:24 -0800
Re: Oozing poison scott@slp53.sl.home (Scott Lurndal) - 2012-01-26 19:13 +0000
Re: Oozing poison Brian Drummond <brian@shapes.demon.co.uk> - 2012-01-27 00:12 +0000
Re: Oozing poison "MikeWhy" <boat042-nospam@yahoo.com> - 2012-01-26 22:44 -0600
Re: Oozing poison 88888 Dihedral <dihedral88888@googlemail.com> - 2012-01-28 14:25 -0800
Re: Oozing poison Robert Miles <milesrf@Usenet-News.net> - 2012-02-26 22:16 -0600
Re: Oozing poison "Gernot Frisch" <me@privacy.net> - 2012-01-24 18:21 +0100
Re: Oozing poison Victor Bazarov <v.bazarov@comcast.invalid> - 2012-01-24 12:41 -0500
Re: Oozing poison Nick Keighley <nick_keighley_nospam@hotmail.com> - 2012-01-26 03:25 -0800
Re: Oozing poison Rui Maciel <rui.maciel@gmail.com> - 2012-01-25 19:44 +0000
Re: Oozing poison Jorgen Grahn <grahn+nntp@snipabacken.se> - 2012-01-26 09:44 +0000
Re: Oozing poison Rui Maciel <rui.maciel@gmail.com> - 2012-01-26 10:36 +0000
Re: Oozing poison scott@slp53.sl.home (Scott Lurndal) - 2012-01-26 19:18 +0000
Re: Oozing poison Jorgen Grahn <grahn+nntp@snipabacken.se> - 2012-01-26 20:42 +0000
Re: Oozing poison Juha Nieminen <nospam@thanks.invalid> - 2012-01-26 16:30 +0000
Re: Oozing poison scott@slp53.sl.home (Scott Lurndal) - 2012-01-26 19:24 +0000
Re: Oozing poison Cholo Lennon <chololennon@hotmail.com> - 2012-01-26 17:13 -0300
Re: Oozing poison scott@slp53.sl.home (Scott Lurndal) - 2012-01-26 20:55 +0000
Re: Oozing poison Jorgen Grahn <grahn+nntp@snipabacken.se> - 2012-01-26 22:08 +0000
Re: Oozing poison scott@slp53.sl.home (Scott Lurndal) - 2012-01-27 00:32 +0000
Re: Oozing poison Dombo <dombo@disposable.invalid> - 2012-01-28 12:59 +0100
Re: Oozing poison Cholo Lennon <chololennon@hotmail.com> - 2012-01-27 18:28 -0300
Re: Oozing poison Jorgen Grahn <grahn+nntp@snipabacken.se> - 2012-01-29 18:02 +0000
Re: Oozing poison Ian Collins <ian-news@hotmail.com> - 2012-01-27 20:18 +1300
Re: Oozing poison Miles Bader <miles@gnu.org> - 2012-01-27 18:09 +0900
Re: Oozing poison scott@slp53.sl.home (Scott Lurndal) - 2012-01-27 20:29 +0000
Re: Oozing poison Ian Collins <ian-news@hotmail.com> - 2012-01-28 10:06 +1300
Re: Oozing poison scott@slp53.sl.home (Scott Lurndal) - 2012-01-27 21:26 +0000
Re: Oozing poison Ian Collins <ian-news@hotmail.com> - 2012-01-28 12:22 +1300
Re: Oozing poison scott@slp53.sl.home (Scott Lurndal) - 2012-01-28 04:18 +0000
Re: Oozing poison Miles Bader <miles@gnu.org> - 2012-01-28 13:44 +0900
Re: Oozing poison scott@slp53.sl.home (Scott Lurndal) - 2012-01-28 21:31 +0000
Re: Oozing poison Ian Collins <ian-news@hotmail.com> - 2012-01-29 11:32 +1300
Re: Oozing poison 88888 Dihedral <dihedral88888@googlemail.com> - 2012-01-28 14:55 -0800
Re: Oozing poison Ian Collins <ian-news@hotmail.com> - 2012-01-29 11:59 +1300
Re: Oozing poison scott@slp53.sl.home (Scott Lurndal) - 2012-01-30 17:08 +0000
Re: Oozing poison Ian Collins <ian-news@hotmail.com> - 2012-01-28 18:06 +1300
Re: Oozing poison scott@slp53.sl.home (Scott Lurndal) - 2012-01-28 22:49 +0000
Re: Oozing poison Ian Collins <ian-news@hotmail.com> - 2012-01-29 12:22 +1300
Re: Oozing poison scott@slp53.sl.home (Scott Lurndal) - 2012-01-27 20:16 +0000
Re: Oozing poison Ian Collins <ian-news@hotmail.com> - 2012-01-28 10:01 +1300
Re: Oozing poison Juha Nieminen <nospam@thanks.invalid> - 2012-01-28 16:00 +0000
Re: Oozing poison Jorgen Grahn <grahn+nntp@snipabacken.se> - 2012-01-10 21:42 +0000
Re: Oozing poison AD <isquat@gmail.com> - 2012-01-17 02:31 -0800
Page 4 of 5 — ← Prev page 1 2 3 [4] 5 Next page →
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2012-01-27 20:18 +1300 |
| Message-ID | <9of1duF8j0U1@mid.individual.net> |
| In reply to | #13598 |
On 01/27/12 09:55 AM, Scott Lurndal wrote: > Cholo Lennon<chololennon@hotmail.com> writes: >> On 26/01/2012 16:24, Scott Lurndal wrote: >>> The readability of C++ seems to get worse with each new version of the >>> standard. Once the<XXX> elements (static/dynamic casts, templates) were added >>> to the language, it became worse than perl for readability. >> >> Really? Do you think C++ cast operators go against readability? For me >> is the opposite: At glance, for example, they give you more information >> than the traditional C cast and, as a result, they are (IMHO) more readable. >> > > Buenas, > > I think they may provide better _maintainability_ at the expense of _readability_. > > It may also be that for someone coming from a C background (starting in 1978), > the dynamic/static cast syntax just looks alien and out of place. > > Templates and exceptions on the other hand, have a distinct impact on code size > (thus icache footprint, thus performance). The only performance impact I have ever measured from the use of exceptions is improvement. I have been testing compilers since the mid 90s and I have only found one compiler/platform (that compiler refused to inline any function that could throw) where exceptions had a detrimental impact on performance. In overall performance terms, templates are no worse and often a significant improvement over the direct C equivalent (macros) because they aren't necessary inlined. They can also provide significant performance improvements over another C alternative, the use of void* and function pointers (sorting being the classic example). Yes you can end up with multiple instances of class methods, but that is the price you pay for type safety. Anyway, what proportion of a decent sized project would that represent? For containers of pointers one can easily use inline wrappers round a container of void* to avoid bloat while retaining type safety. In most code I have seen, containers of T* are more numerous than containers of T Thus with contemporary tools, the twin myths of exception performance and template code bloat are just that: myths. -- Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Miles Bader <miles@gnu.org> |
|---|---|
| Date | 2012-01-27 18:09 +0900 |
| Message-ID | <buozkd91pho.fsf@dhlpc061.dev.necel.com> |
| In reply to | #13604 |
Ian Collins <ian-news@hotmail.com> writes: > The only performance impact I have ever measured from the use of > exceptions is improvement. I have been testing compilers since the mid > 90s and I have only found one compiler/platform (that compiler refused > to inline any function that could throw) where exceptions had a > detrimental impact on performance. Yeah, generally exceptions are very cheap these days, probably cheaper than equivalently-safe explicit-return-value-checking code. I guess some of the people decrying them may be remembering some of the initial naive implementations using setjmp/longjmp (OK, I guess the exception handling in MS's 32-bit ABI is still kinda of stinky). > Yes you can end up with multiple instances of class methods, but that is > the price you pay for type safety. Anyway, what proportion of a decent > sized project would that represent? For containers of pointers one can > easily use inline wrappers round a container of void* to avoid bloat > while retaining type safety. In most code I have seen, containers of T* > are more numerous than containers of T Also note that for really equivalent template expansions, one can sometimes merge the resulting redundant functions at link-time. In gcc, for instance, using "-ffunction-sections" at compile-time, and "-Wl,--icf=safe" at link-time; I'm pretty sure MS's compilers have something equivalent. -Miles -- Love is a snowmobile racing across the tundra. Suddenly it flips over, pinning you underneath. At night the ice weasels come. --Nietzsche
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2012-01-27 20:29 +0000 |
| Message-ID | <ZODUq.107194$487.76393@news.usenetserver.com> |
| In reply to | #13606 |
Miles Bader <miles@gnu.org> writes:
>Ian Collins <ian-news@hotmail.com> writes:
>> The only performance impact I have ever measured from the use of
>> exceptions is improvement. I have been testing compilers since the mid
>> 90s and I have only found one compiler/platform (that compiler refused
>> to inline any function that could throw) where exceptions had a
>> detrimental impact on performance.
>
>Yeah, generally exceptions are very cheap these days, probably cheaper
>than equivalently-safe explicit-return-value-checking code. I guess
>some of the people decrying them may be remembering some of the
>initial naive implementations using setjmp/longjmp (OK, I guess the
>exception handling in MS's 32-bit ABI is still kinda of stinky).
I tried substituting a 'new uint8[xx}' call to replace a malloc with a try
catch block for bad_alloc. I then disassembled the code. One instruction
(to test the return value of the malloc) turned into:
try {
buf = new uint8[bufsize];
7327: 4c 89 f7 mov %r14,%rdi
732a: e8 f9 e0 ff ff callq 5428 <operator new[](unsigned long)@plt>
732f: 48 89 c5 mov %rax,%rbp
7332: 49 89 c5 mov %rax,%r13
} catch (std::exception x) {
iocb->set_rd(IOT_WITH_EXCEPTIONS, RD1_OCS_MPU_PARITY);
return false;
}
switch (cmd) {
7335: 45 84 e4 test %r12b,%r12b
7338: 0f 84 8f 00 00 00 je 73cd <c_uniline_dlp::echo(c_iocb*)+0xdf>
733e: 41 80 fc 08 cmp $0x8,%r12b
7342: 0f 85 7e 01 00 00 jne 74c6 <c_uniline_dlp::echo(c_iocb*)+0x1d8>
7348: e9 21 01 00 00 jmpq 746e <c_uniline_dlp::echo(c_iocb*)+0x180>
734d: 48 89 c5 mov %rax,%rbp
7350: 48 83 fa 01 cmp $0x1,%rdx
7354: 74 08 je 735e <c_uniline_dlp::echo(c_iocb*)+0x70>
7356: 48 89 c7 mov %rax,%rdi
7359: e8 aa de ff ff callq 5208 <_Unwind_Resume@plt>
uint8 *buf;
uint8 cmd = iocb->get_op_var2();
try {
buf = new uint8[bufsize];
} catch (std::exception x) {
735e: 48 89 c7 mov %rax,%rdi
7361: e8 b2 dc ff ff callq 5018 <__cxa_get_exception_ptr@plt>
* library, and by certain language expressions. You are free to derive
* your own %exception classes, or use a different hierarchy, or to
* throw non-class data (e.g., fundamental types).
*/
class exception
{
7366: 48 8b 05 7b 83 20 00 mov 0x20837b(%rip),%rax # 20f6e8 <_DYNAMIC+0x1c0>
736d: 48 8d 40 10 lea 0x10(%rax),%rax
7371: 48 89 04 24 mov %rax,(%rsp)
7375: 48 89 ef mov %rbp,%rdi
7378: e8 db e0 ff ff callq 5458 <__cxa_begin_catch@plt>
iocb->set_rd(IOT_WITH_EXCEPTIONS, RD1_OCS_MPU_PARITY);
737d: 41 b9 00 00 00 00 mov $0x0,%r9d
7383: 41 b8 00 00 00 00 mov $0x0,%r8d
7389: b9 00 00 00 00 mov $0x0,%ecx
738e: ba 04 00 00 00 mov $0x4,%edx
7393: be 00 c0 00 00 mov $0xc000,%esi
7398: 48 89 df mov %rbx,%rdi
739b: e8 e8 dd ff ff callq 5188 <c_iocb::set_rd(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long)@plt>
uint8 *buf;
uint8 cmd = iocb->get_op_var2();
try {
buf = new uint8[bufsize];
} catch (std::exception x) {
73a0: 48 89 e7 mov %rsp,%rdi
73a3: e8 30 e1 ff ff callq 54d8 <std::exception::~exception()@plt>
73a8: e8 7b dd ff ff callq 5128 <__cxa_end_catch@plt>
73ad: 0f 1f 00 nopl (%rax)
73b0: e9 41 01 00 00 jmpq 74f6 <c_uniline_dlp::echo(c_iocb*)+0x208>
73b5: 48 89 c5 mov %rax,%rbp
73b8: 48 89 e7 mov %rsp,%rdi
73bb: e8 18 e1 ff ff callq 54d8 <std::exception::~exception()@plt>
73c0: e8 63 dd ff ff callq 5128 <__cxa_end_catch@plt>
73c5: 48 89 ef mov %rbp,%rdi
73c8: e8 3b de ff ff callq 5208 <_Unwind_Resume@plt>
return false;
}
switch (cmd) {
versus (with malloc):
buf = (uint8 *)malloc(bufsize);
7136: 4c 89 ef mov %r13,%rdi
7139: e8 6a dd ff ff callq 4ea8 <malloc@plt>
713e: 48 89 c3 mov %rax,%rbx
7141: 49 89 c6 mov %rax,%r14
if (buf == NULL) {
7144: 48 85 c0 test %rax,%rax
7147: 75 28 jne 7171 <c_uniline_dlp::echo(c_iocb*)+0x73>
iocb->set_rd(IOT_WITH_EXCEPTIONS, RD1_OCS_MPU_PARITY);
7149: 41 b9 00 00 00 00 mov $0x0,%r9d
714f: 41 b8 00 00 00 00 mov $0x0,%r8d
7155: b9 00 00 00 00 mov $0x0,%ecx
715a: ba 04 00 00 00 mov $0x4,%edx
715f: be 00 c0 00 00 mov $0xc000,%esi
7164: 48 89 ef mov %rbp,%rdi
7167: e8 4c de ff ff callq 4fb8 <c_iocb::set_rd(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long)@plt>
return false;
716c: e9 40 01 00 00 jmpq 72b1 <c_uniline_dlp::echo(c_iocb*)+0x1b3>
}
switch (cmd) {
scott
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2012-01-28 10:06 +1300 |
| Message-ID | <9oghusF8j0U4@mid.individual.net> |
| In reply to | #13610 |
On 01/28/12 09:29 AM, Scott Lurndal wrote: > Miles Bader<miles@gnu.org> writes: >> Ian Collins<ian-news@hotmail.com> writes: >>> The only performance impact I have ever measured from the use of >>> exceptions is improvement. I have been testing compilers since the mid >>> 90s and I have only found one compiler/platform (that compiler refused >>> to inline any function that could throw) where exceptions had a >>> detrimental impact on performance. >> >> Yeah, generally exceptions are very cheap these days, probably cheaper >> than equivalently-safe explicit-return-value-checking code. I guess >> some of the people decrying them may be remembering some of the >> initial naive implementations using setjmp/longjmp (OK, I guess the >> exception handling in MS's 32-bit ABI is still kinda of stinky). > > > I tried substituting a 'new uint8[xx}' call to replace a malloc with a try > catch block for bad_alloc. I then disassembled the code. One instruction > (to test the return value of the malloc) turned into: > How comes one version has multiple calls to new and the other one call to malloc? What was the original source? -- Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2012-01-27 21:26 +0000 |
| Message-ID | <3EEUq.107196$487.32649@news.usenetserver.com> |
| In reply to | #13612 |
Ian Collins <ian-news@hotmail.com> writes:
>On 01/28/12 09:29 AM, Scott Lurndal wrote:
>> Miles Bader<miles@gnu.org> writes:
>>> Ian Collins<ian-news@hotmail.com> writes:
>>>> The only performance impact I have ever measured from the use of
>>>> exceptions is improvement. I have been testing compilers since the mid
>>>> 90s and I have only found one compiler/platform (that compiler refused
>>>> to inline any function that could throw) where exceptions had a
>>>> detrimental impact on performance.
>>>
>>> Yeah, generally exceptions are very cheap these days, probably cheaper
>>> than equivalently-safe explicit-return-value-checking code. I guess
>>> some of the people decrying them may be remembering some of the
>>> initial naive implementations using setjmp/longjmp (OK, I guess the
>>> exception handling in MS's 32-bit ABI is still kinda of stinky).
>>
>>
>> I tried substituting a 'new uint8[xx}' call to replace a malloc with a try
>> catch block for bad_alloc. I then disassembled the code. One instruction
>> (to test the return value of the malloc) turned into:
>>
>
>How comes one version has multiple calls to new and the other one call
>to malloc?
>
>What was the original source?
>
uint8 cmd = iocb->get_op_var2();
buf = (uint8 *)malloc(bufsize);
if (buf == NULL) {
iocb->set_rd(IOT_WITH_EXCEPTIONS, RD1_OCS_MPU_PARITY);
return false;
}
switch (cmd) {
vs.
uint8 cmd = iocb->get_op_var2();
try {
buf = new uint8[bufsize];
} catch (std::exception e) {
iocb->set_rd(IOT_WITH_EXCEPTIONS, RD1_OCS_MPU_PARITY);
return false;
}
switch (cmd) {
There is only one call to operator new (at 732a), the source code
is intermixed with the assembler by the 'objdump' utility and it replicated the source
line in multiple places.
scott
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2012-01-28 12:22 +1300 |
| Message-ID | <9ogpsvF8j0U6@mid.individual.net> |
| In reply to | #13613 |
On 01/28/12 10:26 AM, Scott Lurndal wrote:
> Ian Collins<ian-news@hotmail.com> writes:
>> On 01/28/12 09:29 AM, Scott Lurndal wrote:
>>>
>>>
>>> I tried substituting a 'new uint8[xx}' call to replace a malloc with a try
>>> catch block for bad_alloc. I then disassembled the code. One instruction
>>> (to test the return value of the malloc) turned into:
>>>
>>
>> How comes one version has multiple calls to new and the other one call
>> to malloc?
>>
>> What was the original source?
>>
>
> uint8 cmd = iocb->get_op_var2();
>
> buf = (uint8 *)malloc(bufsize);
> if (buf == NULL) {
> iocb->set_rd(IOT_WITH_EXCEPTIONS, RD1_OCS_MPU_PARITY);
> return false;
> }
>
> switch (cmd) {
>
> vs.
>
> uint8 cmd = iocb->get_op_var2();
>
> try {
> buf = new uint8[bufsize];
> } catch (std::exception e) {
never catch exceptions by value, always catch by const reference to
avoid slicing.
> iocb->set_rd(IOT_WITH_EXCEPTIONS, RD1_OCS_MPU_PARITY);
> return false;
> }
>
> switch (cmd) {
>
> There is only one call to operator new (at 732a), the source code
> is intermixed with the assembler by the 'objdump' utility and it replicated the source
> line in multiple places.
This is fairly atypical use of exceptions, mixing exceptions and return
codes. It is more common to catch the exception at a higher call. This
simplifies the source and machine code (fewer conditional branches).
The catch is also the reason for all the extra code, constructing and
destructing a temporary std::exception object. The actual exception
handling part of the code is this bit:
} catch (std::exception x) {
73a0: 48 89 e7 mov %rsp,%rdi
73a3: e8 30 e1 ff ff callq 54d8
<std::exception::~exception()@plt>
73a8: e8 7b dd ff ff callq 5128 <__cxa_end_catch@plt>
73ad: 0f 1f 00 nopl (%rax)
73b0: e9 41 01 00 00 jmpq 74f6
<c_uniline_dlp::echo(c_iocb*)+0x208>
73b5: 48 89 c5 mov %rax,%rbp
73b8: 48 89 e7 mov %rsp,%rdi
73bb: e8 18 e1 ff ff callq 54d8
<std::exception::~exception()@plt>
73c0: e8 63 dd ff ff callq 5128 <__cxa_end_catch@plt>
73c5: 48 89 ef mov %rbp,%rdi
73c8: e8 3b de ff ff callq 5208 <_Unwind_Resume@plt>
return false;
}
hardly bloat! Now if the exception is caught higher up the call chain
(with f() being a void function), there would be less, rather than more
code.
--
Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2012-01-28 04:18 +0000 |
| Message-ID | <qGKUq.152389$624.85025@news.usenetserver.com> |
| In reply to | #13617 |
Ian Collins <ian-news@hotmail.com> writes:
>On 01/28/12 10:26 AM, Scott Lurndal wrote:
>> Ian Collins<ian-news@hotmail.com> writes:
>>> On 01/28/12 09:29 AM, Scott Lurndal wrote:
>>>>
>>>>
>>>> I tried substituting a 'new uint8[xx}' call to replace a malloc with a try
>>>> catch block for bad_alloc. I then disassembled the code. One instruction
>>>> (to test the return value of the malloc) turned into:
>>>>
>>>
>>> How comes one version has multiple calls to new and the other one call
>>> to malloc?
>>>
>>> What was the original source?
>>>
>>
>> uint8 cmd = iocb->get_op_var2();
>>
>> buf = (uint8 *)malloc(bufsize);
>> if (buf == NULL) {
>> iocb->set_rd(IOT_WITH_EXCEPTIONS, RD1_OCS_MPU_PARITY);
>> return false;
>> }
>>
>> switch (cmd) {
>>
>> vs.
>>
>> uint8 cmd = iocb->get_op_var2();
>>
>> try {
>> buf = new uint8[bufsize];
>> } catch (std::exception e) {
>
>never catch exceptions by value, always catch by const reference to
>avoid slicing.
Good to know, I guess. Since I intend to keep the malloc and forgo
the try/catch clause, the point is however moot.
>
>> iocb->set_rd(IOT_WITH_EXCEPTIONS, RD1_OCS_MPU_PARITY);
>> return false;
>> }
>>
>> switch (cmd) {
>>
>> There is only one call to operator new (at 732a), the source code
>> is intermixed with the assembler by the 'objdump' utility and it replicated the source
>> line in multiple places.
>
>This is fairly atypical use of exceptions, mixing exceptions and return
>codes. It is more common to catch the exception at a higher call. This
>simplifies the source and machine code (fewer conditional branches).
However, in this case (modeling a physical device), the best determination
of how to present the failure can be made as close to the cause of the
exception as possible. I would think that for most applications that
can actually recover from an error (as opposed to just catching std::exception
at the top level, printing a message, and exiting), keeping the recovery action
as close to the code that actually failed makes recovery much simpler.
>
>The catch is also the reason for all the extra code, constructing and
>destructing a temporary std::exception object. The actual exception
>handling part of the code is this bit:
Yet creating and destroying a temporary std::exception object also counts in
terms of both extra cycles and code footprint. Both of which impact
performance (generally negatively).
And indeed, some simple performance testing of code running under the simulation
(a 15,000 line BPL compile), shows that when I try exceptions in one of the common
allocation paths, the performance of the BPL compile drops from 17,177 records compiled
per minute to 16,585 records compiled per minute - an almost 4% performance degredation;
this is actually worse than I expected for a single conversion from malloc/init to
new/constructor with try/catch - I'll need to dig into this further.
>
> } catch (std::exception x) {
> 73a0: 48 89 e7 mov %rsp,%rdi
> 73a3: e8 30 e1 ff ff callq 54d8
><std::exception::~exception()@plt>
> 73a8: e8 7b dd ff ff callq 5128 <__cxa_end_catch@plt>
> 73ad: 0f 1f 00 nopl (%rax)
> 73b0: e9 41 01 00 00 jmpq 74f6
><c_uniline_dlp::echo(c_iocb*)+0x208>
> 73b5: 48 89 c5 mov %rax,%rbp
> 73b8: 48 89 e7 mov %rsp,%rdi
> 73bb: e8 18 e1 ff ff callq 54d8
><std::exception::~exception()@plt>
> 73c0: e8 63 dd ff ff callq 5128 <__cxa_end_catch@plt>
> 73c5: 48 89 ef mov %rbp,%rdi
> 73c8: e8 3b de ff ff callq 5208 <_Unwind_Resume@plt>
> return false;
> }
>
>hardly bloat! Now if the exception is caught higher up the call chain
>(with f() being a void function), there would be less, rather than more
>code.
40 bytes. more than half a cache line each occurance (and you really should
count the exception object constructor/destructors too). In some cases, it really matters.
And placing the catch higher in the call chain is not possible (at least not without
adding a large number of conditionals and carrying a great deal of state in
some derived exception class to the catch).
scott
[toc] | [prev] | [next] | [standalone]
| From | Miles Bader <miles@gnu.org> |
|---|---|
| Date | 2012-01-28 13:44 +0900 |
| Message-ID | <87d3a44es0.fsf@catnip.gol.com> |
| In reply to | #13619 |
scott@slp53.sl.home (Scott Lurndal) writes: >>The catch is also the reason for all the extra code, constructing and >>destructing a temporary std::exception object. The actual exception >>handling part of the code is this bit: > > Yet creating and destroying a temporary std::exception object also counts in > terms of both extra cycles and code footprint. Both of which impact > performance (generally negatively). Er, exceptions are intended to be _exceptional_. If some exception occurs so often that it has a measurable performance impact, it probably shouldn't be an exception. If you look at the code generated for the two styles, one of the big differences with the exception-using code is that the _normal_ case (where no exception is raised) is smaller and faster, since it can basically proceed without considering the exceptional case. The exception-handling code is out-of-line, to avoid a negative icache impact. [Also note that much "handling" of exceptions is not actually "reacting" to specific exceptions, but simply cleaning up and propagating an error; in C++, this typically happens via RAII (i.e. "unwind-protect" in lisp), or "catch(...)", and those have very low space overhead, as they do not need to do any kind of allocation/copying/matching; mostly they simply execute the user code to do whatever is needed.] -Miles -- Carefully crafted initial estimates reward you not only with reduced computational effort, but also with understanding and increased self-esteem. -- Numerical methods in C, Chapter 9. "Root Finding and Nonlinear Sets of Equations"
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2012-01-28 21:31 +0000 |
| Message-ID | <ROZUq.97141$ka3.2190@news.usenetserver.com> |
| In reply to | #13620 |
Miles Bader <miles@gnu.org> writes: >scott@slp53.sl.home (Scott Lurndal) writes: >>>The catch is also the reason for all the extra code, constructing and >>>destructing a temporary std::exception object. The actual exception >>>handling part of the code is this bit: >> >> Yet creating and destroying a temporary std::exception object also counts in >> terms of both extra cycles and code footprint. Both of which impact >> performance (generally negatively). > >Er, exceptions are intended to be _exceptional_. > >If some exception occurs so often that it has a measurable performance >impact, it probably shouldn't be an exception. The exception never occurs (i.e., I never run out of memory). It's the added code to handle the exception and it's effect on a (very) hot codepath that causes the 4% hit in performance. That is the only change in the codebase, and I ran the benchmark three times with each flavor (try/catch/new vs. malloc). I have to admit that I was surprised by the difference and I'm going to take a look at the actual codepaths and do some profiling to see why adding a try/catch clause has such a large effect, when the exception is never taken. scott
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2012-01-29 11:32 +1300 |
| Message-ID | <9ojbcpF8j0U13@mid.individual.net> |
| In reply to | #13631 |
On 01/29/12 10:31 AM, Scott Lurndal wrote: > Miles Bader<miles@gnu.org> writes: >> scott@slp53.sl.home (Scott Lurndal) writes: >>>> The catch is also the reason for all the extra code, constructing and >>>> destructing a temporary std::exception object. The actual exception >>>> handling part of the code is this bit: >>> >>> Yet creating and destroying a temporary std::exception object also counts in >>> terms of both extra cycles and code footprint. Both of which impact >>> performance (generally negatively). >> >> Er, exceptions are intended to be _exceptional_. >> >> If some exception occurs so often that it has a measurable performance >> impact, it probably shouldn't be an exception. > > The exception never occurs (i.e., I never run out of memory). It's the > added code to handle the exception and it's effect on a (very) hot codepath > that causes the 4% hit in performance. That is the only change in the > codebase, and I ran the benchmark three times with each flavor (try/catch/new > vs. malloc). I have to admit that I was surprised by the difference and I'm > going to take a look at the actual codepaths and do some profiling to see why > adding a try/catch clause has such a large effect, when the exception is never > taken. How about new (without the exceptions) compared to malloc? new is doing more work than malloc, one reason I suggested a specialised allocator. -- Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | 88888 Dihedral <dihedral88888@googlemail.com> |
|---|---|
| Date | 2012-01-28 14:55 -0800 |
| Message-ID | <15745250.325.1327791325896.JavaMail.geo-discussion-forums@prhs5> |
| In reply to | #13636 |
在 2012年1月29日星期日UTC+8上午6时32分57秒,Ian Collins写道: > On 01/29/12 10:31 AM, Scott Lurndal wrote: > > Miles Bader<mi...@gnu.org> writes: > >> scott@slp53.sl.home (Scott Lurndal) writes: > >>>> The catch is also the reason for all the extra code, constructing and > >>>> destructing a temporary std::exception object. The actual exception > >>>> handling part of the code is this bit: > >>> > >>> Yet creating and destroying a temporary std::exception object also counts in > >>> terms of both extra cycles and code footprint. Both of which impact > >>> performance (generally negatively). > >> > >> Er, exceptions are intended to be _exceptional_. > >> > >> If some exception occurs so often that it has a measurable performance > >> impact, it probably shouldn't be an exception. > > > > The exception never occurs (i.e., I never run out of memory). It's the > > added code to handle the exception and it's effect on a (very) hot codepath > > that causes the 4% hit in performance. That is the only change in the > > codebase, and I ran the benchmark three times with each flavor (try/catch/new > > vs. malloc). I have to admit that I was surprised by the difference and I'm > > going to take a look at the actual codepaths and do some profiling to see why > > adding a try/catch clause has such a large effect, when the exception is never > > taken. > > How about new (without the exceptions) compared to malloc? new is doing > more work than malloc, one reason I suggested a specialised allocator. > > -- > Ian Collins Well, an object with some methods to generate new objects not to be garbage collected very soon following the o stack push-pop mechnism of auto varibles are somewaht evil in C++ if the programmer does not think carefully and write codes to chain these methods in class B arbitrarily then there might be a definitely expoenti ally growth rate of the heap used by a lousy fat programming hog in some programs.
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2012-01-29 11:59 +1300 |
| Message-ID | <9ojcuqF8j0U15@mid.individual.net> |
| In reply to | #13638 |
On 01/29/12 11:55 AM, 88888 Dihedral wrote: > 在 2012年1月29日星期日UTC+8上午6时32分57秒,Ian Collins写道: >> On 01/29/12 10:31 AM, Scott Lurndal wrote: >>> Miles Bader<mi...@gnu.org> writes: >>>> scott@slp53.sl.home (Scott Lurndal) writes: >>>>>> The catch is also the reason for all the extra code, constructing and >>>>>> destructing a temporary std::exception object. The actual exception >>>>>> handling part of the code is this bit: >>>>> >>>>> Yet creating and destroying a temporary std::exception object also counts in >>>>> terms of both extra cycles and code footprint. Both of which impact >>>>> performance (generally negatively). >>>> >>>> Er, exceptions are intended to be _exceptional_. >>>> >>>> If some exception occurs so often that it has a measurable performance >>>> impact, it probably shouldn't be an exception. >>> >>> The exception never occurs (i.e., I never run out of memory). It's the >>> added code to handle the exception and it's effect on a (very) hot codepath >>> that causes the 4% hit in performance. That is the only change in the >>> codebase, and I ran the benchmark three times with each flavor (try/catch/new >>> vs. malloc). I have to admit that I was surprised by the difference and I'm >>> going to take a look at the actual codepaths and do some profiling to see why >>> adding a try/catch clause has such a large effect, when the exception is never >>> taken. >> >> How about new (without the exceptions) compared to malloc? new is doing >> more work than malloc, one reason I suggested a specialised allocator. > > Well, an object with some methods to generate new objects not to be garbage collected very soon following the o stack push-pop mechnism of auto varibles are somewaht evil in C++ if the programmer does not think carefully and write codes to chain these methods in class B arbitrarily then there might be a definitely expoenti ally growth rate of the heap used by a lousy fat programming hog in some programs. Do what? -- Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2012-01-30 17:08 +0000 |
| Message-ID | <g8AVq.191682$IC2.182329@news.usenetserver.com> |
| In reply to | #13636 |
Ian Collins <ian-news@hotmail.com> writes:
>On 01/29/12 10:31 AM, Scott Lurndal wrote:
>> Miles Bader<miles@gnu.org> writes:
>>> scott@slp53.sl.home (Scott Lurndal) writes:
>>>>> The catch is also the reason for all the extra code, constructing and
>>>>> destructing a temporary std::exception object. The actual exception
>>>>> handling part of the code is this bit:
>>>>
>>>> Yet creating and destroying a temporary std::exception object also counts in
>>>> terms of both extra cycles and code footprint. Both of which impact
>>>> performance (generally negatively).
>>>
>>> Er, exceptions are intended to be _exceptional_.
>>>
>>> If some exception occurs so often that it has a measurable performance
>>> impact, it probably shouldn't be an exception.
>>
>> The exception never occurs (i.e., I never run out of memory). It's the
>> added code to handle the exception and it's effect on a (very) hot codepath
>> that causes the 4% hit in performance. That is the only change in the
>> codebase, and I ran the benchmark three times with each flavor (try/catch/new
>> vs. malloc). I have to admit that I was surprised by the difference and I'm
>> going to take a look at the actual codepaths and do some profiling to see why
>> adding a try/catch clause has such a large effect, when the exception is never
>> taken.
>
>How about new (without the exceptions) compared to malloc? new is doing
>more work than malloc, one reason I suggested a specialised allocator.
>
I've tried using new (sans catch) and malloc both. The difference there is
pretty much in the noise. I've been planning on trying the gcc option -fcheck-new
with the 'new' to handle the case where new returns null (to prevent the constructor
from running) and compare that with malloc; this will add a test and
branch to the hot path, I suspect. If I use new (nothrow), will that still call
the constructor (and SIGSEGV) if the new returns NULL?
I ported a pool allocator over the weekend that can be used with an overloaded
new operator
void *operator new(size_t, c_pool *p) { return p->alloc(); }
The pool class uses ::mmap(MAP_ANONYMOUS) to get pages which are then subdivided
into appropriately sized chunks (16-byte aligned for efficiency on 64-bit
architectures).
c_pool *pool;
pool = new c_pool("Class Objects", sizeof(c_class), 100); // At init time
...
object = new (pool) c_class(); // at run time
This is highly efficient in the cases where you know a priori that you'll
never run out of pool elements (sans a coding error, of course).
A downside is you can't use delete but rather must pool->free(object).
scott
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2012-01-28 18:06 +1300 |
| Message-ID | <9ohe2qF8j0U9@mid.individual.net> |
| In reply to | #13619 |
On 01/28/12 05:18 PM, Scott Lurndal wrote:
> Ian Collins<ian-news@hotmail.com> writes:
>> On 01/28/12 10:26 AM, Scott Lurndal wrote:
>>> Ian Collins<ian-news@hotmail.com> writes:
>>>> On 01/28/12 09:29 AM, Scott Lurndal wrote:
>>>>>
>>>>>
>>>>> I tried substituting a 'new uint8[xx}' call to replace a malloc with a try
>>>>> catch block for bad_alloc. I then disassembled the code. One instruction
>>>>> (to test the return value of the malloc) turned into:
>>>>>
>>>>
>>>> How comes one version has multiple calls to new and the other one call
>>>> to malloc?
>>>>
>>>> What was the original source?
>>>>
>>>
>>> uint8 cmd = iocb->get_op_var2();
>>>
>>> buf = (uint8 *)malloc(bufsize);
>>> if (buf == NULL) {
>>> iocb->set_rd(IOT_WITH_EXCEPTIONS, RD1_OCS_MPU_PARITY);
>>> return false;
>>> }
>>>
>>> switch (cmd) {
>>>
>>> vs.
>>>
>>> uint8 cmd = iocb->get_op_var2();
>>>
>>> try {
>>> buf = new uint8[bufsize];
>>> } catch (std::exception e) {
>>
>> never catch exceptions by value, always catch by const reference to
>> avoid slicing.
>
> Good to know, I guess. Since I intend to keep the malloc and forgo
> the try/catch clause, the point is however moot.
But it is a typical novice error that leads to false assumptions
regarding exception performance.
>>
>>> iocb->set_rd(IOT_WITH_EXCEPTIONS, RD1_OCS_MPU_PARITY);
>>> return false;
>>> }
>>>
>>> switch (cmd) {
>>>
>>> There is only one call to operator new (at 732a), the source code
>>> is intermixed with the assembler by the 'objdump' utility and it replicated the source
>>> line in multiple places.
>>
>> This is fairly atypical use of exceptions, mixing exceptions and return
>> codes. It is more common to catch the exception at a higher call. This
>> simplifies the source and machine code (fewer conditional branches).
>
> However, in this case (modeling a physical device), the best determination
> of how to present the failure can be made as close to the cause of the
> exception as possible. I would think that for most applications that
> can actually recover from an error (as opposed to just catching std::exception
> at the top level, printing a message, and exiting), keeping the recovery action
> as close to the code that actually failed makes recovery much simpler.
It may well be, but the catch and the throw my still be several calls
away. Using nested small functions is much cleaner with exceptions than
with return codes. In your example you return the state in the object
passed. An exception based design may well pass the state in an
application specific exception.
>> The catch is also the reason for all the extra code, constructing and
>> destructing a temporary std::exception object. The actual exception
>> handling part of the code is this bit:
>
> Yet creating and destroying a temporary std::exception object also counts in
> terms of both extra cycles and code footprint. Both of which impact
> performance (generally negatively).
Only if the exceptional condition occurs. The normal path of execution
will not be impacted (and will be cleaner and faster than the error
checking case).
> And indeed, some simple performance testing of code running under the simulation
> (a 15,000 line BPL compile), shows that when I try exceptions in one of the common
> allocation paths, the performance of the BPL compile drops from 17,177 records compiled
> per minute to 16,585 records compiled per minute - an almost 4% performance degredation;
> this is actually worse than I expected for a single conversion from malloc/init to
> new/constructor with try/catch - I'll need to dig into this further.
If you are mixing exceptions and return codes, you aren't really making
a fair comparison. It is very likely you could improve the performance
in other ways, such as a specialised allocator. If your application was
designed to use exceptions throughout, I bet you would see a performance
improvement.
>>
>> } catch (std::exception x) {
>> 73a0: 48 89 e7 mov %rsp,%rdi
>> 73a3: e8 30 e1 ff ff callq 54d8
>> <std::exception::~exception()@plt>
>> 73a8: e8 7b dd ff ff callq 5128<__cxa_end_catch@plt>
>> 73ad: 0f 1f 00 nopl (%rax)
>> 73b0: e9 41 01 00 00 jmpq 74f6
>> <c_uniline_dlp::echo(c_iocb*)+0x208>
>> 73b5: 48 89 c5 mov %rax,%rbp
>> 73b8: 48 89 e7 mov %rsp,%rdi
>> 73bb: e8 18 e1 ff ff callq 54d8
>> <std::exception::~exception()@plt>
>> 73c0: e8 63 dd ff ff callq 5128<__cxa_end_catch@plt>
>> 73c5: 48 89 ef mov %rbp,%rdi
>> 73c8: e8 3b de ff ff callq 5208<_Unwind_Resume@plt>
>> return false;
>> }
>>
>> hardly bloat! Now if the exception is caught higher up the call chain
>> (with f() being a void function), there would be less, rather than more
>> code.
>
> 40 bytes. more than half a cache line each occurance (and you really should
> count the exception object constructor/destructors too). In some cases, it really matters.
No I shouldn't.
It only occurred in your code because you caught by valve. No exception
object is created unless one is thrown. I also quoted more code than I
should (because of the catch by value). Change your code to catch by
const reference and you will see. For example, a bare bones example
with gcc:
bool f( X* iocb ){
try {
uint8_t* buf = new uint8_t[bufsize];
return true;
}
catch (const std::exception& e) {
return false;
}
}
compiles to (removing some labels for brevity):
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $42, (%esp)
call _Znaj
movl $1, %eax
leave
ret
.L6:
subl $1, %edx
je .L4
movl %eax, (%esp)
call _Unwind_Resume
.L4:
movl %eax, (%esp)
call __cxa_begin_catch
call __cxa_end_catch
xorl %eax, %eax
leave
ret
> And placing the catch higher in the call chain is not possible (at least not without
> adding a large number of conditionals and carrying a great deal of state in
> some derived exception class to the catch).
The state has to be carried somewhere... If it is only required in the
case of an error, the exception is the logical place for it.
--
Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2012-01-28 22:49 +0000 |
| Message-ID | <0Y_Uq.11149$Jp3.8515@news.usenetserver.com> |
| In reply to | #13621 |
Ian Collins <ian-news@hotmail.com> writes:
>On 01/28/12 05:18 PM, Scott Lurndal wrote:
>> However, in this case (modeling a physical device), the best determination
>> of how to present the failure can be made as close to the cause of the
>> exception as possible. I would think that for most applications that
>> can actually recover from an error (as opposed to just catching std::exception
>> at the top level, printing a message, and exiting), keeping the recovery action
>> as close to the code that actually failed makes recovery much simpler.
>
>It may well be, but the catch and the throw my still be several calls
>away. Using nested small functions is much cleaner with exceptions than
>with return codes. In your example you return the state in the object
>passed. An exception based design may well pass the state in an
>application specific exception.
Which will have additional overhead to allocate, construct,
destroy and deallocate the application class derived from std::exception, nicht wahr?
I think you would find that "small nested functions" is exactly what is
used, and in this case, the object passed doesn't necessary _return_ the state
passed so much as provide a channel for returning the state to the final
receipient.
Now in the core processor simulation code sigsetjmp/siglongjmp are used to reset
the simulated processor to the start of the instruction processing loop when
an exception occurs executing an instruction (an address error, invalid instruction,
etc). These could possibly be converted to exceptions, but I'm quite sure that
the performance would be worse and the RAS characteristics of the application
wouldn't change appreciably.
I remember reading Tom Cargill's article on exceptions back when they were
introduced to the language - I think many of his points still apply - exceptions
are not a universal panacea and careful analysis of all codepaths need be done
to prevent memory leaks or access to deallocated data when exceptions are being
thrown. The same caveats, of course, apply to setjmp/longjmp as well, but I
don't need to allocate an exception object (just set one of 10 bits in a member
field of the current 'this' when the longjmp is issued; the jmp_buf also a member
of the current object).
>
>>> The catch is also the reason for all the extra code, constructing and
>>> destructing a temporary std::exception object. The actual exception
>>> handling part of the code is this bit:
>>
>> Yet creating and destroying a temporary std::exception object also counts in
>> terms of both extra cycles and code footprint. Both of which impact
>> performance (generally negatively).
>
>Only if the exceptional condition occurs. The normal path of execution
>will not be impacted (and will be cleaner and faster than the error
>checking case).
I haven't seen this in practice, but then my sole exposure to C++ code
has been in the Operating Systems/Microkernel/Hypervisor area none of which
used exceptions (most of which predated exceptions :-), aside from one
application at a major internet certification authority, which also predated
exceptions.
>
>> And indeed, some simple performance testing of code running under the simulation
>> (a 15,000 line BPL compile), shows that when I try exceptions in one of the common
>> allocation paths, the performance of the BPL compile drops from 17,177 records compiled
>> per minute to 16,585 records compiled per minute - an almost 4% performance degredation;
>> this is actually worse than I expected for a single conversion from malloc/init to
>> new/constructor with try/catch - I'll need to dig into this further.
>
>If you are mixing exceptions and return codes, you aren't really making
>a fair comparison. It is very likely you could improve the performance
>in other ways, such as a specialised allocator. If your application was
>designed to use exceptions throughout, I bet you would see a performance
>improvement.
Unfortunately, this is a 60,000+ SLOC application and making such a change
wouldn't be useful - there are only a half dozen or so dynamic allocations
in the entire application, and I'm working on eliminating most of those
(or moving them to the application initialization phase).
Let me be clear, I never actually took an exception in the test I described above;
the sole difference was changing the
buf = malloc(XXX); if (buf == NULL) { YYY}
test to
try {buf = new uint8[XXX];} catch (std::exception& e) { YYY }
(and of course, the corresponding 'free()' <-> 'delete []' changes).
The exception was never thrown during the test (but the test function was called
about 500,000 times while the processor code simulated 43,000,000 mainframe instructions)
over a wall-time duration of about 25 seconds.
Since there is a hard (and relatively small) limit on the number of objects of
the type in the test that can be allocated during a run (basically one per simulated
processor and a couple of extras), I plan on overloading operator new for the
object and using a startup-allocated pool of objects to handle object allocation. This
will eliminate both checks.
Similar mechanisms will be used for all other run-time (vs. initialization time)
allocations.
scott
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2012-01-29 12:22 +1300 |
| Message-ID | <9ojea4F8j0U16@mid.individual.net> |
| In reply to | #13637 |
On 01/29/12 11:49 AM, Scott Lurndal wrote:
> Ian Collins<ian-news@hotmail.com> writes:
>> On 01/28/12 05:18 PM, Scott Lurndal wrote:
>
>>> However, in this case (modeling a physical device), the best determination
>>> of how to present the failure can be made as close to the cause of the
>>> exception as possible. I would think that for most applications that
>>> can actually recover from an error (as opposed to just catching std::exception
>>> at the top level, printing a message, and exiting), keeping the recovery action
>>> as close to the code that actually failed makes recovery much simpler.
>>
>> It may well be, but the catch and the throw my still be several calls
>> away. Using nested small functions is much cleaner with exceptions than
>> with return codes. In your example you return the state in the object
>> passed. An exception based design may well pass the state in an
>> application specific exception.
>
> Which will have additional overhead to allocate, construct,
> destroy and deallocate the application class derived from std::exception, nicht wahr?
Only in the exceptional circumstances where one is thrown. As I said,
the state has to be returned somewhere.
> I think you would find that "small nested functions" is exactly what is
> used, and in this case, the object passed doesn't necessary _return_ the state
> passed so much as provide a channel for returning the state to the final
> receipient.
>
> Now in the core processor simulation code sigsetjmp/siglongjmp are used to reset
> the simulated processor to the start of the instruction processing loop when
> an exception occurs executing an instruction (an address error, invalid instruction,
> etc). These could possibly be converted to exceptions, but I'm quite sure that
> the performance would be worse and the RAS characteristics of the application
> wouldn't change appreciably.
By using exceptions, you are able to utilise the full power of the
language, such as RAII which out of band jumps preclude.
One point I have been trying to make is bolting exceptions onto an
existing design is seldom a good idea. Neither is having to take them
out, which was a situation I once found myself in! Error handling is a
fundamental part of a system's design and mixing paradigms invariably
ends in tears.
> I remember reading Tom Cargill's article on exceptions back when they were
> introduced to the language - I think many of his points still apply - exceptions
> are not a universal panacea and careful analysis of all codepaths need be done
> to prevent memory leaks or access to deallocated data when exceptions are being
> thrown.
This is true and the language provides us with the tools to achieve
this. Tools which cannot be used with out of band jumps!
> The same caveats, of course, apply to setjmp/longjmp as well, but I
> don't need to allocate an exception object (just set one of 10 bits in a member
> field of the current 'this' when the longjmp is issued; the jmp_buf also a member
> of the current object).
The cost of constructing an exception object are far outweighed by the
cost of throwing it *in the exceptional case*.
>>>> The catch is also the reason for all the extra code, constructing and
>>>> destructing a temporary std::exception object. The actual exception
>>>> handling part of the code is this bit:
>>>
>>> Yet creating and destroying a temporary std::exception object also counts in
>>> terms of both extra cycles and code footprint. Both of which impact
>>> performance (generally negatively).
>>
>> Only if the exceptional condition occurs. The normal path of execution
>> will not be impacted (and will be cleaner and faster than the error
>> checking case).
>
> I haven't seen this in practice, but then my sole exposure to C++ code
> has been in the Operating Systems/Microkernel/Hypervisor area none of which
> used exceptions (most of which predated exceptions :-), aside from one
> application at a major internet certification authority, which also predated
> exceptions.
That's where our experiences diverge, I've been comparing the
performance of exceptions on various platforms for many years and I've
found exceptions are generally faster (always on the Unix and Linux
platforms I use). From my perspective, the exceptions vs error returns
argument was settled long ago.
> Let me be clear, I never actually took an exception in the test I described above;
> the sole difference was changing the
>
> buf = malloc(XXX); if (buf == NULL) { YYY}
>
> test to
>
> try {buf = new uint8[XXX];} catch (std::exception& e) { YYY }
>
> (and of course, the corresponding 'free()'<-> 'delete []' changes).
You have introduced two variables, exceptions and new. Try eliminating
both.
--
Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2012-01-27 20:16 +0000 |
| Message-ID | <MCDUq.107191$487.97@news.usenetserver.com> |
| In reply to | #13604 |
Ian Collins <ian-news@hotmail.com> writes: >On 01/27/12 09:55 AM, Scott Lurndal wrote: >> Cholo Lennon<chololennon@hotmail.com> writes: >>> On 26/01/2012 16:24, Scott Lurndal wrote: >>>> The readability of C++ seems to get worse with each new version of the >>>> standard. Once the<XXX> elements (static/dynamic casts, templates) were added >>>> to the language, it became worse than perl for readability. >>> >>> Really? Do you think C++ cast operators go against readability? For me >>> is the opposite: At glance, for example, they give you more information >>> than the traditional C cast and, as a result, they are (IMHO) more readable. >>> >> >> Buenas, >> >> I think they may provide better _maintainability_ at the expense of _readability_. >> >> It may also be that for someone coming from a C background (starting in 1978), >> the dynamic/static cast syntax just looks alien and out of place. >> >> Templates and exceptions on the other hand, have a distinct impact on code size >> (thus icache footprint, thus performance). > >The only performance impact I have ever measured from the use of >exceptions is improvement. I have been testing compilers since the mid >90s and I have only found one compiler/platform (that compiler refused >to inline any function that could throw) where exceptions had a >detrimental impact on performance. > >In overall performance terms, templates are no worse and often a >significant improvement over the direct C equivalent (macros) because >they aren't necessary inlined. They can also provide significant >performance improvements over another C alternative, the use of void* >and function pointers (sorting being the classic example). > >Yes you can end up with multiple instances of class methods, but that is >the price you pay for type safety. Anyway, what proportion of a decent >sized project would that represent? For containers of pointers one can >easily use inline wrappers round a container of void* to avoid bloat >while retaining type safety. In most code I have seen, containers of T* >are more numerous than containers of T > >Thus with contemporary tools, the twin myths of exception performance >and template code bloat are just that: myths. Unless you are writing an operating system or hypervisor where every byte counts. scott
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2012-01-28 10:01 +1300 |
| Message-ID | <9oghluF8j0U3@mid.individual.net> |
| In reply to | #13609 |
On 01/28/12 09:16 AM, Scott Lurndal wrote: > Ian Collins<ian-news@hotmail.com> writes: >> On 01/27/12 09:55 AM, Scott Lurndal wrote: >>> Cholo Lennon<chololennon@hotmail.com> writes: >>>> On 26/01/2012 16:24, Scott Lurndal wrote: >>>>> The readability of C++ seems to get worse with each new version of the >>>>> standard. Once the<XXX> elements (static/dynamic casts, templates) were added >>>>> to the language, it became worse than perl for readability. >>>> >>>> Really? Do you think C++ cast operators go against readability? For me >>>> is the opposite: At glance, for example, they give you more information >>>> than the traditional C cast and, as a result, they are (IMHO) more readable. >>>> >>> >>> Buenas, >>> >>> I think they may provide better _maintainability_ at the expense of _readability_. >>> >>> It may also be that for someone coming from a C background (starting in 1978), >>> the dynamic/static cast syntax just looks alien and out of place. >>> >>> Templates and exceptions on the other hand, have a distinct impact on code size >>> (thus icache footprint, thus performance). >> >> The only performance impact I have ever measured from the use of >> exceptions is improvement. I have been testing compilers since the mid >> 90s and I have only found one compiler/platform (that compiler refused >> to inline any function that could throw) where exceptions had a >> detrimental impact on performance. >> >> In overall performance terms, templates are no worse and often a >> significant improvement over the direct C equivalent (macros) because >> they aren't necessary inlined. They can also provide significant >> performance improvements over another C alternative, the use of void* >> and function pointers (sorting being the classic example). >> >> Yes you can end up with multiple instances of class methods, but that is >> the price you pay for type safety. Anyway, what proportion of a decent >> sized project would that represent? For containers of pointers one can >> easily use inline wrappers round a container of void* to avoid bloat >> while retaining type safety. In most code I have seen, containers of T* >> are more numerous than containers of T >> >> Thus with contemporary tools, the twin myths of exception performance >> and template code bloat are just that: myths. > > Unless you are writing an operating system or hypervisor where every byte > counts. A large proportion of my work is in embedded devices, where the byte count is even more important! These days of low cost, plentiful RAM, the most important factor in hypervisor or operating system is performance, not code size. As I said above, if code size is an an issue, there are well known coding practices that can be employed to minimise it. There are also techniques used by embedded tool chains to minimise code size. However more often than not these techniques are detrimental to performance and should only be employed when physical resources are tight. -- Ian Collins
[toc] | [prev] | [next] | [standalone]
| From | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| Date | 2012-01-28 16:00 +0000 |
| Message-ID | <4f241b9b$0$3110$7b1e8fa0@news.nbl.fi> |
| In reply to | #13595 |
Scott Lurndal <scott@slp53.sl.home> wrote: > The readability of C++ seems to get worse with each new version of the > standard. Once the <XXX> elements (static/dynamic casts, templates) were added > to the language, it became worse than perl for readability. I believe you are confusing readability with brevity. Not the same thing.
[toc] | [prev] | [next] | [standalone]
| From | Jorgen Grahn <grahn+nntp@snipabacken.se> |
|---|---|
| Date | 2012-01-10 21:42 +0000 |
| Message-ID | <slrnjgpc62.1ls.grahn+nntp@frailea.sa.invalid> |
| In reply to | #13209 |
On Tue, 2012-01-10, AD wrote:
> I kid you not, I found this trash in a real project:
>
> //Remove texture from the the stack and try to unload from memory
> void resourceManager::popTexture(const char* nickName)
> {
> BOOL removed = false;
> for (std::vector<texture*>::iterator itr = textures.begin(); itr !=
> textures.end();)
> {
> if ( (*itr)->nickName == nickName )
> {
I don't see anything unusually bad about it. I assume there's a itr++
elsewhere, and that texture::nickName is a std::string.
/Jorgen
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
[toc] | [prev] | [next] | [standalone]
Page 4 of 5 — ← Prev page 1 2 3 [4] 5 Next page →
Back to top | Article view | comp.lang.c++
csiph-web