jmeubank / tdm-gcc

TDM-GCC is a cleverly disguised GCC compiler for Windows!
https://jmeubank.github.io/tdm-gcc/
572 stars 49 forks source link

Someone can explain difference? #57

Closed Ilir-Liburn closed 1 year ago

Ilir-Liburn commented 2 years ago

Hello,

for the following code (9.2.0 compiler version)

int main(void){
    clock_t c1 = clock();
    double s = 0.;
    for (unsigned int j=0; j<1000; j++)
        for (unsigned int i=0; i<1000; i++) s += sin(i);
    printf("result %.20f\n", s);
    clock_t c2 = clock();
    printf("time: %.10f ms\n", 1e3*(double)(c2-c1)/CLOCKS_PER_SEC);
}

32 bit version is double slower than 64 bit version. Replacing sin function with I*j: performance is equal.

Why is sin function call double slower on 32 bit?

revelator commented 2 years ago

do you use sjlj exception model ?.

Ilir-Liburn commented 2 years ago

Here is how I compile test

gcc -static -m32 -O3 -fno-builtin -fno-jump-tables -ftree-vrp -Wfatal-errors -Wl,--output-def,proba.def proba.c

I just copied options making best result from the previous project. What is sjls? I'm not so advanced user. This question came after another person made such test using VC (double slower as well) and Pelles C (6 times slower he said).

revelator commented 2 years ago

sjlj is an exception model used for catching well... exceptions. in C++ it is mainly used with the macros _try _catch _finally etc. sjlj is the only model besides SEH (which gcc does not support in 32 bit) that can be used natively on 32 bit windows if you want to say link to a library built with gcc using msvc, dwarf is native to linux but can be used on windows though it cannot throw an exception across a dll boundary because it relies on kernel support and windows uses SEH for both 32 and 64 bit. unfortunatly sjlj is rather slow so most users prefer the dwarf model regardless.

revelator commented 2 years ago

even if your code does not use exceptions the compiler uses it internally so some overhead still happens, the 32 bit exception model use code injection on the stack so is not the fastest though SEH should be a good deal faster than sjlj which leads me to believe that the codepiece you use might have some bugs or maybe a problem with the functions it uses, hard to tell without debugging it.

Ilir-Liburn commented 2 years ago

I'm not sure I understand you. Source code is given above, what bugs of function problems we are talking about? Isn't compiler option -static causing sin function to be linked statically? Or is it using call to dynamic library exposed function regardless? Dwarf: going to checkout, interesting.

Ilir-Liburn commented 2 years ago

OK, if I understand correctly: you say 32 bit mode uses sljs, while 64 bit mode uses SEH. Is there any way to disable exceptions while compiling (if that causes slow down)?. Another question is: what about address mode? 64 bit address mode is flat while 32 bit is segmented I think. Not sure about last statement, but can this slow down sin function assuming function is accessing some (pre)computed data stored in memory?

revelator commented 1 year ago

there are several versions of exceptions with the tdm compilers look for a dll called something like libgccs.dll in mingw32/bin :) if it is named libgcc_s_sjlj-1.dll then it uses sjlj exceptions if it is named something like libgcc_s_dw2-1.dll then it uses dwarf exceptions. the mingw64 sjlj version is called the same but instead of dwarf exceptions which dont work for 64 bit on windows it uses SEH exceptions for the alternate model so is called libgcc_s_seh-1.dll.

you can use something like export CFLAGS+=" -fno-exceptions" for C code (kinda useless since C does not support exceptions at all but the compiler might actually be g++ and that one does use it internally) and or export CXXFLAGS+=" -fno-exceptions" for C++ to turn of exceptions for the compiled code but that wont turn of any exception code used in the compiler libraries so unless it is actually throwing an exception in the code itself it will probably not work.

bugs sometimes also creep up in the ABI code this is expected to happen sometimes as it is a rolling release system so might not allways be tested for stability, any bugs reported will be processed though so if you do happen to find something be sure to report it to the maintainers :).

revelator commented 1 year ago

since it is sin causing this huge slowdown it might actually be buggy for 32 bit, most of the developers have started focussing more on 64 bit so the 32 bit code does not allways get tested well enough anymore.

Ilir-Liburn commented 1 year ago

Thanks, will see what can be done. I'm using this compiler (32 bit version) to compile VM and got almost perfect results by using this compiler + modifications I made. There is also 64 bit version of the VM available, but it is not official version, e.g. not supporting external libraries getting "all batteries included".

In above code, 32 bit version is also double slower while using VC, therefore I don't think there is a bug in MinGW libraries. But you never know.

Ilir-Liburn commented 1 year ago

Now I tested above code using -fno-exceptions and got following result:

64 bit: 2906.0000000000 ms 32 bit: 2860.0000000000 ms

As you can see, 32 bit version is now slightly faster and I'm getting this result repeatedly. Since I never got any exception other than VM exception in last 3 years, I can use -fno-exceptions option. Making this compiler now perfect . Thank you very much!

revelator commented 1 year ago

looks like your code actually did throw an exception :) while it may work now if i were you id try debugging it with exceptions on to see why. Down the line if you report your findings to the relevant developer you will probably be a lot happier with the problem fixed than just turning off exceptions. Also it is a good learning experience ;)

Ilir-Liburn commented 1 year ago

I don't understand, here is the output:

result 700.59826546991951090604 time: 2922.0000000000 ms

If exception is thrown, there is no output, right? BTW, I use debugger in postmortem mode, loading debugger if there is a crash which I expect to happen for unhandled exceptions.

revelator commented 1 year ago

not allways exceptions are not nessesarily crashes, some code use them to try different methods hence the try catch terminology. output depends on how the handler was written by default it would only show in the debugger as you say but you can write code that would print a message to screen on exception. it may also be that there really is no error but it trips the exceptions handler which may be rather slow and hence would also show the result you are getting :).

Ilir-Liburn commented 1 year ago

GNU gdb (GDB) 10.2 Copyright (C) 2021 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 "x86_64-w64-mingw32". Type "show configuration" for configuration details. For bug reporting instructions, please see: https://www.gnu.org/software/gdb/bugs/. Find the GDB manual and other documentation resources online at: http://www.gnu.org/software/gdb/documentation/.

For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from a... (gdb) r Starting program: ...\language\proba\a.exe [New Thread 8668.0x1d80] result 700.59826546991951000000 time: 4421.0000000000 ms [Thread 8668.0x1d80 exited with code 0] [Inferior 1 (process 8668) exited normally]

revelator commented 1 year ago

looks indeed like it just trips the exception handler, no problem using the -fno-exception flag then :) but allways better to be safe than sorry later on.

Ilir-Liburn commented 1 year ago

Hard to tell: no matter if I use -fno-exceptions or not, execution time is the same, suggesting gdb is always running in handled exception mode. WinDbg have options to run handled or unhandled, is there such option in gdb? Or, is there an option to build executable using gcc with debug symbols compatible to WinDbg (otherwise symbols gets messed)?

revelator commented 1 year ago

there should be try gdb --help that should give you an idea of what is possible. not sure windbg can handle either sjlj or dwarf debug info ? most windows debuggers only handle SEH debug info, there is a debug tool for msvc called wingdb which can but it is not free... they should have a time limited demo version you can use i believe. sadly gui debuggers for gcc based compilers are in short supply but some ide's like codeblocks or qtcreatoe have gui frontends for gdb hich can be used,

Ilir-Liburn commented 1 year ago

WinGDB: it seems there is a free version available, but requires VS which I don't use.

http://wingdb.com/wgDownload.htm

Affinic debugger might be interesting, but official site is down currently

https://affinic-debugger-gui.software.informer.com/