GCC Summit 2010 slides are available at
http://gcc.gnu.org/wiki/summit2010
Saturday, October 30, 2010
Friday, October 22, 2010
top failed ro read /proc/stat
Just noticed that top utiliy fails to read /proc/stat after
cpu offline.
The problem is that Cpu_tot is not updated before calling
cpus_refresh.
In cpus_refresh we're trying to read and sscanf Cpu_tot times /proc/stat
for (i = 0; 1 < Cpu_tot && i < Cpu_tot; i++) {
if (!fgets(buf, sizeof(buf), fp)) std_err("failed /proc/stat read");
cpus[i].x = 0; // FIXME: can't tell by kernel version number
cpus[i].y = 0; // FIXME: can't tell by kernel version number
cpus[i].z = 0; // FIXME: can't tell by kernel version number
num = sscanf(buf, "cpu%u %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu",
&cpus[i].id,
&cpus[i].u, &cpus[i].n, &cpus[i].s, &cpus[i].i, &cpus[i].w, &cpus[i].x, &cpus[i].y, &cpus[i].z
);
if (num < 4)
std_err("failed /proc/stat read");
}
Which is wrong, since:
cat /proc/stat
cpu 5700 0 1474 271836 3554 0 41 0 0 0
cpu0 2167 0 565 66945 974 0 13 0 0 0
cpu1 2600 0 507 66512 1030 0 11 0 0 0
cpu2 518 0 214 69082 810 0 5 0 0 0
cpu3 413 0 186 69296 738 0 9 0 0 0
intr ....
echo 0 > /sys/devices/system/cpu/cpu3/online
cat /proc/stat
cpu 5831 0 1531 292475 3592 0 43 0 0 0
cpu0 2236 0 591 72477 979 0 14 0 0 0
cpu1 2647 0 531 72052 1051 0 12 0 0 0
cpu2 527 0 217 74713 821 0 6 0 0 0
intr ...
(note absent cpu3 line).
The solution may look similar to this one:
smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
if(smp_num_cpus<1) smp_num_cpus=1;
Cpu_tot = smp_num_cpus;
Before cpus_refresh call.
cpu offline.
The problem is that Cpu_tot is not updated before calling
cpus_refresh.
In cpus_refresh we're trying to read and sscanf Cpu_tot times /proc/stat
for (i = 0; 1 < Cpu_tot && i < Cpu_tot; i++) {
if (!fgets(buf, sizeof(buf), fp)) std_err("failed /proc/stat read");
cpus[i].x = 0; // FIXME: can't tell by kernel version number
cpus[i].y = 0; // FIXME: can't tell by kernel version number
cpus[i].z = 0; // FIXME: can't tell by kernel version number
num = sscanf(buf, "cpu%u %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu",
&cpus[i].id,
&cpus[i].u, &cpus[i].n, &cpus[i].s, &cpus[i].i, &cpus[i].w, &cpus[i].x, &cpus[i].y, &cpus[i].z
);
if (num < 4)
std_err("failed /proc/stat read");
}
Which is wrong, since:
cat /proc/stat
cpu 5700 0 1474 271836 3554 0 41 0 0 0
cpu0 2167 0 565 66945 974 0 13 0 0 0
cpu1 2600 0 507 66512 1030 0 11 0 0 0
cpu2 518 0 214 69082 810 0 5 0 0 0
cpu3 413 0 186 69296 738 0 9 0 0 0
intr ....
echo 0 > /sys/devices/system/cpu/cpu3/online
cat /proc/stat
cpu 5831 0 1531 292475 3592 0 43 0 0 0
cpu0 2236 0 591 72477 979 0 14 0 0 0
cpu1 2647 0 531 72052 1051 0 12 0 0 0
cpu2 527 0 217 74713 821 0 6 0 0 0
intr ...
(note absent cpu3 line).
The solution may look similar to this one:
smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
if(smp_num_cpus<1) smp_num_cpus=1;
Cpu_tot = smp_num_cpus;
Before cpus_refresh call.
Thursday, October 21, 2010
Mutt 1.5.21 mail_check_recent option
Updated to mutt 1.5.21 recently and one change really was annoying me so far.
Mutt doesn't mark recently visited folder with 'N' (new message) until it
receives new message... even if there are unread messages.
Quick look at mutt 1.5.21 source code gave the following result:
Gotcha! Quick grep:
Corresponding lines in change log (diff 1.5.20 - 1.5.21)
The solution is to add
unset mail_check_recent
to .muttrc
Why...
Mutt doesn't mark recently visited folder with 'N' (new message) until it
receives new message... even if there are unread messages.
Quick look at mutt 1.5.21 source code gave the following result:
/* returns 1 if maildir has new mail */
static int buffy_maildir_hasnew (BUFFY* mailbox)
{
char path[_POSIX_PATH_MAX];
DIR *dirp;
struct dirent *de;
char *p;
int rc = 0;
struct stat sb;
snprintf (path, sizeof (path), "%s/new", mailbox->path);
/* when $mail_check_recent is set, if the new/ directory hasn't been modified since
* the user last exited the mailbox, then we know there is no recent mail.
*/
if (option(OPTMAILCHECKRECENT))
{
if (stat(path, &sb) == 0 && sb.st_mtime < mailbox->last_visited)
return 0;
}
if ((dirp = opendir (path)) == NULL)
{
mailbox->magic = 0;
return 0;
}
while ((de = readdir (dirp)) != NULL)
{
if (*de->d_name == '.')
continue;
if (!(p = strstr (de->d_name, ":2,")) || !strchr (p + 3, 'T'))
{
if (option(OPTMAILCHECKRECENT))
{
char msgpath[_POSIX_PATH_MAX];
snprintf(msgpath, sizeof(msgpath), "%s/%s", path, de->d_name);
/* ensure this message was received since leaving this mailbox */
if (stat(msgpath, &sb) == 0 && (sb.st_ctime <= mailbox->last_visited))
continue;
}
/* one new and undeleted message is enough */
mailbox->new = 1;
rc = 1;
break;
}
}
closedir (dirp);
return rc;
}
static int buffy_maildir_hasnew (BUFFY* mailbox)
{
char path[_POSIX_PATH_MAX];
DIR *dirp;
struct dirent *de;
char *p;
int rc = 0;
struct stat sb;
snprintf (path, sizeof (path), "%s/new", mailbox->path);
/* when $mail_check_recent is set, if the new/ directory hasn't been modified since
* the user last exited the mailbox, then we know there is no recent mail.
*/
if (option(OPTMAILCHECKRECENT))
{
if (stat(path, &sb) == 0 && sb.st_mtime < mailbox->last_visited)
return 0;
}
if ((dirp = opendir (path)) == NULL)
{
mailbox->magic = 0;
return 0;
}
while ((de = readdir (dirp)) != NULL)
{
if (*de->d_name == '.')
continue;
if (!(p = strstr (de->d_name, ":2,")) || !strchr (p + 3, 'T'))
{
if (option(OPTMAILCHECKRECENT))
{
char msgpath[_POSIX_PATH_MAX];
snprintf(msgpath, sizeof(msgpath), "%s/%s", path, de->d_name);
/* ensure this message was received since leaving this mailbox */
if (stat(msgpath, &sb) == 0 && (sb.st_ctime <= mailbox->last_visited))
continue;
}
/* one new and undeleted message is enough */
mailbox->new = 1;
rc = 1;
break;
}
}
closedir (dirp);
return rc;
}
Gotcha! Quick grep:
{"mail_check_recent",DT_BOOL, R_NONE, OPTMAILCHECKRECENT, 1 },
When set, Mutt will only notify you about new mail that has been received
since the last time you opened the mailbox. When unset, Mutt will notify
you if any new mail exists in the mailbox, regardless of whether you have
visited it recently.
Corresponding lines in change log (diff 1.5.20 - 1.5.21)
2010-09-13 17:25 -0700 Michael Elkins (20b2d496349f)
* init.h: make $mail_check_recent set by default
The solution is to add
unset mail_check_recent
to .muttrc
Why...
Glibc: moving forward to gcc-4.6
Glibc: moving forward to gcc-4.6
http://www.linuxselfhelp.com/gnu/glibc/html_chapter/libc_20.html
Author: Ulrich Drepper
Date: Tue Oct 19 12:56:42 2010 -0400
Provide FP_FAST_FMA{,F,L} definitions for x86/x86-64.
diff --git a/sysdeps/x86_64/bits/mathdef.h b/sysdeps/x86_64/bits/mathdef.h
index 7b16189..9146392 100644
--- a/sysdeps/x86_64/bits/mathdef.h
+++ b/sysdeps/x86_64/bits/mathdef.h
[..]
+/* The GCC 4.6 compiler will define __FP_FAST_FMA{,F,L} if the fma{,f,l}
+ builtins are supported. */
+# if __FP_FAST_FMA
+# define FP_FAST_FMA 1
+# endif
+
+# if __FP_FAST_FMAF
+# define FP_FAST_FMAF 1
+# endif
+
+# if __FP_FAST_FMAL
+# define FP_FAST_FMAL 1
+# endif
+
#endif /* ISO C99 */
http://www.linuxselfhelp.com/gnu/glibc/html_chapter/libc_20.html
On processors which do not implement multiply-add in hardware,fmacan be very slow since it must avoid intermediate rounding. `math.h' defines the symbolsFP_FAST_FMA,FP_FAST_FMAF, andFP_FAST_FMALwhen the corresponding version offmais no slower than the expression `x*y + z'. In the GNU C library, this always means the operation is implemented in hardware.
Tuesday, October 19, 2010
wired: "Oct. 14, 1985: C++ Adds to Programming"
Interview with Bjarne Stroustrup (C++ is 25... a bit outdated).
Full story via wired.com
Wired.com: Most programmers are particular about the music they listen to while coding or writing. What do you listen to?...
Stroustrup: Tchaikovsky’s Fifth, Wagner’s The Ring Without Words, Grieg’s Peer Gynt Suite, Sibelius, Nielsen’s The Inextinguishable, various Mozart concertos, The Dixie Chicks, Beatles’ Abbey Road, Handel’s Messiah and Water Music, Eric Clapton, Beethoven’s Fifth and Seventh. I looked to see what my laptop had been playing lately.
Wired.com: Any advice for young programmers?
Stroustrup: I guess giving advice is easy compared to taking it. Know your fundamentals (algorithms, data structures, machine architecture, systems) and know several programming languages to the point where you can use them idiomatically.Know some non-computer field of study well — math, biology, history, optics, whatever. Learn to communicate effectively in speech and in writing. Spend an unreasonable amount of time on some difficult topic to really master it. Try to do something that might make a difference in the world.
Full story via wired.com
Tuesday, October 12, 2010
Sunday, October 10, 2010
Wednesday, September 29, 2010
delete null pointer
Hi,
iso c++ 03
5.3
c++0x
5.3
iso c++ 03
5.3
/2 ... if the value of the operand of delete is the null pointer the
operation has no effect.
/7 The delete-expression will call a deallocation function (3.7.3.2).
c++0x
5.3
/2 ... the value of the operand of delete may be a null pointer value.
/7 If the value of the operand of the delete-expression is not a
null pointer value, the delete-expression will call a deallocation
function (3.7.4.2). Otherwise, it is unspecified whether the
deallocation function will be called. [ Note: The deallocation
function is called regardless of whether the destructor for the
object or some element of the array throws an exception. -- end note ]
Wednesday, September 22, 2010
Benford's law
Interesting article in wikipedia.
Benford's law
The distribution is as follows:
Is it useful? Yep.
So, whenever you're about to fake some data - use digits between 5 and 9
carefully. You've been warned.
Benford's law
Benford's law, also called the first-digit law, states that in lists of
numbers from many (but not all) real-life sources of data, the leading
digit is distributed in a specific, non-uniform way. According to this
law, the first digit is 1 almost one third of the time, and larger
digits occur as the leading digit with lower and lower frequency, to the
point where 9 as a first digit occurs less than one time in twenty.
The distribution is as follows:
1 30.1%
2 17.6%
3 12.5%
4 9.7%
5 7.9%
6 6.7%
7 5.8%
8 5.1%
9 4.6%
Is it useful? Yep.
Following this idea, Mark Nigrini showed that Benford's law could be used
as an indicator of accounting and expenses fraud.
In the United States, evidence based on Benford's law is legally admissible
in criminal cases at the federal, state, and local levels.
So, whenever you're about to fake some data - use digits between 5 and 9
carefully. You've been warned.
Miklos Szeredi: memory barrier question
Miklos Szeredi posted a question about memory barriers (lkml).
Which lead to an interesting discussion on memory barriers, compilers
and the Universe.
Please read lkml.org/lkml/2010/9/15/223
Which lead to an interesting discussion on memory barriers, compilers
and the Universe.
Please read lkml.org/lkml/2010/9/15/223
Thursday, September 16, 2010
ext4 regression
Hello,
Commit 66e61a9e9504f61b9a928c9055368c81da613a50 intorduced
ext4: Once a day, printk file system error information to dmesg
via kernel timer.
Error report may look like
[ 313.485876] EXT4-fs (sda6): error count: 13
[ 313.485887] EXT4-fs (sda6): initial error at 1283093815: ext4_lookup:1052: inode 4980737
[ 313.485895] EXT4-fs (sda6): last error at 1283094174: ext4_lookup:1052: inode 4980737
and I find it quite useful.
Sad but true - calling print_daily_error_info (by timer event)
on umounted fs will cause NULL pointer derefernce on superblock inode
(EXT4_SB(sb) returns NULL) resulting in OOPS (fatal error during
soft IRQ).
Stack trace will look similar to this one:
(lots of helpfull info cut)
IRQ
run_timer_softirq
?run_timer_softirq
?print_daily_error_info
?__do_softirq
__do_softirq
call_softirq
do_softirq
irq_exit
smp_apic_timer_interrupt
apic_timer_interrupt
EOI
intel_idle
intel_idel
cpuidle_idle_call
cpu_idle
start_secondary
And the solution is:
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 2614774..751997d 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -719,6 +719,7 @@ static void ext4_put_super(struct super_block *sb)
ext4_abort(sb, "Couldn't clean up the journal");
}
+ del_timer(&sbi->s_err_report);
ext4_release_system_zone(sb);
ext4_mb_release(sb);
ext4_ext_release(sb);
Ted Ts'o wrote:
I had some concerns about print_daily_error_info.
Ted Ts'o answered:
YAAYYY!
Commit 66e61a9e9504f61b9a928c9055368c81da613a50 intorduced
ext4: Once a day, printk file system error information to dmesg
via kernel timer.
Error report may look like
[ 313.485876] EXT4-fs (sda6): error count: 13
[ 313.485887] EXT4-fs (sda6): initial error at 1283093815: ext4_lookup:1052: inode 4980737
[ 313.485895] EXT4-fs (sda6): last error at 1283094174: ext4_lookup:1052: inode 4980737
and I find it quite useful.
Sad but true - calling print_daily_error_info (by timer event)
on umounted fs will cause NULL pointer derefernce on superblock inode
(EXT4_SB(sb) returns NULL) resulting in OOPS (fatal error during
soft IRQ).
Stack trace will look similar to this one:
(lots of helpfull info cut)
IRQ
run_timer_softirq
?run_timer_softirq
?print_daily_error_info
?__do_softirq
__do_softirq
call_softirq
do_softirq
irq_exit
smp_apic_timer_interrupt
apic_timer_interrupt
EOI
intel_idle
intel_idel
cpuidle_idle_call
cpu_idle
start_secondary
And the solution is:
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 2614774..751997d 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -719,6 +719,7 @@ static void ext4_put_super(struct super_block *sb)
ext4_abort(sb, "Couldn't clean up the journal");
}
+ del_timer(&sbi->s_err_report);
ext4_release_system_zone(sb);
ext4_mb_release(sb);
ext4_ext_release(sb);
Ted Ts'o wrote:
Good catch! Thanks for the patch. I will include this into ext4
tree, and I will probably push it separately to Linus so that it gets
into 2.6.36, since this is a regresssion.
I had some concerns about print_daily_error_info.
> By the way, isn't print_daily_error_info racy? Is it safe to call
> print_daily_error_info
> (by timer event (softirq)) when we're remounting fs, etc.?
Ted Ts'o answered:
It should be fine. Remounting doesn't actually change out the struct
superblock. There is a chance that the information might not be fully
complete if an error is printed exactly as the same time as
print_daily_error_info() is run, but I'm not sure it's worth trying to
protect against that race, since the worst that this will mean is a
confusing report in the /var/log/messages file, and the ext4 error
message will be printed right next to it, which will have all of the
information the system administrator will need.
YAAYYY!
Wednesday, September 15, 2010
const iterators for elements removal
Q: Adam Badura
A: Bo Persson
A: Daniel Krügler
via comp.lang.c++.moderated.
What is the point of const iterators being unusable for elementsI mean that if I have a const collection object then no matter what
removal?
iterators I have I will not be able to erase any element. But if I
have a non-const collection object then why am I not allowed to erase
its elements with a const iterator? After all I could as well take new
non-const begin and advance it until it is equal to the const iterator
and use such iterator for erasure.
A: Bo Persson
You are right, this will be fixed in the next standard, C++0x.
A: Daniel Krügler
Perfectly right - therefore the Standard Library has fixed this
awful state by accepting LWG issue: lwg-defects
It is the constness of the container which should control whether it can be modified through a
member function such as erase(), not the constness of the iterators.
via comp.lang.c++.moderated.
Tuesday, September 14, 2010
"We no longer support gcc 3.x, so remove the workaround for it."
H. Peter Anvin wrote:
[PATCH 1/5] Disallow building with gcc < 3.4
[PATCH 2/5] x86, gcc: Disallow building Linux/x86 with gcc 3.x/4.0
[PATCH 3/5] x86, cpu: Remove gcc 3.x workarounds in
[PATCH 4/5] x86, mem: Remove gcc < 4.1 support code for memcpy()
[PATCH 5/5] x86, bitops: Remove gcc < 4.1 workaround
We no longer support gcc 3.x, so remove the workaround for it.
[PATCH 1/5] Disallow building with gcc < 3.4
[PATCH 2/5] x86, gcc: Disallow building Linux/x86 with gcc 3.x/4.0
[PATCH 3/5] x86, cpu: Remove gcc 3.x workarounds in
[PATCH 4/5] x86, mem: Remove gcc < 4.1 support code for memcpy()
[PATCH 5/5] x86, bitops: Remove gcc < 4.1 workaround
This patchset bumps the minimum supported gcc version to 3.4 for the
general kernel, and to 4.1 for x86.
Please read lkml.org/lkml/2010/9/13/464 and http://lkml.org/lkml/2010/9/13/73
Thursday, September 9, 2010
it's possible that there won't be any 2.4.37.11 at all
Willy Tarreau wrote:
Please read lkml.org message.
Some of you have noticed that the last update was released 7 months ago. This is long, but these days, very few of the issues reported on 2.6 also affect 2.4, so basically the number of bug reports on 2.4 fades out quite fast.
So I'm releasing 2.4.37.10 here. If nothing happens before September 2011, it's possible that there won't be any 2.4.37.11 at all. By that time, the 2.6 kernel will have been available for almost 8 years, this should have been enough for anyone to have a look at it. Users now have one year to migrate or to report critical bugs.
At one point, I envisaged to start a 2.4.38 with a bunch of updated drivers. Now I'd prefer that the users migrate to 2.6.
Please read lkml.org message.
Wednesday, September 1, 2010
The cost of static
Hi,
gcc-4.5.1
suppose we have very simple and dumb code:
void save_state(int i) {
static int _foo_i = i + 0x09;
static int _foo_j = i;
}
g++ -O2 will give us:
4005c0 <+0>: cmpb $0x0,0x200491(%rip) # 0x600a58 <_ZGVZ10save_stateiE6_foo_i>
4005c7 <+7>: push %rbx
4005c8 <+8>: mov %edi,%ebx
4005ca <+10>: je 0x400600 <_Z10save_statei+64>
4005cc <+12>: cmpb $0x0,0x20048d(%rip) # 0x600a60 <_ZGVZ10save_stateiE6_foo_j>
4005d3 <+19>: je 0x4005e0 <_Z10save_statei+32>
4005d5 <+21>: pop %rbx
4005d6 <+22>: retq
4005d7 <+23>: nopw 0x0(%rax,%rax,1)
4005e0 <+32>: mov $0x600a60,%edi
4005e5 <+37>: callq 0x4004a0 <__cxa_guard_acquire@plt>
4005ea <+42>: test %eax,%eax
4005ec <+44>: je 0x4005d5 <_Z10save_statei+21>
4005ee <+46>: mov %ebx,0x200474(%rip) # 0x600a68 <_ZZ10save_stateiE6_foo_j>
4005f4 <+52>: mov $0x600a60,%edi
4005f9 <+57>: pop %rbx
4005fa <+58>: jmpq 0x4004c0 <__cxa_guard_release@plt>
4005ff <+63>: nop
400600 <+64>: mov $0x600a58,%edi
400605 <+69>: callq 0x4004a0 <__cxa_guard_acquire@plt>
40060a <+74>: test %eax,%eax
40060c <+76>: je 0x4005cc <_Z10save_statei+12>
40060e <+78>: lea 0x9(%rbx),%eax
400611 <+81>: mov $0x600a58,%edi
400616 <+86>: mov %eax,0x200450(%rip) # 0x600a6c <_ZZ10save_stateiE6_foo_i>
40061c <+92>: callq 0x4004c0 <__cxa_guard_release@plt>
400621 <+97>: jmp 0x4005cc <_Z10save_statei+12>
First of all we're checking global _ZGVZ10save_stateiE6_foo_i to see whether local
_ZZ10save_stateiE6_foo_i has been initialized with default value (and by the way to
protect it).
After all those crazy do_lookup_x, _dl_name_match_p, check_match.10800, _dl_lookup_symbol_x, etc.
we have
0x00007ffff7b913a3 <+179>: movb $0x1,0x1(%rdi)
in __cxa_guard_acquire, which sets our global _ZGVZ10save_stateiE6_foo_i to:
0x600a58 <_ZGVZ10save_stateiE6_foo_i>: 0x00000100
and
0x00007ffff7b91459 <+57>: movb $0x0,0x1(%rdi)
0x00007ffff7b9145d <+61>: movb $0x1,(%rdi)
in __cxa_guard_release which sets _ZGVZ10save_stateiE6_foo_i to:
0x600a58 <_ZGVZ10save_stateiE6_foo_i>: 0x00000001
g++ -Os will give us:
4005b4 <+0>: cmpb $0x0,0x20046d(%rip) # 0x600a28 <_ZGVZ10save_stateiE6_foo_i>
4005bb <+7>: push %rbx
4005bc <+8>: mov %edi,%ebx
4005be <+10>: jne 0x4005e1 <_Z10save_statei+45>
4005c0 <+12>: mov $0x600a28,%edi
4005c5 <+17>: callq 0x4004a0 <__cxa_guard_acquire@plt>
4005ca <+22>: test %eax,%eax
4005cc <+24>: je 0x4005e1 <_Z10save_statei+45>
4005ce <+26>: lea 0x9(%rbx),%eax
4005d1 <+29>: mov $0x600a28,%edi
4005d6 <+34>: mov %eax,0x200460(%rip) # 0x600a3c <_ZZ10save_stateiE6_foo_i>
4005dc <+40>: callq 0x4004c0 <__cxa_guard_release@plt>
4005e1 <+45>: cmpb $0x0,0x200448(%rip) # 0x600a30 <_ZGVZ10save_stateiE6_foo_j>
4005e8 <+52>: jne 0x400609 <_Z10save_statei+85>
4005ea <+54>: mov $0x600a30,%edi
4005ef <+59>: callq 0x4004a0 <__cxa_guard_acquire@plt>
4005f4 <+64>: test %eax,%eax
4005f6 <+66>: je 0x400609 <_Z10save_statei+85>
4005f8 <+68>: mov %ebx,0x20043a(%rip) # 0x600a38 <_ZZ10save_stateiE6_foo_j>
4005fe <+74>: mov $0x600a30,%edi
400603 <+79>: pop %rbx
400604 <+80>: jmpq 0x4004c0 <__cxa_guard_release@plt>
400609 <+85>: pop %rbx
40060a <+86>: retq
And by the way, g++ tries to help us with
__cxa_guard_acquire/__cxa_guard_release
which is thread-safe static variable initialization.
If you don't need it - don't pay for it.
g++ -O2 -fno-threadsafe-statics
g++ -Os -fno-threadsafe-statics
will generate equal code:
4004d4 <+0>: cmpb $0x0,0x20042d(%rip) # 0x600908 <_ZGVZ10save_stateiE6_foo_i>
4004db <+7>: jne 0x4004ed <_Z10save_statei+25>
4004dd <+9>: lea 0x9(%rdi),%eax
4004e0 <+12>: movb $0x1,0x200421(%rip) # 0x600908 <_ZGVZ10save_stateiE6_foo_i>
4004e7 <+19>: mov %eax,0x20042f(%rip) # 0x60091c <_ZZ10save_stateiE6_foo_i>
4004ed <+25>: cmpb $0x0,0x20041c(%rip) # 0x600910 <_ZGVZ10save_stateiE6_foo_j>
4004f4 <+32>: jne 0x400503 <_Z10save_statei+47>
4004f6 <+34>: mov %edi,0x20041c(%rip) # 0x600918 <_ZZ10save_stateiE6_foo_j>
4004fc <+40>: movb $0x1,0x20040d(%rip) # 0x600910 <_ZGVZ10save_stateiE6_foo_j>
400503 <+47>: retq
The interesting part here is
movb $0x1, _ZGVZ10save_stateiE6_foo_i
Keep it simple.
gcc-4.5.1
suppose we have very simple and dumb code:
void save_state(int i) {
static int _foo_i = i + 0x09;
static int _foo_j = i;
}
g++ -O2 will give us:
4005c0 <+0>: cmpb $0x0,0x200491(%rip) # 0x600a58 <_ZGVZ10save_stateiE6_foo_i>
4005c7 <+7>: push %rbx
4005c8 <+8>: mov %edi,%ebx
4005ca <+10>: je 0x400600 <_Z10save_statei+64>
4005cc <+12>: cmpb $0x0,0x20048d(%rip) # 0x600a60 <_ZGVZ10save_stateiE6_foo_j>
4005d3 <+19>: je 0x4005e0 <_Z10save_statei+32>
4005d5 <+21>: pop %rbx
4005d6 <+22>: retq
4005d7 <+23>: nopw 0x0(%rax,%rax,1)
4005e0 <+32>: mov $0x600a60,%edi
4005e5 <+37>: callq 0x4004a0 <__cxa_guard_acquire@plt>
4005ea <+42>: test %eax,%eax
4005ec <+44>: je 0x4005d5 <_Z10save_statei+21>
4005ee <+46>: mov %ebx,0x200474(%rip) # 0x600a68 <_ZZ10save_stateiE6_foo_j>
4005f4 <+52>: mov $0x600a60,%edi
4005f9 <+57>: pop %rbx
4005fa <+58>: jmpq 0x4004c0 <__cxa_guard_release@plt>
4005ff <+63>: nop
400600 <+64>: mov $0x600a58,%edi
400605 <+69>: callq 0x4004a0 <__cxa_guard_acquire@plt>
40060a <+74>: test %eax,%eax
40060c <+76>: je 0x4005cc <_Z10save_statei+12>
40060e <+78>: lea 0x9(%rbx),%eax
400611 <+81>: mov $0x600a58,%edi
400616 <+86>: mov %eax,0x200450(%rip) # 0x600a6c <_ZZ10save_stateiE6_foo_i>
40061c <+92>: callq 0x4004c0 <__cxa_guard_release@plt>
400621 <+97>: jmp 0x4005cc <_Z10save_statei+12>
First of all we're checking global _ZGVZ10save_stateiE6_foo_i to see whether local
_ZZ10save_stateiE6_foo_i has been initialized with default value (and by the way to
protect it).
After all those crazy do_lookup_x, _dl_name_match_p, check_match.10800, _dl_lookup_symbol_x, etc.
we have
0x00007ffff7b913a3 <+179>: movb $0x1,0x1(%rdi)
in __cxa_guard_acquire, which sets our global _ZGVZ10save_stateiE6_foo_i to:
0x600a58 <_ZGVZ10save_stateiE6_foo_i>: 0x00000100
and
0x00007ffff7b91459 <+57>: movb $0x0,0x1(%rdi)
0x00007ffff7b9145d <+61>: movb $0x1,(%rdi)
in __cxa_guard_release which sets _ZGVZ10save_stateiE6_foo_i to:
0x600a58 <_ZGVZ10save_stateiE6_foo_i>: 0x00000001
g++ -Os will give us:
4005b4 <+0>: cmpb $0x0,0x20046d(%rip) # 0x600a28 <_ZGVZ10save_stateiE6_foo_i>
4005bb <+7>: push %rbx
4005bc <+8>: mov %edi,%ebx
4005be <+10>: jne 0x4005e1 <_Z10save_statei+45>
4005c0 <+12>: mov $0x600a28,%edi
4005c5 <+17>: callq 0x4004a0 <__cxa_guard_acquire@plt>
4005ca <+22>: test %eax,%eax
4005cc <+24>: je 0x4005e1 <_Z10save_statei+45>
4005ce <+26>: lea 0x9(%rbx),%eax
4005d1 <+29>: mov $0x600a28,%edi
4005d6 <+34>: mov %eax,0x200460(%rip) # 0x600a3c <_ZZ10save_stateiE6_foo_i>
4005dc <+40>: callq 0x4004c0 <__cxa_guard_release@plt>
4005e1 <+45>: cmpb $0x0,0x200448(%rip) # 0x600a30 <_ZGVZ10save_stateiE6_foo_j>
4005e8 <+52>: jne 0x400609 <_Z10save_statei+85>
4005ea <+54>: mov $0x600a30,%edi
4005ef <+59>: callq 0x4004a0 <__cxa_guard_acquire@plt>
4005f4 <+64>: test %eax,%eax
4005f6 <+66>: je 0x400609 <_Z10save_statei+85>
4005f8 <+68>: mov %ebx,0x20043a(%rip) # 0x600a38 <_ZZ10save_stateiE6_foo_j>
4005fe <+74>: mov $0x600a30,%edi
400603 <+79>: pop %rbx
400604 <+80>: jmpq 0x4004c0 <__cxa_guard_release@plt>
400609 <+85>: pop %rbx
40060a <+86>: retq
And by the way, g++ tries to help us with
__cxa_guard_acquire/__cxa_guard_release
which is thread-safe static variable initialization.
If you don't need it - don't pay for it.
g++ -O2 -fno-threadsafe-statics
g++ -Os -fno-threadsafe-statics
will generate equal code:
4004d4 <+0>: cmpb $0x0,0x20042d(%rip) # 0x600908 <_ZGVZ10save_stateiE6_foo_i>
4004db <+7>: jne 0x4004ed <_Z10save_statei+25>
4004dd <+9>: lea 0x9(%rdi),%eax
4004e0 <+12>: movb $0x1,0x200421(%rip) # 0x600908 <_ZGVZ10save_stateiE6_foo_i>
4004e7 <+19>: mov %eax,0x20042f(%rip) # 0x60091c <_ZZ10save_stateiE6_foo_i>
4004ed <+25>: cmpb $0x0,0x20041c(%rip) # 0x600910 <_ZGVZ10save_stateiE6_foo_j>
4004f4 <+32>: jne 0x400503 <_Z10save_statei+47>
4004f6 <+34>: mov %edi,0x20041c(%rip) # 0x600918 <_ZZ10save_stateiE6_foo_j>
4004fc <+40>: movb $0x1,0x20040d(%rip) # 0x600910 <_ZGVZ10save_stateiE6_foo_j>
400503 <+47>: retq
The interesting part here is
movb $0x1, _ZGVZ10save_stateiE6_foo_i
Keep it simple.
Subscribe to:
Posts (Atom)