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

tools/test: adding tools for splitting up mock headers #12150

Merged
merged 51 commits into from
Aug 28, 2020

Conversation

foreseeable
Copy link
Contributor

@foreseeable foreseeable commented Jul 17, 2020

Signed-off-by: Muge Chen mugechen@google.com

Commit Message: adding tools for splitting up mock headers.
Risk level: low
Testing: Build succeeds.

We need to reduce resource consumption of test compilation by simplifying mock library inclusions. #10917
One way to do that is to break the monolithic mock headers into different mock classes and then refactor the code base (like #12053 #12051 #11797)
It's hard to refactor them manually. So I wrote headersplit, a tool based on libclang and python to help me divide the monolithic mock header and replace includes after dividing automatically. This tool can also generate building time comparison between before/after refactoring.

Signed-off-by: Muge Chen <mugechen@google.com>
@foreseeable
Copy link
Contributor Author

\cc @ahedberg @bbarenblat

Copy link
Contributor

@ahedberg ahedberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of us will do a more in-depth review later, but here are some high-level comments to get started.

Please also fix the formatting CI.

tools/envoy_headersplit/README.md Outdated Show resolved Hide resolved
tools/envoy_headersplit/README.md Outdated Show resolved Hide resolved
tools/envoy_headersplit/README.md Outdated Show resolved Hide resolved
tools/envoy_headersplit/changed.txt Outdated Show resolved Hide resolved
tools/envoy_headersplit/replace_includes.py Show resolved Hide resolved
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
tools/envoy_headersplit/README.md Outdated Show resolved Hide resolved
tools/envoy_headersplit/README.md Outdated Show resolved Hide resolved
tools/envoy_headersplit/README.md Outdated Show resolved Hide resolved
tools/envoy_headersplit/headersplit.py Outdated Show resolved Hide resolved
tools/envoy_headersplit/headersplit.py Outdated Show resolved Hide resolved
tools/envoy_headersplit/headersplit.py Outdated Show resolved Hide resolved
tools/envoy_headersplit/headersplit_test.py Outdated Show resolved Hide resolved
tools/envoy_headersplit/headersplit_test.py Outdated Show resolved Hide resolved
tools/envoy_headersplit/replace_includes.py Outdated Show resolved Hide resolved
tools/envoy_headersplit/replace_includes_test.py Outdated Show resolved Hide resolved
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
tools/envoy_headersplit/headersplit.py Outdated Show resolved Hide resolved
tools/envoy_headersplit/headersplit.py Outdated Show resolved Hide resolved
tools/envoy_headersplit/headersplit_test.py Show resolved Hide resolved
tools/envoy_headersplit/headersplit_test.py Outdated Show resolved Hide resolved
tools/envoy_headersplit/replace_includes.py Show resolved Hide resolved
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
@foreseeable
Copy link
Contributor Author

\cc @htuch

Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I like where you're going with trying to make things more hermetic and nice work on getting tests happening. Some feeedback to hopefully get this to a final state.
/wait

@@ -14,6 +14,10 @@ def _python_deps():
name = "protodoc_pip3",
requirements = "@envoy//tools/protodoc:requirements.txt",
)
pip3_import(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm the pip3 trick is so you can bring in Clang as a Python dependency during test via requirements.txt? @lizan @PiotrSikora is there going to be some Wasm dependency that eventually gives us this more directly? I think what is here right now is fine for now though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I have to install the clang module so that I can use them at test.

tools/envoy_headersplit/requirements.txt Outdated Show resolved Hide resolved
ci/do_ci.sh Outdated Show resolved Hide resolved
ci/do_ci.sh Outdated Show resolved Hide resolved
py_test(
name = "headersplit_test",
srcs = [
"headersplit.py",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't you depend on headersplit_pip3 and then not bring in the file directly?

tools/envoy_headersplit/headersplit.py Outdated Show resolved Hide resolved
tools/envoy_headersplit/headersplit.py Show resolved Hide resolved
tools/envoy_headersplit/headersplit.py Outdated Show resolved Hide resolved
)
""".format(to_filename(class_name), to_filename(class_name), to_filename(class_name))
with open("BUILD", "a") as bazel_file:
bazel_file.write(bazel_text)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is append, this script is somewhat non-idempotent. What happens if you run it multiple times?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it will add rule for same mock class target for multiple times.
Now I add statements to check if the target has been already appended. So now it will only add once if run multiple times

@@ -0,0 +1,12 @@
# Envoy Header Split
Tool for spliting monolithic header files in Envoy to speed up compilation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How often do you think Envoy developers should be running this? Is this a once a year kind of cleanup?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the period could be several months or a year. It should be long enough until we get some monolithic mock headers appeared in Envoy repository.

Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
@foreseeable
Copy link
Contributor Author

@htuch can you have a look again?
I fixed some style issue. llvm-config is no longer needed to run the scripts since clang is installed from pip3. (But we still need to run the test un-sandboxed)

Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, let's add the TODO and ship it. Awesome work!

main = "headersplit_test.py",
python_version = "PY3",
srcs_version = "PY3",
tags = ["no-sandbox"],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some TODOs to dig into this? I'm still unclear on the interaction with --spawn_strategy=local.

Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Muge Chen <mugechen@google.com>
Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@htuch htuch merged commit a6cfb35 into envoyproxy:master Aug 28, 2020
@@ -45,6 +45,11 @@ function exclude_testdata() {
grep -v tools/testdata/check_format/
}

# Do not run clang-tidy on envoy_headersplit testdata files.
function exclude_testdata() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that you redefined the exclude_testdata function and effectively undid the tools/testdata/check_format exclusion a few lines up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch! Thanks for fix it

clarakosi pushed a commit to clarakosi/envoy that referenced this pull request Sep 3, 2020
)

We need to reduce resource consumption of test compilation by simplifying mock library inclusions. envoyproxy#10917
One way to do that is to break the monolithic mock headers into different mock classes and then refactor the code base (like envoyproxy#12053 envoyproxy#12051 envoyproxy#11797)
It's hard to refactor them manually. So I wrote headersplit, a tool based on libclang and python to help me divide the monolithic mock header and replace includes after dividing automatically. This tool can also generate building time comparison between before/after refactoring.

Risk level: low
Testing: Build succeeds.

Signed-off-by: Muge Chen <mugechen@google.com>
Signed-off-by: Clara Andrew-Wani <candrewwani@gmail.com>
@@ -0,0 +1,103 @@
# Lint as: python3
Copy link
Contributor

@antoniovicente antoniovicente Jan 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm having trouble getting this test to run locally or in CI. See https://dev.azure.com/cncf/4684fb3d-0389-4e0b-8251-221942316e06/_apis/build/builds/63187/logs/48 from PR #14615 which tries to add //tools/... to CI

Do you know what may be going wrong?

======================================================================
ERROR: test_class_definitions (__main__.HeadersplitTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/b/f/w/bazel-out/k8-opt/bin/tools/envoy_headersplit/headersplit_test.runfiles/headersplit_pip3_pypi__clang_10_0_1/clang/cindex.py", line 4172, in get_cindex_library
    library = cdll.LoadLibrary(self.get_filename())
  File "/usr/lib/python3.6/ctypes/__init__.py", line 426, in LoadLibrary
    return self._dlltype(name)
  File "/usr/lib/python3.6/ctypes/__init__.py", line 348, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: libclang-10.so: cannot open shared object file: No such file or directory

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/b/f/w/bazel-out/k8-opt/bin/tools/envoy_headersplit/headersplit_test.runfiles/envoy/tools/envoy_headersplit/headersplit_test.py", line 55, in test_class_definitions
    idx = Index.create()
  File "/b/f/w/bazel-out/k8-opt/bin/tools/envoy_headersplit/headersplit_test.runfiles/headersplit_pip3_pypi__clang_10_0_1/clang/cindex.py", line 2698, in create
    return Index(conf.lib.clang_createIndex(excludeDecls, 0))
  File "/b/f/w/bazel-out/k8-opt/bin/tools/envoy_headersplit/headersplit_test.runfiles/headersplit_pip3_pypi__clang_10_0_1/clang/cindex.py", line 212, in __get__
    value = self.wrapped(instance)
  File "/b/f/w/bazel-out/k8-opt/bin/tools/envoy_headersplit/headersplit_test.runfiles/headersplit_pip3_pypi__clang_10_0_1/clang/cindex.py", line 4146, in lib
    lib = self.get_cindex_library()
  File "/b/f/w/bazel-out/k8-opt/bin/tools/envoy_headersplit/headersplit_test.runfiles/headersplit_pip3_pypi__clang_10_0_1/clang/cindex.py", line 4177, in get_cindex_library
    raise LibclangError(msg)
clang.cindex.LibclangError: libclang-10.so: cannot open shared object file: No such file or directory. To provide a path to libclang use Config.set_library_path() or Config.set_library_file().

@repokitteh-read-only repokitteh-read-only bot added the deps Approval required for changes to Envoy's external dependencies label Jan 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
deps Approval required for changes to Envoy's external dependencies
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants