summaryrefslogtreecommitdiff
path: root/bin/find-mergedlib-can-be-private.py
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2020-03-04 20:27:36 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2020-03-06 08:18:06 +0100
commit47b4ee1a1a2a0212ffcf3e85647e9f9f67276ee3 (patch)
tree4dc94e2ea216efee2b583a9fa4ecd13fe884889d /bin/find-mergedlib-can-be-private.py
parentcedc8a942e451a63dd1e7dae7f25642c0fcb4be8 (diff)
limit symbols exported when using --enable-mergelibs
when doing LTO and --enable-mergelibs, we can improve the effectiveness of LTO by marking more code as internal to the merged library. So introduce a new macro UNLESS_MERGELIBS, which we can wrap around *_DLLPUBLIC annotations Also introduced here is a script that can be run on a completed build to determine which classes can be marked with this macro. Change-Id: I73fb87c897489da53791277d0b66b01f884ba061 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89991 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'bin/find-mergedlib-can-be-private.py')
-rwxr-xr-xbin/find-mergedlib-can-be-private.py152
1 files changed, 152 insertions, 0 deletions
diff --git a/bin/find-mergedlib-can-be-private.py b/bin/find-mergedlib-can-be-private.py
new file mode 100755
index 000000000000..572cd1c8e005
--- /dev/null
+++ b/bin/find-mergedlib-can-be-private.py
@@ -0,0 +1,152 @@
+#!/usr/bin/python2
+#
+# Generate a custom linker script/map file for the --enabled-mergedlibs merged library
+# which reduces the startup time and enables further optimisations with --enable-lto because 60% or more
+# of the symbols become internal only.
+#
+
+import subprocess
+import sys
+import re
+
+exported_symbols = set()
+imported_symbols = set()
+
+
+# Copied from solenv/gbuild/extensions/pre_MergedLibsList.mk
+# TODO there has to be a way to run gmake and get it to dump this list for me
+merged_libs = { \
+ "avmedia" \
+ ,"basctl" \
+ ,"basprov" \
+ ,"basegfx" \
+ ,"canvasfactory" \
+ ,"canvastools" \
+ ,"comphelper" \
+ ,"configmgr" \
+ ,"cppcanvas" \
+ ,"crashreport)" \
+ ,"dbtools" \
+ ,"deployment" \
+ ,"deploymentmisc" \
+ ,"desktopbe1)" \
+ ,"desktop_detector)" \
+ ,"drawinglayer" \
+ ,"editeng" \
+ ,"expwrap" \
+ ,"filterconfig" \
+ ,"fsstorage" \
+ ,"fwe" \
+ ,"fwi" \
+ ,"fwk" \
+ ,"helplinker)" \
+ ,"i18npool" \
+ ,"i18nutil" \
+ ,"lng" \
+ ,"localebe1" \
+ ,"mcnttype" \
+ ,"msfilter" \
+ ,"mtfrenderer" \
+ ,"opencl" \
+ ,"package2" \
+ ,"sax" \
+ ,"sb" \
+ ,"simplecanvas" \
+ ,"sfx" \
+ ,"sofficeapp" \
+ ,"sot" \
+ ,"spl" \
+ ,"stringresource" \
+ ,"svl" \
+ ,"svt" \
+ ,"svx" \
+ ,"svxcore" \
+ ,"tk" \
+ ,"tl" \
+ ,"ucb1" \
+ ,"ucbhelper" \
+ ,"ucpexpand1" \
+ ,"ucpfile1" \
+ ,"unoxml" \
+ ,"utl" \
+ ,"uui" \
+ ,"vcl" \
+ ,"xmlscript" \
+ ,"xo" \
+ ,"xstor" }
+
+classes_with_exported_symbols = set()
+classes_with_imported_symbols = set()
+
+# look for symbols exported by libmerged
+subprocess_nm = subprocess.Popen("nm -D instdir/program/libmergedlo.so", stdout=subprocess.PIPE, shell=True)
+with subprocess_nm.stdout as txt:
+ # We are looking for lines something like:
+ # 0000000000036ed0 T flash_component_getFactory
+ line_regex = re.compile(r'^[0-9a-fA-F]+ T ')
+ for line in txt:
+ line = line.strip()
+ if line_regex.match(line):
+ exported_symbols.add(line.split(" ")[2])
+subprocess_nm.terminate()
+
+# look for symbols imported from libmerged
+subprocess_find = subprocess.Popen("(find instdir/program/ -type f; ls ./workdir/LinkTarget/CppunitTest/*.so) | xargs grep -l mergedlo",
+ stdout=subprocess.PIPE, shell=True)
+with subprocess_find.stdout as txt:
+ for line in txt:
+ sharedlib = line.strip()
+ s = sharedlib[sharedlib.find("/lib") + 4 : len(sharedlib) - 3]
+ if s in merged_libs: continue
+ # look for imported symbols
+ subprocess_objdump = subprocess.Popen("objdump -T " + sharedlib, stdout=subprocess.PIPE, shell=True)
+ with subprocess_objdump.stdout as txt2:
+ # ignore some header bumpf
+ txt2.readline()
+ txt2.readline()
+ txt2.readline()
+ txt2.readline()
+ # We are looking for lines something like (noting that one of them uses spaces, and the other tabs)
+ # 0000000000000000 DF *UND* 0000000000000000 _ZN16FilterConfigItem10WriteInt32ERKN3rtl8OUStringEi
+ for line2 in txt2:
+ line2 = line2.strip()
+ if line2.find("*UND*") == -1: continue
+ tokens = line2.split(" ")
+ sym = tokens[len(tokens)-1].strip()
+ imported_symbols.add(sym)
+ subprocess_objdump.terminate()
+subprocess_find.terminate()
+
+intersec_symbols = exported_symbols.intersection(imported_symbols)
+print("no symbols exported from libmerged = " + str(len(exported_symbols)))
+print("no symbols that can be made internal = " + str(len(intersec_symbols)))
+
+# Now look for classes where none of the class symbols are imported,
+# i.e. we can mark the whole class as hidden
+
+def extract_class(sym, add_to_set):
+ filtered_sym = subprocess.check_output(["c++filt", sym]).strip()
+ if filtered_sym.startswith("vtable for "):
+ classname = filtered_sym[11:]
+ add_to_set.add(classname)
+ return
+ if filtered_sym.startswith("non-virtual thunk to "):
+ filtered_sym = filtered_sym[21:]
+ elif filtered_sym.startswith("virtual thunk to "):
+ filtered_sym = filtered_sym[17:]
+ i = filtered_sym.find("(")
+ if i != -1:
+ i = filtered_sym.rfind("::", 0, i)
+ if i != -1:
+ classname = filtered_sym[:i]
+ add_to_set.add(classname)
+
+for sym in exported_symbols:
+ extract_class(sym, classes_with_exported_symbols)
+for sym in imported_symbols:
+ extract_class(sym, classes_with_imported_symbols)
+
+with open("bin/find-mergedlib-can-be-private.classes.results", "wt") as f:
+ for sym in sorted(classes_with_exported_symbols - classes_with_imported_symbols):
+ if sym.startswith("std::") or sym.startswith("void std::"): continue
+ f.write(sym + "\n")