-
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
[uTVM] Initial BYOC support with c-source module #6950
Conversation
manupak
commented
Nov 23, 2020
- Current flow uses saves the module as a c source and compiles it seperately. This blocks multi-module compilation.
- This patch upgrades it to use export_library which supports external modules.
- Added BYOC support for uTVM and testing
- A new member for IRModule to carry external function names as they are required to create the function registry when creating a system-lib.
I'm not familiar with uTVM. Out of curiosity, how uTVM uses BYOC codegen C? I ask because BYOC codegen C is just for demonstration purpose so its functionality is not complete. |
@comaniac , Likewise this is also for demonstration purpose but in the uTVM context. i.e., if we can annotate and offload a set of operations and produce a c-source that can do the required computations and return the DLTensors, this is to show it works in the uTVM context. Thus, we do not intend to use "ccompiler" as the solution rather to show a external codegen that could create c-source the place of the "ccompiler", the changes done here should enable the compilation of a such a source. Moreover, we do not prefer the metadata packing of Imports (using PackImports* methods) as they will re-create the artifacts in the volatile memory. However, having a c-source gives much better control as to where the artifacts should be placed through a standard linker script. |
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.
LGTM to the codegen C part.
891e53f
to
16a51f9
Compare
Happy new year to you all! . After CSourceMetadata module, this PR got reduced to introducing a simple test for utvm byoc example and some adjustments to external c-source code generator to make it applicable for uTVM as well. We would like to carry this test to ensure external module compilation works in uTVM. Please take a look when you have time. |
// These are only needed to handle metadata copying | ||
code_stream_ << "#include <tvm/runtime/container.h>\n"; | ||
code_stream_ << "#include <tvm/runtime/packed_func.h>\n"; | ||
code_stream_ << "#include <dlpack/dlpack.h>\n"; |
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 think packed_func is probably needed to handle packed args. dlpack has to be included if we have DLTensor. The reason it doesn't cause errors is probably because c_runtime_api.h includes it as well or we don't use DLTensor at all.
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.
Yes, dlpack is in the c_runtime_api.h, thus we can remove it altogether.
Do we need packed_func.h ? -- I would like to avoid if the constants copying process is not required. The obvious usage is from TVM_DLL_EXPORT_TYPED_FUNC macro here which creates C++ code. Hence the gating based on presence of constants.
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.
@zhiics to clarify this codegen is just meant to generate C code, correct? we just got away with generating C++ code because export_library always writes .cc files. i also see that the BYOC blogpost has -std=c++14
as a compiler arg, but is that necessary with this simple codegen_c?
it looks like the purpose of TVM_DLL_EXPORT_TYPED_FUNC is to do some limited argument type validation and translate the function call signature from TVMBackendPackedCFunc into a series of primitive pointers. what's confusing is that theoretically we shouldn't need to go through C++ to do this, and you wouldn't expect that to happen since this is called, well, CodegenC.
it seems like the typechecking is actually not buying us much, because it doesn't actually check the element datatype of any DLTensors passed-in. Here, we just static_cast
and presume the element datatype matches. if that's true, i'd propose (perhaps not in this PR) that we get rid of the dependency on TVM_DLL_EXPORT_TYPED_FUNC here. I think we should aim to have the same C header dependencies as the c
target codegen in src/target/source/codegen_c_host.cc
.
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.
@areusch Yeah, we used it to generated C++ code before when working on BYOC. But I think you are right, we should just export C code and get rid of the dependency of TVM_DLL_EXPORT_TYPED_FUNC
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 removed dlpack for now and since we need to have Array<NDArray> here, we cant get away not using C++ here. Therefore, I might as well use the macro for convenience here.
However, I made it obvious that this part is not codegen'd/ not visible for a c-compiler.
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.
@manupa-arm happy new year and thanks for continuing to push this forward. this looks pretty good, just a couple small things and some clarifying questions (as I'm not as familiar with codegen_c internals as I should be).
code_stream_ << "#include <tvm/runtime/container.h>\n"; | ||
code_stream_ << "#include <tvm/runtime/packed_func.h>\n"; | ||
code_stream_ << "#include <dlpack/dlpack.h>\n"; | ||
code_stream_ << "using namespace tvm::runtime;\n"; |
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.
how come we dropped std::malloc
yet have a using decl here?
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.
Actually this segment is only to be generated in the presence of constant copying process and makes this source a C++ one. To this end, there is a init function that accepts "Array<NDArray> arr" (See in codegen_c.h) that is in that namespace. I could not think of a way to make it a C source immediately.
Honestly, I was less worried about it as this is an example codegen and in utvm we dont want to be doing constant copying anyway. Therefore this segment will not be codegen'd. I understand its not ideal. However, the purpose of this test was to keep c-source base external codegen support (without constant copying -- which is controlled by constant extraction relay pass) in uTVM
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.
hrm. should we then add code like:
#ifdef __cplusplus
using std::malloc;
#endif
you're right this is a demo codegen, perhaps we don't need to resolve this. it's just confusing to create c++ code in a codegen named codegen_c.
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.
@areusch So I made it obvious this segment is C++ in the code. See if it works.
tests/micro/qemu/test_zephyr.py
Outdated
|
||
def check_result(relay_mod, model, zephyr_board, map_inputs, out_shape, result): | ||
"""Helper function to verify results""" | ||
tol = 1e-5 |
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.
can you make this a module-level all-CAPS constant?
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.
Done
code_stream_ << "#include <tvm/runtime/c_backend_api.h>\n"; | ||
code_stream_ << "#include <tvm/runtime/crt/module.h>\n"; | ||
if (!variables.empty()) { | ||
// These are only needed to handle metadata copying |
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.
nitpick: delete "only" here--that statement is true only at this moment.
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.
Done and added a longer description to say why C++ code is generated, at least in this moment.
// These are only needed to handle metadata copying | ||
code_stream_ << "#include <tvm/runtime/container.h>\n"; | ||
code_stream_ << "#include <tvm/runtime/packed_func.h>\n"; | ||
code_stream_ << "#include <dlpack/dlpack.h>\n"; |
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.
@zhiics to clarify this codegen is just meant to generate C code, correct? we just got away with generating C++ code because export_library always writes .cc files. i also see that the BYOC blogpost has -std=c++14
as a compiler arg, but is that necessary with this simple codegen_c?
it looks like the purpose of TVM_DLL_EXPORT_TYPED_FUNC is to do some limited argument type validation and translate the function call signature from TVMBackendPackedCFunc into a series of primitive pointers. what's confusing is that theoretically we shouldn't need to go through C++ to do this, and you wouldn't expect that to happen since this is called, well, CodegenC.
it seems like the typechecking is actually not buying us much, because it doesn't actually check the element datatype of any DLTensors passed-in. Here, we just static_cast
and presume the element datatype matches. if that's true, i'd propose (perhaps not in this PR) that we get rid of the dependency on TVM_DLL_EXPORT_TYPED_FUNC here. I think we should aim to have the same C header dependencies as the c
target codegen in src/target/source/codegen_c_host.cc
.
This commit mainly introduces a byoc c-source module example to uTVM. Moreover, it carries certain modifications to the example codegen_c external module generator code to generate utvm friendly c-source. Change-Id: I09f3a42017d518dd5b6c89e3fe0a0332b80088b0
I've addressed all the minor comments. The current limitation of making this generator a pure C code generator is that is carries a Array<NDArray> for constants that will be copied in, if required by the compilation pipeline. I feel changing this is a bigger work and its only there to test the external codegen/runtime pathway (especially the JSONRuntime) handles the constant copying. Therefore, given that we have Array<NDArray>, I might as well use the macro. However, I clearly commented and made it obvious that bit of the code is C++ (using ifdef __cplusplus as @areusch suggested.) Therefore, in the absense of the constant copying, this will generate a pure C code -- If you see I have removed macro usage for the main compute function (its just the constant copying one uses it). Let me know your thoughts and what more could be done about it, if any. |
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.
looks good, thanks for bearing with me @manupa-arm!
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.
LGTM. Thanks for the effort.
Thanks @manupa-arm @areusch |
This commit mainly introduces a byoc c-source module example to uTVM. Moreover, it carries certain modifications to the example codegen_c external module generator code to generate utvm friendly c-source. Change-Id: I09f3a42017d518dd5b6c89e3fe0a0332b80088b0
This commit mainly introduces a byoc c-source module example to uTVM. Moreover, it carries certain modifications to the example codegen_c external module generator code to generate utvm friendly c-source. Change-Id: I09f3a42017d518dd5b6c89e3fe0a0332b80088b0
This commit mainly introduces a byoc c-source module example to uTVM. Moreover, it carries certain modifications to the example codegen_c external module generator code to generate utvm friendly c-source. Change-Id: I09f3a42017d518dd5b6c89e3fe0a0332b80088b0
This commit mainly introduces a byoc c-source module example to uTVM. Moreover, it carries certain modifications to the example codegen_c external module generator code to generate utvm friendly c-source. Change-Id: I09f3a42017d518dd5b6c89e3fe0a0332b80088b0