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

[CRT] Create C-runtime-style metadata module for llvm builds #7398

Merged
merged 20 commits into from
Feb 23, 2021

Conversation

areusch
Copy link
Contributor

@areusch areusch commented Feb 3, 2021

This PR is a follow-on to #7002 and continues its work to support BYOC functions with the llvm TVM target with the C runtime. Though the BYOC flow is supported with the TVM C++ runtime, this support depends heavily on dlsym and shared library support, neither of which are required to use the TVM C runtime.

This PR can roughly be thought of in these parts:

  • Build a corresponding runtime.CreateLLVMCrtMetadataModule PackedFunc to the runtime.CreateCSourceCrtMetadataModule. Also add crt here to distinguish between these metadata modules (which are intended to be compiled) and runtime::MetadataModule (which is intended to be directly loaded into the TVM compiler c++ runtime)
  • Move FuncRegistry and TVMSystemLibEntryPoint LLVM generator into a new LLVMModule instance. Change function registry to declare extern functions rather than using internal linkage.
  • Allow tvm.micro.build_static_runtime to accept object files from the LLVM backend. This temporarily solution allows us to build llvm-targeted code using microTVM.

Copy link
Contributor

@manupak manupak left a comment

Choose a reason for hiding this comment

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

Just a heads up that you might want to know.

csource_modules.push_back(target_module);
target_module = CreateCSourceCrtMetadataModule(csource_modules, target);
} else if (target->kind->name == "llvm") {
binary_modules.push_back(target_module);
Copy link
Contributor

@manupak manupak Feb 4, 2021

Choose a reason for hiding this comment

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

I think target_module should not be a binary module that gets imported inside non-DSOExportable metadata module.
I think csource_modules --> dso_modules and binary_modules --> non_dso_modules would be better. Moreover, non-DSOExportable metadata module should not be created if non of the modules need constant loading.

TL;DR
This one is little complex to explain. Let me use some definitions first (and feel free to change the names as you see fit).

[Defn.1] binary module : a runtime.Module that is not DSOExportable (not of type "c" or "llvm").
[Defn.2][NCL (needs constant loading) module : a module that requires constant loading in the init process.

As of today these two things are not strictly orthogonal. (i.e. DSOExportabe module could use constant loading -- though the only one is the example byoc c codegen).

So technically any module that implements get_func_names could be imported under the DSOExportable metadata module (llvm -- the one this PR introduces or c -- the one I introduced before). However, currently the only ones that get imported inside DSOExportable metadata module are modules that are !("binary" or "NCL"). So I had a hard time finding the name and end-up calling them binary modules.

Copy link
Contributor Author

@areusch areusch Feb 4, 2021

Choose a reason for hiding this comment

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

As of today these two things are not strictly orthogonal. (i.e. DSOExportabe module could use constant loading -- though the only one is the example byoc c codegen).

Do you mean "(I.e. binary module could use constant loading..." here?

okay I think my point of confusion here (and I think it's related to lack of experience with BYOC) is: what makes metadata module non-DSO-exportable?

Copy link
Contributor

@manupak manupak Feb 4, 2021

Choose a reason for hiding this comment

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

runtime::MetadataModuleCreate() --> is non-DSO-exportable it gets packed into to devc.{o/c} and I think we should only need this if we have modules that require constant loading. This one is of type "metadata". Im talking about the one that is created in line 96.

I mean DSOExportable modules could still use constant loading -- though I think its not very useful since we have linked params now. Only remaining place is the example c byoc codegen that uses the constant loading process as a demo to all BYOC codegens -- I think.

Thus, if none of the modules does not require constant loading -- that is indicated by arrays.empty() -- we dont need to create the non-DSOExportable metadata module.

See the diagram here : https://discuss.tvm.apache.org/t/csourcemetadata-module-a-csourcemodule-to-hold-function-registry-for-utvm/8554.

Does that make sense ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okay so let me summarize my understanding:

  1. at the end of the day, we want to produce a single module that imports all the others
  2. This function gets the Module that implements target_host (target_module) plus a list of all the BYOC modules (ext_modules).
  3. when building for the C++ runtime, we have runtime::MetadataModule for this root module. We assume each Module inext_modules contains exactly one Relay function whose name is get_symbol() and which may use ConstantNodes whose values must be initialized from get_const_vars(). get_func_names() is unused because dlsym is used to resolve functions in the C++ runtime.
  4. when building for the C runtime, we use either the CSourceMetadataModule from Created CSourceMetaData module for model metadata #7002 or LLVMCrtMetadataModule from this PR. These are both DSO-exportable. The CSourceMetadataModule queries function names from and imports all DSO-exportable modules which don't define any const_vars. Let's call these "CRT-exportable modules" since we don't have a good name for them.
  5. Then, any modules which are: a) non-DSO-exportable, b) not codegen'd by c or llvm backend, OR c) not defining any const_vars are imported into the resulting metadata module.

Presumably then the LLVM module should work the same way as the C-source one, the only change needed being that target->kind->name == "llvm" should also admit DSO-exportable functions to csource_modules.

Then, I'd propose the following name changes:

  • csource_modules -> crt_exportable_modules
  • binary_modules -> non_crt_exportable_modules

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, this seems right :)
Let me just tighten the point 5

"5.) Then, any modules which are: a) non-DSO-exportable OR b) (not defining any const_vars OR result of get_const_vars() is empty() ) are imported into the resulting (here resulting means at least one of the two conditions is met) metadata module."

Summary is 5b is covered 5a and metadata module of type "metadata" should only be created if one of the above condition is met.
Moreover, c runtime does not support ProcessModuleBlob(Im talking about : src/runtime/library_module.cc) anyway -- does it ? -- that could be used as a blanket assertion to check whether all modules are !5a and !5b if the target says c runtime ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah that seems right. I think we've come to similar conclusions. I think there are a couple of larger issues to be resolved here:

  1. When targeting the C runtime, an entirely different strategy than MetadataModule is needed to export Modules which don't run on the target_host CPU. This isn't well-defined yet. Model Library Format RFC also touches on this, but doesn't resolve it.
  2. Related to resolving this conundrum: the model of the C++ runtime is that some library running on target_host parses binary configuration data in MetadataModule and then configures any runtime libraries or accelerators. This is generally used to implement BYOC. C runtime does not want to require any startup procedure that involves parsing binary blobs using RAM--instead, this must happen at code-generation time. This means that we need to do a better job here of organizing Module according to the DLContext which will be executing those modules.

Here we've mostly fixed problem 1. In future PR and RFC, we can work to address problem 2. Let me know if that makes sense to you!

Copy link
Contributor

@manupak manupak Feb 15, 2021

Choose a reason for hiding this comment

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

@areusch , few clarfications :

  1. The MetadataModule of type "metadata" is a another module that get loaded using ProcessModuleBlob in c++ runtime. Therefore, I would not agree to "MetadataModule is needed to export Modules ". For e.g., currently ARM Ethos-N that uses ProcessModuleBlob does not require MetadataModule of type "metadata" as it does not need any constants to be loaded into it in the init process. Having said that, what I agree with you is that ProcessModuleBlob should not be the way to do things in C runtime -- more specifically in uTVM environments. So you can think of MetadataModule of type "metadata" as a peer to all runtime modules that gets "packed" to use ProcessModuleBlob in the runtime.

  2. Similarly, I would not agree "target_host parses binary configuration data in MetadataModule and then configures any runtime libraries or accelerators", because MetadataModule of type "metadata" only have the constants and other binaries go inside devc.c/o independently of MetadataModule of type "metadata".

I agree that " C runtime does not want to require any startup procedure that involves parsing binary blobs using RAM--instead, this must happen at code-generation time.".

"This means that we need to do a better job here of organizing Module according to the DLContext which will be executing those modules." -- This I agree. First thing is we need to move away from the assumption that BYOC flows always generate non-DSO-exportable runtime.Modules that is not currently true for our ongoing ARM Ethos-U work. We will be producing a DSOExportable runtime.Module. One side note to this, we might want to integrate the BYOC (possiblly not call it BYOC :) ) in the compilation pathway as it offers IRModule --> runtime.Module conversion generally and TVM's internal module compilation is "a" way of producing it. I have made a similiar comment here : #7428

So towards that goal, I think we need a mechanism to identify the DLContext without relying on their type being "c" or "llvm" as they could possiblly be coming from a BYOC flow. There should be a primary key in the runtime.Module to say its DLContext, IMHO.

Copy link
Contributor Author

@areusch areusch Feb 16, 2021

Choose a reason for hiding this comment

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

Therefore, I would not agree to "MetadataModule is needed to export Modules ". For e.g., currently ARM Ethos-N that uses ProcessModuleBlob does not require MetadataModule of type "metadata" as it does not need any constants to be loaded into it in the init process.

sure, but it depends on ProcessModuleBlob calling runtime.module.loadbinary_ethos-n, right? This is the part I think of most concern going forward--for µTVM, and I think we could say more broadly for CRT (no reason to support two flows in one runtime) we want to make it possible to do as much of this logic at compile time to produce a firmware binary that requires minimal startup procedures.

So you can think of MetadataModule of type "metadata" as a peer to all runtime modules that gets "packed" to use ProcessModuleBlob in the runtime.

this makes sense to me, but I'd further qualify it to "all non-DSO-exportable runtime modules," at least for now.

Similarly, I would not agree "target_host parses binary configuration data in MetadataModule and then configures any runtime libraries or accelerators", because MetadataModule of type "metadata" only have the constants and other binaries go inside devc.c/o independently of MetadataModule of type "metadata".

You're right--I was getting this confused with codegen_blob since the FuncRegistry logic doesn't have an explicit home in C++ land.

So towards that goal, I think we need a mechanism to identify the DLContext without relying on their type being "c" or "llvm" as they could possiblly be coming from a BYOC flow. There should be a primary key in the runtime.Module to say its DLContext, IMHO.

I agree with a few clarifications. Perhaps better to discuss on the forum. The main points are: all BYOC are ext_dev, and perhaps some SoC may have a set of identical accelerators, some configured with one program and some with another. We probably should just consider how to support that case now rather than have to refactor that later--I think the difference is minor and amounts to coming up with another name for runtime::Module which indicates a) which device_type or BYOC accelerator the module is to run on and b) if multiple such things exist, a sort of "program name" for the particular accelerator program being generated.

@areusch areusch marked this pull request as ready for review February 12, 2021 22:41
@areusch
Copy link
Contributor Author

areusch commented Feb 12, 2021

Copy link
Contributor

@manupak manupak left a comment

Choose a reason for hiding this comment

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

Thanks for hard work!
Broadly LGTM, just a one clarification about a test.

global TARGET
old_target = TARGET
try:
TARGET = tvm.target.Target("llvm " + str(TARGET)[2:])
Copy link
Contributor

Choose a reason for hiding this comment

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

Not very clear to me what is going on here ?
I would imagine we would want to test both llvm and c targets, right ?
May I ask why is the need for try-finally here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

clarified a bit--i'm being lazy and reusing test_compile_runtime

Copy link
Member

@zhiics zhiics left a comment

Choose a reason for hiding this comment

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

The changes for metadata module and csource module look good to me, please fix the ci

python/tvm/micro/compiler.py Outdated Show resolved Hide resolved
Copy link
Contributor

@manupak manupak left a comment

Choose a reason for hiding this comment

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

LGTM

@areusch
Copy link
Contributor Author

areusch commented Feb 22, 2021

@zhiics merge?

@tmoreau89 tmoreau89 merged commit 0ba3741 into apache:main Feb 23, 2021
@tmoreau89
Copy link
Contributor

Thank you @areusch @zhiics @manupa-arm the PR has been merged.

Lokiiiiii pushed a commit to Lokiiiiii/tvm that referenced this pull request Mar 2, 2021
…7398)

* Create C-runtime-style metadata module for llvm builds.

* maybe address manupa's comment

* lint

* actually address manupa comments

* comment and rename

* git-clang-format

* pylint

* cpp warning

* try to fix apps/bundle_deploy

* black format

* build correct file

* Use save() for C++-runtime targeted artifacts.

* fix build_module LLVM metadata module conditions

* fix test comment

* black format

* further restrict CRT MetadataModule creation

* Fix test_link_params

* black format and address zhiics comments

* fix test_link_params, i think?
trevor-m pushed a commit to neo-ai/tvm that referenced this pull request Mar 2, 2021
…7398)

* Create C-runtime-style metadata module for llvm builds.

* maybe address manupa's comment

* lint

* actually address manupa comments

* comment and rename

* git-clang-format

* pylint

* cpp warning

* try to fix apps/bundle_deploy

* black format

* build correct file

* Use save() for C++-runtime targeted artifacts.

* fix build_module LLVM metadata module conditions

* fix test comment

* black format

* further restrict CRT MetadataModule creation

* Fix test_link_params

* black format and address zhiics comments

* fix test_link_params, i think?
@trevor-m
Copy link
Contributor

trevor-m commented Mar 2, 2021

FYI, this appears to break TVM builds with USE_LLVM=OFF. Will try to come up with a fix

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

Successfully merging this pull request may close these issues.

5 participants