Closed p5pRT closed 4 years ago
TLDR\, Win32 Perl needs to rebase and bind all its DLLs and EXE files during the build process and save alot of memory on Win32 and speed up process start up time very easily.
In 729a02f2394e6a50fe8352c9471391b53e54ac40 a change was done to the VC makefile in win32/Makefile. This change was to avoid DLL relocation on windows to speed up Perl starting up. While the perl core dll (perl5**.dll) does not get relocated\, all XS modules (which are DLLs in Win32 Perl) sit at the default 0x10000000. Perl 5.17.4 comes with the following DLLs on Win32 out of the box. The list was hand pruned to remove /site's DLLs. _______________________________________________________ C:\perl517>dir /s /b *.dll C:\perl517\bin\perl517.dll C:\perl517\lib\auto\arybase\arybase.dll C:\perl517\lib\auto\attributes\attributes.dll C:\perl517\lib\auto\B\B.dll C:\perl517\lib\auto\Compress\Raw\Bzip2\Bzip2.dll C:\perl517\lib\auto\Compress\Raw\Zlib\Zlib.dll C:\perl517\lib\auto\Cwd\Cwd.dll C:\perl517\lib\auto\Data\Dumper\Dumper.dll C:\perl517\lib\auto\Devel\Peek\Peek.dll C:\perl517\lib\auto\Devel\PPPort\PPPort.dll C:\perl517\lib\auto\Digest\MD5\MD5.dll C:\perl517\lib\auto\Digest\SHA\SHA.dll C:\perl517\lib\auto\Encode\Encode.dll C:\perl517\lib\auto\Encode\Byte\Byte.dll C:\perl517\lib\auto\Encode\CN\CN.dll C:\perl517\lib\auto\Encode\EBCDIC\EBCDIC.dll C:\perl517\lib\auto\Encode\JP\JP.dll C:\perl517\lib\auto\Encode\KR\KR.dll C:\perl517\lib\auto\Encode\Symbol\Symbol.dll C:\perl517\lib\auto\Encode\TW\TW.dll C:\perl517\lib\auto\Encode\Unicode\Unicode.dll C:\perl517\lib\auto\Fcntl\Fcntl.dll C:\perl517\lib\auto\File\Glob\Glob.dll C:\perl517\lib\auto\Filter\Util\Call\Call.dll C:\perl517\lib\auto\Hash\Util\Util.dll C:\perl517\lib\auto\Hash\Util\FieldHash\FieldHash.dll C:\perl517\lib\auto\IO\IO.dll C:\perl517\lib\auto\List\Util\Util.dll C:\perl517\lib\auto\Math\BigInt\FastCalc\FastCalc.dll C:\perl517\lib\auto\MIME\Base64\Base64.dll C:\perl517\lib\auto\mro\mro.dll C:\perl517\lib\auto\Opcode\Opcode.dll C:\perl517\lib\auto\PerlIO\encoding\encoding.dll C:\perl517\lib\auto\PerlIO\mmap\mmap.dll C:\perl517\lib\auto\PerlIO\scalar\scalar.dll C:\perl517\lib\auto\PerlIO\via\via.dll C:\perl517\lib\auto\POSIX\POSIX.dll C:\perl517\lib\auto\re\re.dll C:\perl517\lib\auto\SDBM_File\SDBM_File.dll C:\perl517\lib\auto\Socket\Socket.dll C:\perl517\lib\auto\Storable\Storable.dll C:\perl517\lib\auto\Sys\Hostname\Hostname.dll C:\perl517\lib\auto\Text\Soundex\Soundex.dll C:\perl517\lib\auto\threads\threads.dll C:\perl517\lib\auto\threads\shared\shared.dll C:\perl517\lib\auto\Tie\Hash\NamedCapture\NamedCapture.dll C:\perl517\lib\auto\Time\HiRes\HiRes.dll C:\perl517\lib\auto\Time\Piece\Piece.dll C:\perl517\lib\auto\Unicode\Collate\Collate.dll C:\perl517\lib\auto\Unicode\Normalize\Normalize.dll C:\perl517\lib\auto\Win32\Win32.dll C:\perl517\lib\auto\Win32API\File\File.dll ________________________________________________ So after the 1st XS module is loaded\, all further DLL modules must be relocated (google the term)\, since they all share the same address. I belive the read only PE sections can not be COWed/shared between different win32 processes then (atleast on Win XP\, NT 6 might be different because of ASLR changes). Of course read write PE sections can never be shared between perl processes. "Rebase" ing (rebasing) the perl.exe might also be useful so in the million to one chance a XS module links with a DLL that links with a EXE (an EXE that exports functions)\, that 2nd EXE image won't have to be relocated. I think by default with Visual C\, EXEs do not contain relocation data and are therefore unrelocatable\, but 3rd party creating an exe that exports and is inteded to be linked with in a different process will include the reloc info. Rebasing is a very large way to save process specific memory on Windows. The savings are all the read only data in the PE file (machine code/C const data) that was relocated\, per PE file\, per Perl process.
A 2nd way smaller way of decreasing the private memory usage of Perl images is to "bind" the EXEs and DLLs. That mean that the import table is prefilled with the function pointers of the functions to import\, along with a CRC and timestamp of the exporting DLL\, if the CRC and timestamp of the exporting DLL in the importer DLL match the exporting DLL on disk\, no fixups are required. This reduces the private memory by 4KB (1 page) per EXE/DLL. This is highly Windows OS release and MS security fix specific. One strange thing about Visual C linker is\, it merges the ".idata" section\, which itself is marked as read/write in .lib files\, into the ".rdata" section of the PE file. The ".idata" section contains the function pointer import table. This means\, that unless a DLL is binded\, 1 page of C const "read only" data is always unsharable since the DLL loaded will mark the page read write to do fixup the function pointers\, then mark it back to read only\, but now its unsharable with other Perl processes. This can be confirmed with VMMap on WinXP. Using the -merge option to VC linker to force the .idata section into .data (read write initialized data) where is rightfully belongs results in linker error LNK1272.
An example of the bind command\, note it is missing the winsxs specific directory of comctl32.dll V6 so perl5**.dll is not fully binadable I guess.
bind� -p "C:\WINDOWS\system32;C:\perl517\bin"� -u "C:\perl517\bin\perl.exe" "C:\perl517\bin\perl517.dll" "C:\perl517\lib\auto\arybase\arybase.dll" ......
An example of the rebase command\,
rebase -b 0x70000000 -d� -R "." -G "C:/Documents and Settings/Owner/Desktop/p517dlls_to_rebase.txt"
p517dlls_to_rebase.txt is newline separated dll names\, like the list above.
Both bind and rebase are MS command line tools included with Visual C/Platform SDK. I dont know if any of this ticket applies to Mingw Perl or not. I've heard rumors rebase has been discontinued for Windows 8's SDK\, probably due to ASLR caching/interprocess sharing of relocated DLLs.
A rebasing should be done atleast build time. Perhaps a bat file or a perl script can be written and installed to /bin so if a user has rebase and bind they can rebase all the DLLs in /lib and /site/lib to be neatly in order. The bind is most important since it is end user OS patch level specific. Of course the user would have to have bind and rebase in their PATH already and have a copy of paid Visual Studio or free Platform SDK. I'm not sure if there are any FOSS equivelents of rebase and bind\, and whether they would be Perl license compatible. A fancier idea more complicated more unrealistic idea idea is to have ExtUtils::MakeMaker or Config.pm or IDK what keep a record on disk of the last used base address\, and lower it or rebase the XS DLL to be just below the last known lowest base address on the last EUMM compiled module\, each time a XS DLL is built\, this way /site/lib XS modules are always rebased to not ever conflict and a manual tool or perl script does not have to be run on demand by the user to keep their /site/lib rebased and binded.
Looking at ActivePerl 5.12.3 32 bit\, none of the /lib XS DLLs are rebased\, all of them are 0x10000000. I'm surprised nobody including AS ever thought of this before.
These 2 ideas presented here can reduce accusations that Perl is a memory hog/slow startup/etc on Windows. I'm not sure how much impact on "Mem Usage" column in Task Manager these ideas will have\, but the results will be measurable in Process Explorer and VMMap.
I dont have the time to do anything about this idea right now or in the near future\, so I'm creating this as a todo ticket for me in the future\, or some other Win32 Perl dev to look at one day.
On Sat\, Sep 01\, 2012 at 07:59:22PM -0700\, bulk 88 wrote:
A rebasing should be done atleast build time. Perhaps a bat file or a perl script can be written and installed to /bin so if a user has rebase and bind they can rebase all the DLLs in /lib and /site/lib to be neatly in order. The bind is most important since it is end user OS patch level specific. Of course the user would have to have bind and rebase in their PATH already and have a copy of paid Visual Studio or free Platform SDK. I'm not sure if there are any FOSS equivelents of rebase and bind\, and whether they would be Perl license compatible. A fancier idea more complicated more unrealistic idea idea is to have ExtUtils::MakeMaker or Config.pm or IDK what keep a record on disk of the last used base address\, and lower it or rebase the XS DLL to be just below the last known lowest base address on the last EUMM compiled module\, each time a XS DLL is built\, this way /site/lib XS modules are always rebased to not ever conflict and a manual tool or perl script does not have to be run on demand by the user to keep their /site/lib rebased and binded.
There are Win32 API functions to rebase and bind images from XP onwards:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363364%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms679278%28v=vs.85%29.aspx
Tony
The RT System itself - Status changed from 'new' to 'open'
On Sat Sep 01 20:38:14 2012\, tonyc wrote:
There are Win32 API functions to rebase and bind images from XP onwards:
http://msdn.microsoft.com/en- us/library/windows/desktop/aa363364%28v=vs.85%29.aspx
http://msdn.microsoft.com/en- us/library/windows/desktop/ms679278%28v=vs.85%29.aspx
Tony
I saw that\, but I thought its best not to reinvent the wheel. MS's bind tool does not use BindImageEx\, I believe it has its own PE parser and loader. MS Bind's import table lists ImageRvaToVa and MapViewOfFile http://msdn.microsoft.com/en-us/library/windows/desktop/ms680218%28v=vs.85%29.aspx . MS's rebase does import ReBaseImage64. My docs (2006 MSDN) say Win95/NT4 for BindImageEx and ReBaseImage\, that means basically forever (NT 3.1/3.51 I guess). Someone could always write a Perl license clone of MS rebase tool in pure C or XS or FFI/Win32::API or request that someone relicense their GPL rebase clone under Perl license. MS rebase isn't just a wrapper around ReBaseImage since MS rebase processes a list of DLLs putting them all in order and not overlapping (or overlapping if requested). IDK how easy it will be to keep the PDB files working (I didn't do any tests on my 5.17). IDK if Mingw Perl already does this or if Mingw64/.org have clones of rebase and bind.
On Sat\, Sep 01\, 2012 at 11:14:46PM -0700\, bulk 88 via RT wrote:
On Sat Sep 01 20:38:14 2012\, tonyc wrote:
There are Win32 API functions to rebase and bind images from XP onwards:
http://msdn.microsoft.com/en- us/library/windows/desktop/aa363364%28v=vs.85%29.aspx
http://msdn.microsoft.com/en- us/library/windows/desktop/ms679278%28v=vs.85%29.aspx
Tony
I saw that\, but I thought its best not to reinvent the wheel. MS's bind tool does not use BindImageEx\, I believe it has its own PE parser and loader. MS Bind's import table lists ImageRvaToVa and MapViewOfFile http://msdn.microsoft.com/en-us/library/windows/desktop/ms680218%28v=vs.85%29.aspx . MS's rebase does import ReBaseImage64. My docs (2006 MSDN) say Win95/NT4 for BindImageEx and ReBaseImage\, that means basically forever (NT 3.1/3.51 I guess). Someone could always write a Perl license clone of MS rebase tool in pure C or XS or FFI/Win32::API or request that someone relicense their GPL rebase clone under Perl license. MS rebase isn't just a wrapper around ReBaseImage since MS rebase processes a list of DLLs putting them all in order and not overlapping (or overlapping if requested). IDK how easy it will be to keep the PDB files working (I didn't do any tests on my 5.17). IDK if Mingw Perl already does this or if Mingw64/.org have clones of rebase and bind.
Cygwin includes a GPL2 rebase tool\, which uses ReBaseImage64.
The tool can't be written using perl - since it needs write to the perl (for bind at least) and XS .dll files (for bind and rebase.)
Tony
On Sat Sep 01 19:59:21 2012\, bulk88 wrote:
***CUT***
Adding a system 'pause' to the script after it loaded all the core DLLs (unrealistic\, but this is testing)\,
before 4236KB Private Bytes Proc Mon After 1668KB Private Bytes Proc Mon
Not bad at all in the extreme case. This is intended for Win32 parallel testing one day so more memory is shared and therefore saved between the same perl.exe processes+whatever benefit comes out of CPU cache.
Now have a WIP patch. Added benchmarking. Quite noisy even though it runs for 5-10 mins (didnt count it precisely) each run.
C:\perl521>perl bench.pl (warning: too few iterations for a reliable count) (warning: too few iterations for a reliable count) Rate old rebase old 291/s -- -55% rebase 641/s 121% --
C:\perl521> C:\perl521>perl bench.pl (warning: too few iterations for a reliable count) (warning: too few iterations for a reliable count) Rate old rebase old 266/s -- -34% rebase 400/s 50% --
C:\perl521> C:\perl521>perl bench.pl (warning: too few iterations for a reliable count) (warning: too few iterations for a reliable count) Rate old rebase old 357/s -- -11% rebase 400/s 12% --
C:\perl521>
There is also some more optimizing to do on a linker level.
PL_ppaddr and PL_check and PL_magic_vtables and all the magic vtable structs themselves\, plus the PIO thing slike PerlIO_remove\, PerlIO_utf8\, PerlIO_byte\, PerlIO_raw\, PerlIO_unix\, PerlIO_stdio\, etc\, those add upto atleast one 4 KB (page size) if not more. PL_ppaddr and PL_check are public API and hooking them is public API\, so they can never be made "C const"/RO\, but if the memory manager+linker can put them in 1 page\, and not other random C RW statics that WILL be always written to on perl process start/interp construct\, they will be COWed between perl processes. Perl core .c files (I didn't grep core modules) never patch PL_check. They do patch PL_ppaddr in pp_i_modulo() but its #ifdefed for only certain GLIBCs so I dont need to worry about that on Win32. In any case feeding a symbol order list to VC linker is compiler/platform specific.
plus fcrypt.c is very polluting\, SPtrans and skb and cov_2char and con_salt and shifts2 in fcrypt.c need to be RO (thats probably my next patch).
So my question is\, why are the magic vtables and PerlIO vtables non-const RW?
I still need to test the patch on Win64 compiling 32 bit perl to make sure bind tool doesn't put the "defaults" to connect 32 bit perl DLLs to 64 bit OS DLLs (that will be silent error\, since the DLL Loader will ignore the defaults if they aren't right).
-- bulk88 ~ bulk88 at hotmail.com
Now with support for binding to SxS CRTs and the Win64 question is answered\, 64 bit rebase tool finds 64 bit kernel32.dll. MS really didn't intend to support IAT binding with SxS. Figuring out the path of the CRT DLL was quite complicated. In this patch\, to do a IAT bind\, full perl and Win32 the module must be built\, because of the xsub Win32::GetModuleFileName which I added. I could change Win32::GetCRTDllHandle to be Win32::GetCRTDllFileName and return a string\, that way miniperl.exe can IAT bind itself on SxS VCs. Or I could add a plain C "--w32libc" option to generate_uudmap.c which prints the CRT path and miniperl gets it with backticks from generate_uudmap.exe since both were compiled with the same VC/same config.
The problem with this script from my original goals in this ticket is\, it doesn't run at XS module build time\, it only runs at Perl engine build time. Maybe it should be extracted from make_ext.pl and go into /utils as "/utils/winprelink" or "/utils/plrebase" or "/utils/plrb" ("rb.pl" is what I've called it when running it outside of make_ext.pl). Cygwin has a unix shell script called "perlrebase" but is unusable on non-Cygwin Win32 perl. https://github.com/ajaxorg/cygwin-builds/blob/master/bin/perlrebase
related reading: cygwin rebase.exe's readme http://www.tishler.net/jason/software/rebase/rebase-2.4.2.README
-- bulk88 ~ bulk88 at hotmail.com
@bulk88 barring you interest in rebasing or pursuing this, I don't see anything to be done here.
Rebasing probably not as effective on modern Win OS as it used to be prior to ASLR: https://devblogs.microsoft.com/oldnewthing/20170120-00/?p=95225
Yeah, setting a base address opts out from ASLR and it's generally considered a bad practice on modern Windowses.
Migrated from rt.perl.org#114704 (status was 'open')
Searchable as RT114704$