Hello MinGW-users!
I'm trying to run an example in section "Using the Profile Mode", in here:
http://gcc.gnu.org/onlinedocs/libstdc++/manual/profile_mode.html
I almost got it to work.
I am able to compile the source code without errors (after several
attempts and one patch to one MinGW header file -- described below).
I am able to start the program.
The program is able to start generating profiler output.
However, it is not able to finish generating the output and terminates
with SIGSEGV.
Having tried debugging with GDB I was able to backtrace the error to
__gnu_profile (details below).
What I'm not able to do is to fix it :-)
Any help with this would be very, very much appreciated :)
I shall describe my compilation, linking, patching, running and
debugging processes -- let me know if any further information would be
useful or helpful.
This is the example:
$ cat foo.cc
#include <vector>
using std::vector;
int main()
{
vector<int> v;
for (int k = 0; k < 1024; ++k) v.insert(v.begin(), k);
}
This is how I'm compiling it:
// Intention: to produce a file 'a.exe' which I will later run by './a';
$ g++ -D_GLIBCXX_PROFILE foo.cc
In file included from
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler_hash_func.h:51:0,
from
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler.h:400,
from
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/base.h:44,
from
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/vector:39,
from
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/vector:77,
from foo.cc:1:
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler_trace.h:68:21:
fatal error: pthread.h: No such file or directory
compilation terminated.
This means I don't have pthreads. OK. Let's install pthreads:
$ mingw-get update
...
$ mingw-get install mingw32-pthreads-w32
...
no change: libpthread-2.8.0-3-mingw32-dll-2.tar.lzma
install: pthreads-w32-2.8.0-3-mingw32-dev.tar.lzma
install: pthreads-w32-2.8.0-3-mingw32-doc.tar.lzma
install: pthreads-w32-2.8.0-3-mingw32-lic.tar.lzma
Now, let's try again:
$ g++ -D_GLIBCXX_PROFILE foo.cc
In file included from
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler_hash_func.h:51:0,
from
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler.h:400,
from
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/base.h:44,
from
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/vector:39,
from
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/vector:77,
from foo.cc:1:
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler_trace.h:
In function 'void __gnu_profile::__read_cost_factors()':
c:\mingw\bin\../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler_trace.h:559:62:
error: 'setenv' was not declared in this scope
This means I don't have 'setenv'. OK. Let's google to see what that is
and what can I replace it with.
Bingo!
This is what it is:
http://www.opengroup.org/onlinepubs/009695399/functions/setenv.html
And this is a replacement: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27892
Apparently, I can use 'putenv', just like here:
http://gcc.gnu.org/bugzilla/attachment.cgi?id=11598&action=diff
Let's try and replicate this patch for
"c:\MinGW\lib\gcc\mingw32\4.5.0\include\c++\profile\impl\profiler_trace.h":
-setenv(__factor_name.c_str(), __factor_value.c_str(), 0);
+char *buffer = (char *) malloc
+ (
+ strlen (__factor_name.c_str())
+ + strlen (__factor_value.c_str()) + 2
+ );
+strcpy (buffer, __factor_name.c_str());
+strcat (buffer, "=");
+strcat (buffer, __factor_value.c_str());
+putenv (buffer);
+free (buffer);
(I understand that +2 above accounts for '=' and '\0' contributing to
the length of a buffer.)
(I also mallocated free(buffer) to be sure I don't have a memory leak.)
Having backed-up "profiler_trace.h" to "profiler_trace.h.bak" and
subsequently modified "profiler_trace.h", I issue:
$ diff profiler_trace.h.bak profiler_trace.h > patchfile.diff
The generated patchfile looks like this:
$ cat patchfile.diff
559c559,570
< setenv(__factor_name.c_str(), __factor_value.c_str(), 0);
---
> //setenv(__factor_name.c_str(), __factor_value.c_str(), 0);
> char *buffer = (char *) malloc
> (
> strlen (__factor_name.c_str())
> + strlen (__factor_value.c_str()) + 2
> );
> strcpy (buffer, __factor_name.c_str());
> strcat (buffer, "=");
> strcat (buffer, __factor_value.c_str());
> putenv (buffer);
> free (buffer);
>
Having patched my
"/lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler_trace.h"
file,
let's try compiling again:
$ g++ -D_GLIBCXX_PROFILE foo.cc
C:\DOCUME~1\matt\LOCALS~1\Temp\ccHHRqac.o:foo.cc:(.text$_ZN13__gnu_profile6__turnENS_12__state_typeE[__gnu_profile::__turn(__gnu_profile::__state_type)]+0x28):
undefined reference to `__sync_val_compare_and_swap_4'
C:\DOCUME~1\matt\LOCALS~1\Temp\ccHHRqac.o:foo.cc:(.text$_ZN13__gnu_profile6__lockERP16pthread_mutex_t_[__gnu_profile::__lock(pthread_mutex_t_*&)]+0xd):
undefined reference to `_imp__pthread_mutex_lock'
C:\DOCUME~1\matt\LOCALS~1\Temp\ccHHRqac.o:foo.cc:(.text$_ZN13__gnu_profile8__unlockERP16pthread_mutex_t_[__gnu_profile::__unlock(pthread_mutex_t_*&)]+0xd):
undefined reference to `_imp__pthread_mutex_unlock'
collect2: ld returned 1 exit status
OK. Compilation successful, linking not so much. What I can see
immediately is that I'm missing stuff from pthreads, so let's link it,
too:
$ g++ -D_GLIBCXX_PROFILE foo.cc -lpthread
C:\DOCUME~1\matt\LOCALS~1\Temp\cc7stHSZ.o:foo.cc:(.text$_ZN13__gnu_profile6__turnENS_12__state_typeE[__gnu_profile::__turn(__gnu_profile::__state_type)]+0x28):
undefined reference to `__sync_val_compare_and_swap_4'
collect2: ld returned 1 exit status
OK. Just one undefined reference left. I have no idea what that is, so
let's google.
Bingo!
Someone else also had this error:
http://www.linuxquestions.org/questions/linux-software-2/glibc-make-error-undefined-reference-to-%60__sync_fetch_and_add_4-a-571961/
Mysteriously, passing "-march=i486" helps. Let's go ahead and do so:
$ g++ -D_GLIBCXX_PROFILE foo.cc -lpthread -march=i486
Amazing! No errors :-)
Now, let's try and execute our application:
$ ./a
Unfortunately, it fails and gets terminated -- the usual Windows message,
i.e. "a.exe has encountered a problem and needs to close."
$ echo $?
5
However, now it didn't fail completely and accomplishes something
before it terminates:
$ ls -al *profile*
-rw-r--r-- 1 matt Administrators 534 Oct 27 19:32 libstdcxx-profile.conf.out
-rw-r--r-- 1 matt Administrators 21 Oct 27 19:33 libstdcxx-profile.raw
-rw-r--r-- 1 matt Administrators 0 Oct 27 19:32 libstdcxx-profile.txt
Well, those three files are new.
Looking at the contents:
$ cat libstdcxx-profile.conf.out
__vector_shift_cost_factor = 1.000000
__vector_iterate_cost_factor = 1.000000
__vector_resize_cost_factor = 1.000000
__list_shift_cost_factor = 0.000000
__list_iterate_cost_factor = 10.000000
__list_resize_cost_factor = 0.000000
__map_insert_cost_factor = 1.500000
__map_erase_cost_factor = 1.500000
__map_find_cost_factor = 1.000000
__map_iterate_cost_factor = 2.300000
__umap_insert_cost_factor = 12.000000
__umap_erase_cost_factor = 12.000000
__umap_find_cost_factor = 10.000000
__umap_iterate_cost_factor = 1.700000
$ cat libstdcxx-profile.raw
vector-size||(null)u
Apparently, the diagnostic file got generated, including the warning
about vector-size being uninitialized, which may be suboptimal for
vectors that are going to grow.
What is missing, compared to sample output on "Using the Profile Mode"
manual, is a vector-to-list diagnostic and, perhaps more importantly,
libstdcxx-profile.txt (which normally "contains human readable advice"
and in this case is an empty file).
I suppose that this is because the program failed and got terminated
prematurely, before it could get to a stage where the final output
would be generated.
Let's see why it failed:
$ g++ -D_GLIBCXX_PROFILE foo.cc -lpthread -march=i486 -g3
$ gdb ./a
GNU gdb (GDB) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "mingw32".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from c:\MinGW\msys\1.0\home\matt\gcc/./a.exe...done.
(gdb) list
1 #include <vector>
2 using std::vector;
3
4 int main()
5 {
6 vector<int> v;
7 for (int k = 0; k < 1024; ++k) v.insert(v.begin(), k);
8 }
(gdb) start
Temporary breakpoint 1 at 0x4013d2: file foo.cc, line 5.
Starting program: c:\MinGW\msys\1.0\home\matt\gcc/./a.exe
[New Thread 1212.0x420]
Temporary breakpoint 1, main () at foo.cc:5
5 {
(gdb) next
6 vector<int> v;
(gdb)
7 for (int k = 0; k < 1024; ++k) v.insert(v.begin(), k);
(gdb)
6 vector<int> v;
(gdb)
8 }
(gdb)
0x004010db in __mingw_CRTStartup ()
(gdb)
Single stepping until exit from function __mingw_CRTStartup,
which has no line number information.
Program received signal SIGSEGV, Segmentation fault.
0x77c42859 in wscanf () from C:\WINDOWS\system32\msvcrt.dll
(gdb)
Single stepping until exit from function wscanf,
which has no line number information.
0x7c90e480 in ntdll!LdrDisableThreadCalloutsForDll () from
C:\WINDOWS\system32\ntdll.dll
(gdb)
Single stepping until exit from function ntdll!LdrDisableThreadCalloutsForDll,
which has no line number information.
0x7c92a970 in towlower () from C:\WINDOWS\system32\ntdll.dll
(gdb)
Single stepping until exit from function towlower,
which has no line number information.
0x7c9033dc in ntdll!RtlCheckRegistryKey () from C:\WINDOWS\system32\ntdll.dll
(gdb)
Single stepping until exit from function ntdll!RtlCheckRegistryKey,
which has no line number information.
0x7c92a99f in towlower () from C:\WINDOWS\system32\ntdll.dll
(gdb)
Single stepping until exit from function towlower,
which has no line number information.
0x7c9033f8 in ntdll!RtlCheckRegistryKey () from C:\WINDOWS\system32\ntdll.dll
(gdb)
Single stepping until exit from function ntdll!RtlCheckRegistryKey,
which has no line number information.
0x7c92a9a4 in towlower () from C:\WINDOWS\system32\ntdll.dll
(gdb)
Single stepping until exit from function towlower,
which has no line number information.
0x7c901118 in ntdll!RtlUnhandledExceptionFilter () from
C:\WINDOWS\system32\ntdll.dll
(gdb)
Single stepping until exit from function ntdll!RtlUnhandledExceptionFilter,
which has no line number information.
0x7c92aac7 in towlower () from C:\WINDOWS\system32\ntdll.dll
(gdb)
Single stepping until exit from function towlower,
which has no line number information.
0x7c910339 in ntdll!RtlInitAnsiString () from C:\WINDOWS\system32\ntdll.dll
(gdb)
Single stepping until exit from function ntdll!RtlInitAnsiString,
which has no line number information.
0x7c9102d9 in ntdll!RtlAppendStringToString () from
C:\WINDOWS\system32\ntdll.dll
(gdb)
Single stepping until exit from function ntdll!RtlAppendStringToString,
which has no line number information.
0x7c90e8cb in strchr () from C:\WINDOWS\system32\ntdll.dll
(gdb)
Single stepping until exit from function strchr,
which has no line number information.
0x7c9102e5 in ntdll!RtlAppendStringToString () from
C:\WINDOWS\system32\ntdll.dll
(gdb)
Single stepping until exit from function ntdll!RtlAppendStringToString,
which has no line number information.
Program received signal SIGSEGV, Segmentation fault.
0x77c42859 in wscanf () from C:\WINDOWS\system32\msvcrt.dll
(gdb)
Single stepping until exit from function wscanf,
which has no line number information.
Program exited with code 030000000005.
(gdb)
(gdb) The program is not being run.
OK. I suspect I might have done something wrong with my patch, since
the above errors suggests that what's failing has something to do with
C-strings manipulation -- this failed: "0x77c42859 in wscanf () from
C:\WINDOWS\system32\msvcrt.dll".
Let's see:
(gdb) run
Starting program: c:\MinGW\msys\1.0\home\matt\gcc/./a.exe
[New Thread 428.0x214]
Program received signal SIGSEGV, Segmentation fault.
0x77c42859 in wscanf () from C:\WINDOWS\system32\msvcrt.dll
(gdb) bt
#0 0x77c42859 in wscanf () from C:\WINDOWS\system32\msvcrt.dll
#1 0x0000000b in ?? ()
#2 0x77c40e46 in msvcrt!fprintf () from C:\WINDOWS\system32\msvcrt.dll
#3 0x77c5fce0 in msvcrt!_iob () from C:\WINDOWS\system32\msvcrt.dll
#4 0x004154a0 in
__emutls_v._ZZN13__gnu_profile18__reentrance_guard8__insideEvE9_S_inside
()
#5 0x0022fe2c in ?? ()
#6 0x0040817c in __gnu_profile::__container_size_info::__write
(this=0x3e437c, __f=0x77c5fce0) at
c:/mingw/bin/../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler_container_size.h:211
#7 0x00403db4 in
__gnu_profile::__trace_base<__gnu_profile::__container_size_info,
__gnu_profile::__container_size_stack_info>::__write (this=0x3e4008,
__f=0x77c5fce0) at
c:/mingw/bin/../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler_trace.h:385
#8 0x00406056 in __gnu_profile::__trace_vector_size_report
(__f=0x77c5fce0, __warnings=...) at
c:/mingw/bin/../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler_vector_size.h:75
#9 0x00406c7a in __gnu_profile::__report () at
c:/mingw/bin/../lib/gcc/mingw32/4.5.0/include/c++/profile/impl/profiler_trace.h:485
#10 0x77c39e24 in msvcrt!_initterm () from C:\WINDOWS\system32\msvcrt.dll
#11 0x77c39ec5 in msvcrt!_cexit () from C:\WINDOWS\system32\msvcrt.dll
#12 0x00000000 in ?? ()
OK. It even points to "profiler_trace.h". But not the lines of a
function I have modified.
In fact, in the process of patching (as described above), I have
solely modified function "inline void __read_cost_factors()", which
stretches from line 533 to line 573 (after patch) in
"profiler_trace.h" file.
That's weird.
I'm afraid it's at this point where I need help.
What am I doing wrong and how can I fix this?
Best,
Matt
|