Jump to content

  • Log In with Google      Sign In   
  • Create Account


(mingw/winapi) growing exe size when linking to psapi


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
15 replies to this topic

#1 fir   Members   -  Reputation: -448

Like
0Likes
Like

Posted 13 March 2014 - 04:32 AM

My app is 25 kb size when stripping symbols (-s) in no it has 62kb

When im linking to psapi (-lpsapi and using one function from it, psapi is winapi lib for process info etc) it grows to 175 k and with stripping symbols 75 k

 

no using psapi   25k  62k

using paspi       75k 175k

 

why it grows so large (i am using only one function and my app grows from 25k to 75k i dislike it because i like tiny executables)

 

Is there a way to shrink it to 25 k again?

 



Sponsor:

#2 Ashaman73   Crossbones+   -  Reputation: 6952

Like
0Likes
Like

Posted 13 March 2014 - 05:59 AM

Have you already tried dynamic/runtime linking. Is the API open source, so that you can stripe all the unnecessary code out of it ?



#3 fir   Members   -  Reputation: -448

Like
0Likes
Like

Posted 13 March 2014 - 08:40 AM

Have you already tried dynamic/runtime linking. Is the API open source, so that you can stripe all the unnecessary code out of it ?

 

psapi is some winapi but you must link to libe explicity -lpsapi

(also you must include header (#include <psapi.h>) out of

the normal windows.h (but present and included like windows.h)

 

- I dont know the difference agains other winapi where you do not

link explicite, why I must use header and link it 

 

I not tried the dynamic linking it would probably work (could eventaullt try it) but now I just wonder why it grows so (including whole windows.h

not fats out my exe and this psapi makes +50k)



#4 samoth   Crossbones+   -  Reputation: 4656

Like
1Likes
Like

Posted 13 March 2014 - 11:53 AM

Are you sure you are doing this correctly, your MinGW install is good, and your computer has no malware on it?

 

My complete psapi.dll alltogether only weights 9,216 bytes, so even assuming you linked the DLL's complete binary code into your executable somehow (which is not how it works!), this couldn't explain an extra 50kiB.

 

Linking with psapi.dll the proper way using the import lib (-lpsapi) makes exactly zero difference here (it's probably a few bytes extra, but due to PE/COFF section size alignment, the final executable is exactly the same size).


Edited by samoth, 13 March 2014 - 11:54 AM.


#5 fir   Members   -  Reputation: -448

Like
0Likes
Like

Posted 13 March 2014 - 12:44 PM

Are you sure you are doing this correctly, your MinGW install is good, and your computer has no malware on it?

 

My complete psapi.dll alltogether only weights 9,216 bytes, so even assuming you linked the DLL's complete binary code into your executable somehow (which is not how it works!), this couldn't explain an extra 50kiB.

 

Linking with psapi.dll the proper way using the import lib (-lpsapi) makes exactly zero difference here (it's probably a few bytes extra, but due to PE/COFF section size alignment, the final executable is exactly the same size).

 

strange,

 

mingw should be ok, as to malware cannot be sure but never saw

a manifestation of it and everything seem to be ok

 

psapi here 23 040 bytes, I could try disasembly etc matbe try to see

whats going on but maybe im too unexperienced - and thus this question



#6 LorenzoGatti   Crossbones+   -  Reputation: 2621

Like
1Likes
Like

Posted 14 March 2014 - 02:04 AM

Increasing the total linked size by over twice the size of the added library is completely abnormal. I guess there must be some other source of code, such as

  • C++ template instantiations that you use to call the new functions
  • potentially large pieces of whatever libraries this "psapi" depends on

 

There are plenty of tools to list the content of an executable file: they should allow you to see which sections grow and which sections remain the same between the two versions of the program.


Edited by LorenzoGatti, 14 March 2014 - 02:10 AM.

Produci, consuma, crepa

#7 samoth   Crossbones+   -  Reputation: 4656

Like
1Likes
Like

Posted 14 March 2014 - 07:58 AM

I've tried this again with a different MinGW build (TDM-4.8.1), and done binary compares.

 

Wiht or without -lpsapi (when not actually using any functions from psapi) makes exactly zero difference (executables are binary identical except for the linker's timestamp in the PE header, but that one is different for every two builds).

 

When actually using a function from the library (I tried EnumProcesses), a few dozen bytes are added to .text (no surprise), and the function's name is added to the back of the file (presumably import table), as well as the library's name. Alltogether, fewer than a hundred bytes are different.

The total size of the executable remains exactly the same (again, because of PE section sizes, there are merely some fewer zeroes at the end).

 

So... if your executable grows by 50kiB, something must be seriously amiss.



#8 fir   Members   -  Reputation: -448

Like
0Likes
Like

Posted 14 March 2014 - 08:45 AM

I've tried this again with a different MinGW build (TDM-4.8.1), and done binary compares.

 

Wiht or without -lpsapi (when not actually using any functions from psapi) makes exactly zero difference (executables are binary identical except for the linker's timestamp in the PE header, but that one is different for every two builds).

 

When actually using a function from the library (I tried EnumProcesses), a few dozen bytes are added to .text (no surprise), and the function's name is added to the back of the file (presumably import table), as well as the library's name. Alltogether, fewer than a hundred bytes are different.

The total size of the executable remains exactly the same (again, because of PE section sizes, there are merely some fewer zeroes at the end).

 

So... if your executable grows by 50kiB, something must be seriously amiss.

 

dont know i can link the binary if somebody would like to disasembly it or something, I feel not ready to this..

 

https://www.dropbox.com/s/q5htqxrv94oocq9/psapigrow.zip

 

here are both versions , i comented my prototype game code so it is only green dot moved by mouse - app



#9 samoth   Crossbones+   -  Reputation: 4656

Like
1Likes
Like

Posted 14 March 2014 - 09:02 AM

One is compiled with exception support, and the other without.

 

You can easily tell by the presence (or absence) of __unexpected_handler_sh and __terminate_handler_sh or strings such as "terminate called after unhandled exception".



#10 fir   Members   -  Reputation: -448

Like
0Likes
Like

Posted 14 March 2014 - 09:11 AM

One is compiled with exception support, and the other without.

 

You can easily tell by the presence (or absence) of __unexpected_handler_sh and __terminate_handler_sh or strings such as "terminate called after unhandled exception".

 

I carefull add -fno-rtti -fno-exceptions to all i compile and link, so

linking to psapi forces mingw to enable exceptions (and ignore my commands)? Is there a way to remove it?



#11 samoth   Crossbones+   -  Reputation: 4656

Like
0Likes
Like

Posted 14 March 2014 - 09:20 AM

Linking pasapi should not (that would be nonsensical, since it's a C API) and, on my machine, does not force MinGW to enable exceptions.

 

Though using exceptions in any form does, obviously. Are you positively sure that you do not have anything like throw or catch in your sources? This includes headers from any other libraries that you may be including (which maybe have some #ifdef that you accidentially triggered?).

 

While I obviously cannot tell you the exact reason of why and where and how exception handling got turned on without my divining crystal ball, I can only tell you what the symptoms are. One of the files you uploaded on pastebin does contain the names and strings of the standard exception handling code, and the other one does not.

 

If you have MSYS or GnuWin or something similar on your computer, you can run something like grep exception psapilinked.exe to see yourself (or "unexpected" or "handler"). Or just use a hex editor (I used WinMerge to compare them, but HxD would work fine, too).



#12 fir   Members   -  Reputation: -448

Like
0Likes
Like

Posted 14 March 2014 - 09:33 AM

Linking pasapi should not (that would be nonsensical, since it's a C API) and, on my machine, does not force MinGW to enable exceptions.

 

Though using exceptions in any form does, obviously. Are you positively sure that you do not have anything like throw or catch in your sources? This includes headers from any other libraries that you may be including (which maybe have some #ifdef that you accidentially triggered?).

 

While I obviously cannot tell you the exact reason of why and where and how exception handling got turned on without my divining crystal ball, I can only tell you what the symptoms are. One of the files you uploaded on pastebin does contain the names and strings of the standard exception handling code, and the other one does not.

 

If you have MSYS or GnuWin or something similar on your computer, you can run something like grep exception psapilinked.exe to see yourself (or "unexpected" or "handler"). Or just use a hex editor (I used WinMerge to compare them, but HxD would work fine, too).

 

No all headers im using are windows.h (with lean and mean and extra lean) and some c standard lib thats all - and psapi.h here - maybe this 

causes the exceptions? nothing other, I carefully add teh options to strip symbols, no exceptions, no runtime - I am using pure c code 

but compile it in c++ mode, this is simple and pure winapi app

 

got no idea what causes this exceptions.. do they have runtime cost

involved (I would like to strip them out)



#13 fir   Members   -  Reputation: -448

Like
0Likes
Like

Posted 14 March 2014 - 10:20 AM

Linking pasapi should not (that would be nonsensical, since it's a C API) and, on my machine, does not force MinGW to enable exceptions.

 

Though using exceptions in any form does, obviously. Are you positively sure that you do not have anything like throw or catch in your sources? This includes headers from any other libraries that you may be including (which maybe have some #ifdef that you accidentially triggered?).

 

While I obviously cannot tell you the exact reason of why and where and how exception handling got turned on without my divining crystal ball, I can only tell you what the symptoms are. One of the files you uploaded on pastebin does contain the names and strings of the standard exception handling code, and the other one does not.

 

If you have MSYS or GnuWin or something similar on your computer, you can run something like grep exception psapilinked.exe to see yourself (or "unexpected" or "handler"). Or just use a hex editor (I used WinMerge to compare them, but HxD would work fine, too).

 

I did some tests yet , my psapi code is like that

 


#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN
#include <windows.h>
 
#include <psapi.h>
 
#include "..\allmyheaders\allmyheaders.h"
 

long working_set_size = -1;
long paged_pool_size = -1;
long nonpaged_pool_size = -1;
 
static PROCESS_MEMORY_COUNTERS process_memory_counters;
 
long GetMemoryInfo()
{
 
    static HANDLE hProcess;
 
    static int initialised = 0;
    if(!initialised)
    {
    // return -1;
     static DWORD processID = GetCurrentProcessId();
    // return -2;
     hProcess = OpenProcess(  PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID );
 
     if (NULL == hProcess)  ERROR_EXIT("cant open process for get memory info");
 
     initialised = 1;
 
 
    }
 
 
    if(GetProcessMemoryInfo(hProcess, &process_memory_counters, sizeof(process_memory_counters)))
    {
      working_set_size    = process_memory_counters.WorkingSetSize;
      paged_pool_size     = process_memory_counters.QuotaPagedPoolUsage;
      nonpaged_pool_size  = process_memory_counters.QuotaNonPagedPoolUsage ;
    }
 
    if(0)
      CloseHandle( hProcess );
 
    return working_set_size;
}
 
it shows that when i uncomment return -2 here my app has 75k when i uncomment return -1 (disabling the execution of
 
     static DWORD processID = GetCurrentProcessId();
 
the app has 25k - is it possible, can it be explained?
 
(same with dynamic linking regardless of static or dynamic it seems
that it all depends on this "     static DWORD processID = GetCurrentProcessId();" line

Edited by fir, 14 March 2014 - 10:23 AM.


#14 samoth   Crossbones+   -  Reputation: 4656

Like
0Likes
Like

Posted 14 March 2014 - 05:54 PM

These two are quite hefty antipatterns:

I am using pure c code but compile it in c++ mode, this is simple and pure winapi app
#include "..\allmyheaders\allmyheaders.h"

 

You should either write C or C++ and compile the language that you use, not something different. C++ is not "C with some additional stuff", it is a different language with similar, but different rules. There is nothing wrong with writing C code, but then you should also compile as C. If you compile C++, then you should write C++.

 

Including "allmyheaders.h" is something that generally works, but it makes compilation needlessly slow, and you maybe bring definitions into scope which you don't need (or which even interfere in a non-obvious manner). It will also cause some people to raise an eyebrow when they look at your code, and will cause others to yell at you.

 

One notable difference of whether you compile C or C++ is for example that C++ (at least C++11, but GCC since ca. version 4.6 also does that for C++03) mandates initialization of function-local static variables being thread-safe. I'm mentioning that since you use that feature (maybe without being aware).

 

You most probably should not worry about exceptions. Do they have a runtime cost? Well, it depends, generally everything has a runtime cost. A better question would be whether they have a cost that matters, or a cost that is not justified by the benefits.

Giving a meaningful answer about exceptions is also hard since it depends a lot on what compiler build you use. MinGW can use setjump/longjump, DW2, and SEH exceptions. Which ones you have is determined when the compiler is built (on a proper build, you can figure out by running gcc -v).

 

SJLJ exceptions do have a runtime overhead, but even these are very acceptable, and the usefulness of exceptions still outweights their runtime cost in my opinion. DW2 exceptions make your exectuable somewhat bigger, but do not have a runtime overhead unless or until you actually throw (when trowing, they're indeed slightly slower). SEH exceptions combine the best of two worlds, but are presently only implemented in 64-bit builds (patent issues).

 

Exceptions have traditionally been accused of killing performance, but at least on a desktop, that is definitively not the case (it might be on a console). Like most language features, exceptions can be used for good and for evil. If you use them in a reasonable manner, their overhead will be very low (close to zero), but they will be immensely useful and greatly improve your code quality.

If you abuse them, ... well, the opposite. smile.png

 

 

disabling GetCurrentProcessId() [...] can it be explained?

 

I can't explain that. Does not seem like this is possible.



#15 fir   Members   -  Reputation: -448

Like
0Likes
Like

Posted 14 March 2014 - 06:52 PM

These two are quite hefty antipatterns:

 

I am using pure c code but compile it in c++ mode, this is simple and pure winapi app
#include "..\allmyheaders\allmyheaders.h"

 

You should either write C or C++ and compile the language that you use, not something different. C++ is not "C with some additional stuff", it is a different language with similar, but different rules. There is nothing wrong with writing C code, but then you should also compile as C. If you compile C++, then you should write C++.

 

Including "allmyheaders.h" is something that generally works, but it makes compilation needlessly slow, and you maybe bring definitions into scope which you don't need (or which even interfere in a non-obvious manner). It will also cause some people to raise an eyebrow when they look at your code, and will cause others to yell at you.

 

One notable difference of whether you compile C or C++ is for example that C++ (at least C++11, but GCC since ca. version 4.6 also does that for C++03) mandates initialization of function-local static variables being thread-safe. I'm mentioning that since you use that feature (maybe without being aware).

 

You most probably should not worry about exceptions. Do they have a runtime cost? Well, it depends, generally everything has a runtime cost. A better question would be whether they have a cost that matters, or a cost that is not justified by the benefits.

Giving a meaningful answer about exceptions is also hard since it depends a lot on what compiler build you use. MinGW can use setjump/longjump, DW2, and SEH exceptions. Which ones you have is determined when the compiler is built (on a proper build, you can figure out by running gcc -v).

 

SJLJ exceptions do have a runtime overhead, but even these are very acceptable, and the usefulness of exceptions still outweights their runtime cost in my opinion. DW2 exceptions make your exectuable somewhat bigger, but do not have a runtime overhead unless or until you actually throw (when trowing, they're indeed slightly slower). SEH exceptions combine the best of two worlds, but are presently only implemented in 64-bit builds (patent issues).

 

Exceptions have traditionally been accused of killing performance, but at least on a desktop, that is definitively not the case (it might be on a console). Like most language features, exceptions can be used for good and for evil. If you use them in a reasonable manner, their overhead will be very low (close to zero), but they will be immensely useful and greatly improve your code quality.

If you abuse them, ... well, the opposite. smile.png

 

 

disabling GetCurrentProcessId() [...] can it be explained?

 

I can't explain that. Does not seem like this is possible.

 this allmyheaders.h is only with my own headers, from different modules (added here for convenience, (not to inllude specyfic list each one for each include) some way of short, also this 'my' name suggest this is some playfield (this is experimantal home project and not large)- except mu ovn headers I am using onlu std c lib (like stdio.h math.h stdlib.h) and windows.h

 

well my tests showed what i said if i wil uncomment return it is 75 k

if i give return vefore thi it is 25k

 

 

as to c /c++

 

I am big fan of c and not use c++ features, but i cant stand one thing

 

 

const int tab_max = 1000; //at global/file scope

int tab[tab_max];

 

it wil not compile in c - so i just need to switch to c++ simply for this 

one 'feature' (the only one i use)



#16 fir   Members   -  Reputation: -448

Like
0Likes
Like

Posted 14 March 2014 - 07:06 PM

 

One notable difference of whether you compile C or C++ is for example that C++ (at least C++11, but GCC since ca. version 4.6 also does that for C++03) mandates initialization of function-local static variables being thread-safe. I'm mentioning that since you use that feature (maybe without being aware).

 

 

BINGO, (what a shit is this ;c )

 

I just turned 

static DWORD processID =  GetCurrentProcessId();

into

 

static DWORD processID = 0;
 processID = GetCurrentProcessId();
 
and the size dropped down from 75k to 27k
also spped of the ap from 4ms/frame dropped to 3ms/frame
 
so it seem there was some overgead or something
 
scary, important lesson learned - avoid such kind of static 'initialisations' (scarry , realy scary, i very much dislike when compiler do thi kind of staf degrading performance)

Edited by fir, 14 March 2014 - 07:11 PM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS