-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Header reorganization #708
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
Comments
I definitely agree with both the There are more details in the linked blog post, but I'll summarize what it would look like for pybind11 (it's actually slightly simplified since pybind11 would only support header-only and static lib configurations but not dynamic lib). Optional header-onlyThis would make it possible to compile pybind11 itself as a static library which would help with compile time. This can be done so that it's 100% backward compatible -- existing users would not notice any change and everything would still function as header-only by default. Compiling as a static library would be opt-in, e.g. by defining The main idea is that headers would be split up into the expected #if !defined(PYBIND11_STATIC_LIB)
# define PYBIND11_FUNC inline
#else
# define PYBIND11_FUNC
#endif This would essentially replace The header and source files would look like this: // foo.h
#pragma once
PYBIND11_FUNC void foo();
#if !defined(PYBIND11_STATIC_LIB)
# include "foo.cpp"
#endif // foo.cpp
#include "foo.h"
PYBIND11_FUNC void foo() {
// implementation
} The obvious benefit would be compile time. I made a very quick prototype to measure the speedup that could be expected. I only moved
The performance would still go up as more of the files split up into Most of the Thoughts? |
Interesting idea re: header-only opt-in; I recall a few libraries where this is done quite well, like If done properly, this will probably involve a bit more work than a mere .h/.cpp split, like -- considering which templates to extern, maybe a few commonly used specialisations could get precompiled; considering whether the guts of some heavier types could be pimpled away; moving the type-parameter-independent functionality out of template classes (luckily, pybind11 development has always been very focused on binary size, so this is already satisfied for the most part). |
@dean0x7d I think that pretty much the only benefactors would be |
@wjakob firstly hello Wenzel and contributors and thank you for this awesome software. I'm working on the system simulator gem5 which makes heavy use of pybind11. I was feeling that the build was a bit slower than what seemed reasonable, and I started to poke a bit, and it seemed that pybind11, or at least the way we are using it, was responsible for a large part of the problem. I then tried to simply split pybind11 into header and cpp (we currently have an in tree copy of pybind11 2.4.1), and that alone reduced our full build time by 40% from 25 minutes to 15 minutes, which is, needless to say, a game changing improvement for our project as described at: https://gem5.atlassian.net/browse/GEM5-572 Because of this I was wondering, is there any chance you would review a patch that does such a split, or is there anyone with an ongoing patch? It would be of course done in a way along what @dean0x7d suggested in an optional opt-in way that would not affect existing users. Or alternatively, if you see any alternative that does not require modifying pybind11 source, also do let us know. Someone proposed precompiled headers, but I'm not sure the gains would be as significant (haven't tried it yet). To give a clearer explanation of how gem5 uses pybind11, we basically just use it as a way to pass configuration parameters from python to C++. Our full build has 1271 object files, and 365 of them are simple auto-generated C++ files that include pybind11 to contain parameters for different C++ classes, and those 365 files dominate build times. One such sample typical file looks like:
so we can see that each file individually is pretty simple, and the problem really seems to come from redefining common pybind11 objects 365 times. As a random fact :-) I also saw that one of the reasons why pytorch does not use pybind11 is the build time impact: https://discuss.pytorch.org/t/how-are-python-bindings-created/46453/2?u=cirosantilli so maybe other big projects would also benefit from this. |
I also generate pybinds automatically, and was aware of the build time problem from using luabind in the past. I chose to generate one large file with all of my pybinds in it, instead of a bunch of smaller files. This seems to work pretty well, but since I did not generate separate files first, I don't really have anything to compare to. Just a thought, in case it would work for someone else. |
@carlsonmark yes, this is one of the possibilities we are considering if it is decided that the split should not happen yet. Hopefully we can avoid that though to prevent slow rebuilds when touching one of the generation inputs. |
#679 initially added a
detail/
directory to the header includes. It was withdrawn to be discussed later in a separate issue/PR; this is meant to be the start of discussion. Also read the following not as a done deal, but as a request for comments where I'm mostly thinking out loud to start the discussion.I think we should make the move for most (or even all?) of our
detail
namespace code. Basically, all the things inclass_support.h
are an obvious first start to move todetail/class.h
; but there are also many other potential additions:Detail headers
the various template meta-code in common.h (for things like satisfied_all_of, would fit nicely into a
detail/meta.h
. It's relatively centralized now (in common.h), but that hasn't always been the case and has led to me, at least, occassionally duplicating meta template functionality that was already implemented (but implemented elsewhere, i.e. immediately before it was used/needed).The same sort of moving of
detail
namespace bits intodetail
-namespace companions would be a nice cleanup to the non-detail code. E.g. pybind11.h'sgeneric_type
andinit
classes, keep alive implementation, etc. are all already in thedetail
namespace; moving them into a detail directory header would be appropriate.Type casters
Along a similar line, we could move type caster implementations into their own namespace,
pybind11::cast
, and directory,pybind11/cast
. For now, for backwards compatibility,cast
would be a namespace alias ofdetail
, but the plan would be to eventually drop the alias so that all type casters live aspybind11::cast::type_caster<T>
, thus having external type casters put themselves in thedetail
namespace.Thus you would include
pybind11/cast/stl.h
for stl casters,pybdin11/cast/eigen.h
for eigen casters, etc. (The currentpybind11/stl.h
,pybind11/eigen.h
would just one-line compatibility headers that just include the new location).Many of the built-in casters would be usefully moved as well:
cast/arithmetic.h
cast/string.h
cast/tuple.h
cast.h
.cast.h
—I think it's there mainly for historic reasons, since it was originally part of thestd::tuple
caster. Perhapsdetail/argloader.h
?The text was updated successfully, but these errors were encountered: