Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fat Build on Windows #236

Closed
duhadler opened this issue Nov 25, 2017 · 32 comments
Closed

Fat Build on Windows #236

duhadler opened this issue Nov 25, 2017 · 32 comments

Comments

@duhadler
Copy link

Is there any way to produce a fat build on Windows with the MSVC toolchain?

@wbhart
Copy link
Owner

wbhart commented Nov 25, 2017 via email

@duhadler
Copy link
Author

Thanks for the quick response!.
Just curious: what is the reason?

@wbhart
Copy link
Owner

wbhart commented Nov 25, 2017 via email

@dimpase
Copy link
Contributor

dimpase commented Nov 29, 2017

Theoretically it ought to be possible to build MPIR using autoconf/automake and cl.exe as the C compiler (that was the approach taken at some point by CGAL project).

What should be much more feasible is to port MPIR to cmake, and cmake is able to create Windows makefiles to be run with nmake. (CGAL presently uses cmake). This would also largely alleviate the need for that VC metadata in build.vc*/

@dimpase
Copy link
Contributor

dimpase commented Nov 29, 2017

As well, it used to be perfectly possible to call VC compiler from Cygwin. Why would one want to jump hoops, if there is a working build system, just use the right command-line compiler?

@wbhart
Copy link
Owner

wbhart commented Nov 29, 2017 via email

@dimpase
Copy link
Contributor

dimpase commented Nov 29, 2017 via email

@wbhart
Copy link
Owner

wbhart commented Nov 29, 2017 via email

@dimpase
Copy link
Contributor

dimpase commented Nov 29, 2017

One talks about different types of enable-fat. One is simply about making a binary that works on as many CPUs as possible (also known as universal). This is well-supported on OSX via autoconf (or directly by OSX tools), by the way. It used to be possible to make a binary that works on PPC and on x86 and on x86_64. The right for the arch binary is then enabled at loading time (not at runtime).

I understand now that MPIR is doing something else here.

And as far as toolsets on Windows are concerned, one is not wedded to Visual Studio IDE.
D is in there for development, not for deployment. By the way, I don't understand why all these build.vs*/ are even getting into the main MPIR repo. It would be perfectly fine for them to be in a git submodule, and not being bundled into the main distribution either.

@wbhart
Copy link
Owner

wbhart commented Nov 29, 2017 via email

@dimpase
Copy link
Contributor

dimpase commented Nov 29, 2017 via email

@isuruf
Copy link
Contributor

isuruf commented Nov 29, 2017

And as far as toolsets on Windows are concerned, one is not wedded to
Visual Studio IDE.

You are misunderstanding. The VS files are in there because that is what
Windows developers want. The fact that some other option is possible is
irrelevant.

FYI, this might change in the future. Builtin CMake support is included in VS2017 IDE. (VS2017 can target older VS versions too). Microsoft also has a package manager for C/C++ projects called vcpkg which is written using cmake and integrates well with VS2015 and VS2017. (MPIR is installable using vcpkg)

@dimpase
Copy link
Contributor

dimpase commented Nov 29, 2017 via email

@wbhart
Copy link
Owner

wbhart commented Nov 29, 2017 via email

@BrianGladman
Copy link
Contributor

I am coming very late to this thread as I did not know of its existence earlier (I am the sole developer/maintainer of the Visual Studio build system for MPIR).

As Bill has said, MPIR exists precisely because of the need for a build system for GMP that uses the native Microsoft build tools (an approach that the GMP developers rejected at the time of the fork).

In my view a FAT binary build with Visual Studio would be possible. However, this is not a part of the current build system for two reasons: (1) there has not been demand for this in the community that builds MPIR with Visual Studio, and (2) the cost of developing and maintaining such a FAT build would be high.

Contrary to the view expressed above, Visual Studio build tools have been delivering thousands of large scale projects on Windows for many years. To suggest that they don't have the flexibility to do this is completely incorrect. I suspect that this view is based on a profound misunderstanding of the different approaches for applications delivery in the *nix and Windows environments.

Turing to CMake and vcpkg, Microsoft has been extending the reach of Visual Studio into the open source domain by adding support for these in Visual Studio 2017. This is an interesting development and one that it would be nice to harness if we had the resources to do so. But I am the only person working on the Visual Studio build system and, for several reasons I have not yet been able to invest in these new and potentially valuable developments.

The Visual Studio build system for MPIR involves a lot of code, which will mean that moving it to CMake and then to vcpkg wil be a significant task, especially so if a FAT build were to be included. This will almost certainly need good knowledge of CMake but, surprisingly, I have not been able to find any accessible in-depth paper based documentation for it (yes I like to read such stuff on paper!)

The Kitware book appears to meet this need but it is insanely expensive and I am unwilling to spend money on it as my work on MPIR is completely unfunded. So, although I would like to look at using CMake/vcpkg for the Visual Studio build, the lack of free in-depth paper based documentation of CMake has so far prevented any work by me on this.

@dimpase
Copy link
Contributor

dimpase commented Nov 30, 2017 via email

@BrianGladman
Copy link
Contributor

Thank you for your rapid and detailed response to my input.

I do not doubt that the current build system for Windows is not going to meet everyone's current needs.

However, it has been an effective way of building MPIR over the last decade and is only now showing its age as a result of the recent steps that Microsoft has made to extend its tools into the open source domain.

It would certainly be very nice if it proved possible to make use of these recent developments but I honestly do not know whether I will have the time to undertake what I fear will be a large task.

I will email you separately on this.

@duhadler
Copy link
Author

duhadler commented Dec 1, 2017

I am very happy to learn that a FAT binary build with Visual Studio would (in principle) be possible!

So I would like to suggest that this option will be included in future MPIR builds with Visual Studio.

I am also very interested to work with the MPIR team (and I guess, in particular with Brain Gladman) to help developing and maintaining such a build. This might also involve some work regarding the current (MPIR 3.0.0) build using MSYS2 and MinGW-w64, which does not support a FAT build properly on Windows 64 bit (I had pointed this out earlier, see #213).

The reason for wanting a FAT build in the first place is maybe best explained by looking at a Python project like gmpy2 (see https://pypi.python.org/pypi/gmpy2), which provides an Python interface to MPIR, MPFR and MPC. On Python for Windows, the expectation is to distribute a binary build, not just the source code. A binary build on 64 bit will have to use the AMD K8 configuration as the lowest common denominator. This does not really do justice to the support which MPIR provides for newer CPUs. The alternative would be to provide many more CPU-specific binary builds multiplied by the number of supported Python versions, which seems neither practical nor desirable. A 64 bit distribution of gmpy2 with a FAT binary build would solve this dilemma.

@duhadler duhadler closed this as completed Dec 1, 2017
@duhadler duhadler reopened this Dec 1, 2017
@BrianGladman
Copy link
Contributor

@duhadler I should stress again that a creating a Visual Studio FAT build will be a VERY difficult task. I looked at this several years ago and it did not take me long to conclude that it was not something that I was very keen to take on!
@wbhart Bill, when I looked at this several years ago you were kind enough to set out in detail what I would have to do to match how this is achieved with *nix/GCC. I am wondering if you might still have this description around?

@wbhart
Copy link
Owner

wbhart commented Dec 1, 2017 via email

@BrianGladman
Copy link
Contributor

If, say, we want a FAT build involving N functions, I would have thought we would have each of the N functions called through a single function pointer in a table of N pointers which is set up on the first call to any of the N functions (i.e. all the pointers are initially pointing to initialisation routines that will set up all the pointers for the detected architecture before completing the called function).

This first call will, of course, be costly but I can't see why the costs would be high on any subsequent calls since these will involve only one extra jump instruction. I also believe this could be done using an indexed jump instruction with a fixed index so it would not require an extra register.

Am I missing something obvious here?

@duhadler
Copy link
Author

duhadler commented Dec 1, 2017

MPIR 2.7.2 using MSYS2 and MinGW-w64 (GCC 4.8.3 or later) has full support for a FAT build on Windows 64 bit. The resulting DLL can be called from executables which depend on the GCC runtime, like R (Statistical System), or which do not depend on any C++ runtime, like C# or Visual Basic.

However, this 64 bit DLL cannot be called from executables which depend on a current version of the MSVC runtime (2010 or later) if the code contains anything that the MSVC compiler believes needs an object initialisation (which is the reason why MinGW-w64 cannot be used for Python, Matlab, Java 64 bit on Windows, since these languages depend on recent versions of the MSVC runtime).

Python, Matlab, Java 64 bit can however call the MPIR 2.7.2 DLL when it is built with the MSVC tool chain, and linked against the MSVC 2010 runtime or later.

So I would assume that, since MinGW-w64 can produce a working FAT build on Windows 64 bit, this should in principle also be possible with the MSVC tool chain, unless recent versions of the MSVC runtime contain restrictions (registers etc) that make that impossible. Since the MinGW-w64 runtime itself links against an ancient version of the MSVC runtime (msvcrt.dll), I would think that this is worth a try.

@wbhart
Copy link
Owner

wbhart commented Dec 1, 2017

I don't know who added Fat binary support for MPIR on Windows, since it certainly wasn't me or Brian. The calling conventions are different on Windows, which means different registers are used to pass arguments. So if this actually works, I certainly don't know how. I can believe it builds, but I have a hard time believing that it actually works. But maybe someone added support for it, and I have just forgotten.

@wbhart
Copy link
Owner

wbhart commented Dec 1, 2017

@BrianGladman I don't recall if the entire table is set up on the first call to any function or if each function is set up individually on the first call. But either should work.

There is still overhead because you need a short function to actually call the relevant assembly object through the table. This does have overhead. Even on Linux, a fat binary build is much slower than a native build. But it is still faster than a generic C build.

@wbhart
Copy link
Owner

wbhart commented Dec 1, 2017

I think there may also be some overhead since some of the optimisation is put out of kilter by the extra function call. On modern CPUs the indirect function call probably isn't a big source of slowdown. Neither of these sources of overhead is relevant here of course; they both occur on Linux and Windows.

@duhadler
Copy link
Author

duhadler commented Dec 2, 2017

Both GMP 6.1.2 and MPIR 2.7.2, using MSYS2 and MinGW-w64 (GCC 4.8.3 or later), have full support for a FAT build on Windows 64 bit. They not only can be built, they actually work. This can be verified as follows:

Download MSYS2 (64 bit) from www.msys2.org

Install the downloaded package to C:\msys64 and follow the instructions from the homepage.

Close MSYS2 and restart (i.e. double-click on mingw64.exe in the installation directory).
From within MSYS2, type

pacman -S base-devel mingw-w64-x86_64-toolchain

and install everything. Close MSYS2 and restart.

Place the GMP 6.1.2 and MPIR 2.7.2 directories in C:\msys64\home\MP64.
For compilation and testing of a FAT 64 bit static library, proceed as follows: Within MSYS2, type
cd ..
to change to the home directory, and then type
cd MP64/gmp-6.1.2
to change to the /home/ MP64/gmp-6.1.2 directory.

Within MSYS2, type

./configure --build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32 --enable-fat --enable-static --disable-shared ABI=64 CFLAGS="-m64 -march=k8 -Wno-attributes" --prefix=/local/Win64 --exec-prefix=/local/Win64

to configure the GMP source files for compilation of a FAT 64 bit static library. Once this has been completed type
make
to start the actual compilation. Once this has been completed, type
make check
to start the compilation and execution of the test programs. All tests should pass.
The process for MPIR 2.7.2 is the same, except for the directory containing the code.
Please let me know if you cannot reproduce these results.

@ghost
Copy link

ghost commented Dec 4, 2017

As @isuruf said, CMake is pretty much going to be the default build system for new C/C++/Assembly projects going forward. This is because CMake works with all major operating systems (Windows/OSX/Linux), and most importantly, like autoconf, requires zero maintenance once set up (you don't need to regenerate build files manually for each VC version).

Now, whether existing projects such as MPIR and flint2 will adopt CMake anytime soon is a different question. Switching build systems requires significant effort, and it will take time to bring the CMake build system up to the capabilities of the autoconf build system.

@KevinHake
Copy link

@ghost, @dimpase, @isuruf - Resurrecting this old thread :) - I see a lot of talk about CMake here (for which we now have #186, #214, #215). I seem to be missing the link between CMake and a theoretical FAT build on Windows. Does CMake make this possible?

@BrianGladman, @wbhart - Spitballing here - perhaps the FAT binary functionality could be achieved with the Microsoft toolchain using a different approach compared to the dynamic jump table you described in Linux:
Imagine we build a number of dlls for different optimizations/architectures, exactly as we do today. Then, we build a broker dll which the main application links to. This broker dll is special in that all it does is detect the architecture and decide which of the regular dlls should be called. I'm not sure if we can run this detection code on loading (need to think/research), but if not certainly we could make it a stub dll where all functions jump to the detection routine.
The end of the detection routine will then replace itself; it will load the optimized dll, and thus every subsequent call will be the same as native, no extra jumps (so theoretically faster than the Linux style dynamic load).
The obvious drawback is that you will ship multiple entire dlls. An improvement is to paste them all together in one blob of a dll. A further improvement could be compressing each of those dlls in some manner (perhaps keeping only one copy of all the shared code between dll versions... or something more complex).
Another potential drawback is I'm not sure how to do something similar with a static library build.

@BrianGladman
Copy link
Contributor

@KevinHake There is a general desire to have a CMake based build for MPIR on Windows, especially so, given that Visual Studio 2017 directly supports it (there is already such a build for the MPIR library using the generic C code). But I doubt that CMake is going to make any FAT build easier to achieve.

Turning to your thought on a FAT binary, the idea you put forward is an interesting one We wouldn't have to have a special DLL since we can just have a routine to detect the underlying architecture after which we would simply dynamically load the fastest compatible one. I have not implemented dynamic loading with MPIR but I have done this with my AES library and it was not too hard to implement. As you say, the downside is a large expansion in the size of the distribution.

Another alternative is to note that only a small number of routines are sped up using assembler so we could put all of these into a set of dynamically loaded optimised DLLs with another standard DLL for the remaining C code. This would considerably reduce the size of the distribution. We should be able to do something similar with static libraries.

@dimpase
Copy link
Contributor

dimpase commented Sep 5, 2018

My biggest problem with this FAT business is the need for it in the open-source realm. Building MPIR on the host it has to run on is reasonably fast, needs to be done just once, and may be done with free tools.

@KevinHake
Copy link

It could also be argued that an application meant for distribution, not just a one-off research project or what have you, which is also concerned about performance, should really use an installer. And that installer should really be responsible for detecting the local architecture and choosing the most optimized dll(s) to use. From a software architecture standpoint, FAT binaries in general are kind of a flawed approach; They're bigger, slower, more complicated: harder to develop and debug, compared to a single-architecture binary. That's why they haven't become standard practice, and never even implemented natively in Windows.
I am curious if there are widely distributed projects which already ship with multiple MPIR bins, or if everyone just uses a low level of optimization. Maybe it would be helpful to provide a detection routine for people to use.

@wbhart wbhart closed this as completed Sep 28, 2018
@wjblanke
Copy link

BrianGladman#19

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants