-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Optimize Linux shared library modules (*.so files) #2445
Conversation
The automatic build failed. Somebody please help me to understand why it failed. It was building on my local machine: It looks to me there are only warnings, not errors. And they are all related to Doxygen unable to parse the code correctly. It should not effect the builds in anyway. However I do not know how to fix warnings. |
It appears to me the code does not have a problem, but the Jenkins script checking syntax cannot understand attribute((visibility("default"))) placed in front of a function protocol declaration. The syntax is valid according to: |
It appears that the warnings occurs near the end of parsing the header file. The Doxygen parser tries to match the parameters it sees in the comment with the actual parameters in the function protocol:
It expands NNVM_DLL into attribute((visibility("default"))), and thinks it is the function protocol, and tries to find within it the parameter msg mentioned in the comment, but could not find it. The code has no problem. But the doxygen parser could not understand the attribute((visibility("default"))) is just an attribute tag. I do not know how to suppress that warning. Some one please help. |
This still does not work. Now the error is unresolved symbols: This is probably because with the new way how the macro is defined:
It some how result in NNVM_DLL to be defined to nothing, thus the symbol is not exported. Strangely, as NNVM_DLL is defined to nothing, it does not trigger the Doxygen parser warning any more. I am going to try something else to make this working: Define NNVM_DLL in the way of original pull request, without the GNUC version check. Get rid of the visibility specifier NNVM-DLL from the header file where the Doxygen comments sit, but add it to the cc file where the function actually sits. |
Thanks for the contribution. I think we should still find ways to put these DLL marks in the header file, as they are the user-facing places that recognizes which ones need to be exported |
tqchen:
Thus it makes more sense to have the visibility specifier not where function protocol is define, but rather where the definition of the function is, i.e., where an actual function sits. like "Here is the actual function and I want to export it." For the same reason, it is absurd to add the visibility specifier to a virtual function, or even a pure virtual function in a header file. "I want to export a pure virtual function which actually does not exist (???)". Do you now agree that the place where a function is implemented is the logically right place to specify that it should be made visible and exported, not the place a function is declared? |
As far as I know, the common way is put function attribute (include visibility) into function declaration, not function implementation. I agree that the header file is end users care about. Like the doc(https://gcc.gnu.org/wiki/Visibility) say: |
The changes finally builds with every symbols resolved, in patch #13. However now there are unit test failures all related to one spot:
The code in util.py says: |
FrozenGene: Unless some one has a better solution I propose we take it as it is, with the visibility attribute stay with the implementation. This visibility change is very valuable in reducing module size so should be taken. |
Yes. I fully understand its value in reducing module size. However, I think place attribute in the funcion definition because of Doxygen issue is not the right way. I think the right way should be Doxygen preprocessing setting. In fact, many users has similar problem, for example. https://sites.google.com/site/opensourceconstriubtions/ettl-martin-1/tutorials/doxygen-is-not-able-to-parse-the-gcc-keywords-__attribute__-x-how-to-solve-this . You could also check this document: http://www.doxygen.nl/manual/preprocessing.html I think these two links should be related with your Doxygen problem. |
FrozenGene: |
The doxygen code is here https://github.com/dmlc/tvm/blob/master/docs/Doxyfile we can reproduce locally via make doc |
tqchen: |
Please rebase against current master and squash the commits, ideally we only have to change the def of TVM_DLL |
4ec23c7
to
9da79c9
Compare
I am trying to squash multiple git commit into one and move the visibility specifier back to the head file. Let's see how it goes: http://ci.tvm.ai:8080/blue/organizations/jenkins/tvm/detail/PR-2445/27/pipeline |
757ec39
to
bf1e851
Compare
TQChen:
|
@tqchen and @FrozenGene could you review again? The CR is now in a good shape. Passed all tests. And my local tests all works fine. This can reduce module sizes quite a bit and speed up load time, too. |
I have no other comments. @tqchen maybe could give some comments. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still see quite a bit un-necessary changes
@tqchen I updated my changes to sync up with the master branch, and fixed a trivial alignment. You questioned why I moved a few inline functions into their places. These are necessary fixes to get rid of the compiler and lint check warnings, and those are the reasons why the original code had to have the "NOLINT" comment. Basically if you want a function to be inline, then do not separate declaration and implementation. Keep them in the same place at the declaration. If you insist to keep declaration and implementation separate, then the function probably should not be inline in the first place. Please review again. |
Patch build 33 failed: |
@tqchen Please approve separate pull request: dmlc/HalideIR#45 Those only two entries corresponds to the two lines, 653 and 654 in src/ir/IR.cpp which already had the EXPORT keyword. Line 652 was not exported since it did not have the "EXPORT": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please still restore the inline functions
OK, some comments wrt to the inline function declaration vs implementation. I agree that it is a subjective thing, and the reason that inline keyword exists to enable such separation. The main reason to keep declaration and implementation apart is to make the interface more clear without mixing implementation into it. While I agree this is an subjective choice of code style, it has nothing to do with the compiler warning or lint, so let us keep the way as it is |
Change updated and synced with master again. Waiting for the checks: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One final comment on alignment, once it is fixed, we can merge it in
@tqchen Your final comment was addressed. The check comes back all green: |
@Anthony-Mai somehow the commits seems to be messed up, this is likely due to the fact that you did a merge instead of rebase. Please try some of the tips in https://docs.tvm.ai/contribute/git_howto.html, you can start to apply your patches from a clean state. |
Default compilation of Linux shared library modules (*.so files) exports all symbols. This creates large module files as the export symbol table contains too many entries. The correct approach is to export nothing by default. Anything that needs to be exported must be explicitly specified. This is done by the following steps: In the Makefile, add "-fvisibility=hidden" flag. You can search for "-fPIC" to find the appropriate place to add the flag. This hides symbols by default if not explicitly specified otherwise. To declare of any symbol to be exported, add this attribute: __attribute__((visibility("default"))) The attribute string can be added using a macro definition. It should be added right before the return type for functions, or right after the 'class' or 'struct' keyword for class/struct. To supress Doxygen parser warnings, modify docs/Doxyfile and add to PRE_DEFINED: TVM_DLL= NNVM_DLL= __attribute__(x)= For more info on shared module export symbol visibility read: https://gcc.gnu.org/wiki/Visibility Update submodule HalideIR to 7a3287d3883fdeac3aba2a7f3865c7ab78e1925c and dlpack to 5c792cef3aee54ad8b7000111c9dc1797f327b59. Explicitly export __gnu_f2h_ieee() which is needed in a unit test. Move the visibility specifier to header files.
@tqchen Thanks for the tip https://docs.tvm.ai/contribute/git_howto.html That was exactly what messed up. I used git pull to rebase to upstream instead of the correct way of rebase upstream/master. I used your method and it is much cleaner. Now it shows only the files I actually modified, and the rebasing went much smoother. I also fixed the remaining alignment of runtime.h. Please review again. |
Thanks, @Anthony-Mai, @FrozenGene ! this is now merged |
Thanks @FrozenGene and @tqchen for spending time to review. And thanks for teaching me the correct way of rebase with upstream master. Cheers! To give an idea how much making the default symbol visibility as hidden would save. here is the a comparison of before and after module sizes: |
exports all symbols. This creates large module files as the export
symbol table contains too many entries. The correct approach is
to export nothing by default. Anything that needs to be exported
must be explicitly specified. This is done by the following steps:
For more info on shared module export symbol visibility read:
https://gcc.gnu.org/wiki/Visibility
Thanks for contributing to TVM! Please refer to guideline https://docs.tvm.ai/contribute/ for useful information and tips. After the pull request is submitted, please request code reviews from Reviewers.