blob: 6f8fc45b7528cefe1e7bbb74152276c4bb0a8f99 [file] [log] [blame] [view]
- Feature Name: extend_metadata_in_projectoption
- Start Date: 2021-09-09
- RFC PR: [apache/tvm-rfcs#0020](https://github.com/apache/tvm-rfcs/pull/0000)
- GitHub Issue: [apache/tvm#0020](https://github.com/apache/tvm/issues/0000)
# Summary
[summary]: #summary
This RFC proposes to extend the current metadata associated with project options
provided by the Project API to allow a better integration with command line
interface tools, like TVMC.
# Motivation
[motivation]: #motivation
Currently metadata associated with project options provided by the Project API
is insufficent to allow building easily and automatically command line parsers
used by CLI tool like TVMC.
The metadata available for the project options, stored in instances of the
ProjectOption class are limited as they do not:
1. Provide a list of the API methods which support the options;
2. Allow determination if the options are required or optional;
3. Provide a default value if one is used by the Project API server.
As a consequence it complicates the integration with command line interfaces
that need to create command line arguments based on the project options
available for a platform.
This RFC proposes to extend the existing metadata with four new members in
`ProjectOption` (`required`, `optional`, `type`, and `default`) to address
issues **1.**, **2.**, and **3.** and ease the integration of Project API with
CLI tools.
# Guide-level explanation
[guide-level-explanation]: #guide-level-explanation
Below it is explained in detail the need and properties of the four new members
(`required`, `optional`, `type`, and `default`) proposed to be added to the
`ProjectOption` class to extend the project option metadata returned by Project
API `server_info_query` method. `required`, `optional`, and `type` are proposed
as **required fields**, whilst `default` is proposed as an **optional field**.
Modals like "must", "may" and similar ones are interpreted in this RFC
accordingly to the semantics defined by the IETF RFC-2119, 1997.
## On "required" and "optional" metadata
Currently even though all options available for a given project can be
discovered via the Project API `server_info_query` interface there is no way to
know which options belong (or apply) to which API method (like the
`generate_project`, `build`, `flash`, and `open_transport` methods).
This is fine when the user knows beforehand which method accepts a set of
options, so it's possible to manually select which options will be passed to a
given API method, like when using the API in a Python script.
However that's a problem when the API user (e.g. TVMC) needs to automatically
determine the options available for the API methods, like when automatically
building a command line parser with subcommand domains that closely mapped to
the API methods (e.g. subcommands to create, build, and flash a project).
Moreover, currently it's impossible to determine which option is required and
which one is optional, so it would be at least necessary for the API user to
build a static ad hoc table with all options available on a given project
stating which option is required and which one is optional for the project. This
is impractical to maintain and would result in the API user having to update the
the static table every time an option is added, removed, or modified in the
Project API server.
Hence to ease the automatic detection of the options available on each Project
API method the following two new metadata are proposed: `required` and
`optional`.
Both will contain a list of method names for which the option is available,
either as a required option (if in `required` list), or as an optional option
(if in `optional` list). At least one API method must be listed in `required` or
in the `optional` list. A method name must be listed only in the `required` or
in the `optional` list, i.e. an option can't be required and optional at the
same time for given API method. An option can be required for a method and
optional for another method.
The elements in the lists `required` and `optional` must be in the set of method
names implemented by the ProjectAPIClient class and that have the parameter
`options` defined. These methods are dispatched to the server, which implements
the server counterparts to properly handle the client dispatches and
ultimately defines the options available for each API method. The current method
names that satisfy these criteria are `generate_project`, `build`, `flash`, and
`open_transport`.
`required` metadatum or `optional` metadatum (or both) must be provided for
every option.
## On "type" metadatum
The option type can sometimes be determined implicitly by what is returned
in metadatum `choices`, but this not ideal. For example, for option `verbose` it
would be possible to infer it is a boolean option and therefore it can be
converted to a command line flag if metadatum `choices` is a couple of True and
False. Nonetheless that would lead to cumbersome logic at API user side (e.g.
TVMC) to infer the option type, like iterating over the tuple elements to search
for True or False. This can be solved directly if the option type is returned
explicitly with the option.
Thus adding a `type` metadatum allows a much simpler way for the API users to
determine the type of an option when that is necessary for various reasons, like
when building a command line parser based on the available project options.
The types must be only non-complex JSON-serializable primitive types, passed as
strings. Hence the following types are proposed for the `type` metadatum:
`"bool"`, `"str"`, `"int"`, and `"float"`.
`type` metadatum must be provided for every option.
## On "default" metadatum
Sometimes Project API uses a default value if an option is not specified, but
currently there is no way to determine it by using the option metadata.
However it's important for CLI tools to inform users what's the default value
for a given option, if applicable, so the user can decide if it's necessary to
provide a different value.
The default values for the options on a project could be defined at the user
side (e.g. TVMC) but that's not ideal.
Hence having an additional field `default` in the metadata that the API can use
to inform the user if the option has any default value is quite useful. It also
avoids one to keep that information at the client / user side.
`default` may be provided for an option, if applicable.
# Reference-level explanation
[reference-level-explanation]: #reference-level-explanation
All that's necessary to complish the proposal is:
1. Extend `ProjectOption` class by adding the new fields discussed above;
2. Adjust the existing platform options to comply with the required fields.
An example follows considering the Zephyr platform:
```
diff --git a/python/tvm/micro/project_api/server.py b/python/tvm/micro/project_api/server.py
index 07d328597..323bf418a 100644
--- a/python/tvm/micro/project_api/server.py
+++ b/python/tvm/micro/project_api/server.py
@@ -50,7 +50,8 @@ class ProjectOption(_ProjectOption):
def __new__(cls, name, **kw):
"""Override __new__ to force all options except name to be specified as kwargs."""
assert "name" not in kw
- assert "type" in kw, "'type' parameter must be specified"
+ assert "required" in kw or "optional" in kw, "'required' or 'optional' must be specified"
+ assert "type" in kw, "'type' field must be specified"
kw["name"] = name
for param in ["choices", "default", "required", "optional"]:
diff --git a/apps/microtvm/zephyr/template_project/microtvm_api_server.py b/apps/microtvm/zephyr/template_project/microtvm_api_server.py
index 4e62739d5..8d0b1722c 100644
--- a/apps/microtvm/zephyr/template_project/microtvm_api_server.py
+++ b/apps/microtvm/zephyr/template_project/microtvm_api_server.py
@@ -216,40 +216,58 @@ if IS_TEMPLATE:
PROJECT_OPTIONS = [
server.ProjectOption(
"extra_files_tar",
- help="If given, during generate_project, uncompress the tarball at this path into the project dir.",
+ optional=["generate_project"],
type="str",
+ help="If given, during generate_project, uncompress the tarball at this path into the project dir.",
),
server.ProjectOption(
"gdbserver_port", help=("If given, port number to use when running the local gdbserver."),
+ optional=["open_transport"],
type="int",
),
server.ProjectOption(
"nrfjprog_snr",
- help=("When used with nRF targets, serial # of the attached board to use, from nrfjprog."),
+ optional=["open_transport"],
type="int",
+ help=("When used with nRF targets, serial # of the attached board to use, from nrfjprog."),
),
server.ProjectOption(
"openocd_serial",
- help=("When used with OpenOCD targets, serial # of the attached board to use."),
+ optional=["open_transport"],
type="int",
+ help=("When used with OpenOCD targets, serial # of the attached board to use."),
),
server.ProjectOption(
"project_type",
- help="Type of project to generate.",
choices=tuple(PROJECT_TYPES),
+ required=["generate_project"],
type="str",
+ help="Type of project to generate.",
),
server.ProjectOption("verbose", help="Run build with verbose output.", type="bool"),
server.ProjectOption(
"west_cmd",
+ optional=["generate_project"],
+ default="python3 -m west",
+ type="str",
help=(
"Path to the west tool. If given, supersedes both the zephyr_base "
"option and ZEPHYR_BASE environment variable."
),
+ ),
+ server.ProjectOption(
+ "zephyr_base",
+ optional=["build", "open_transport"],
+ default="ZEPHYR_BASE",
+ type="str",
+ help="Path to the zephyr base directory.",
+ ),
+ server.ProjectOption(
+ "zephyr_board",
+ required=["generate_project", "build", "flash", "open_transport"],
+ help="Name of the Zephyr board to build for.",
type="str",
),
- server.ProjectOption("zephyr_base", help="Path to the zephyr base directory.", type="str"),
- server.ProjectOption("zephyr_board", help="Name of the Zephyr board to build for.", type="str"),
]
```
It's important to note that every project option must be at least associated to
one API method (at least one method is listed in the option's `'required'` or
`'optional'` list).
It's possible to enforce that an option will never be passed to an API method
call if it's not a valid option for that method (i.e. the method is listed
neither in the option's `required` list nor in its `optional` list).
That ideally must be enforced at the server side (`server.py`) of the Project
API. The enforcement can consist in having the server removing an invalid option
for a method before the method is called effectively on consulting ProjectOption
for the option being passed and not finding the method in either the
`'required'` or `'optional`' list.
# Drawbacks
[drawbacks]: #drawbacks
The impact on existing code is low and the current project options will only
need to be adjusted to define the new mandatory fields, i.e. `required`,
`optional`, and `type`, all are straightforward to be provided for the existing
options on the current supported platforms.
Adding the four new members to `ProjectOption` will increase the size of
`ProjectOption` class and consequently the amount of data returned by
`server_info_query`, however since Project API client and server run on the same
host that is negligible.
# Rationale and alternatives
An alternative would be to implement the data proposed here as metadata at the
user side instead, however it would complicate the use of Project API by CLI
like TVMC, since ah hoc tables would need to be created for each platform and
for each project option available on the platform, allow one to map options data
for their required or optional methods, default value, etc. Hence that
alternative is impractical or hard to maintain at best for syncing up with
Project API updates (updating the tables to match Project API) would be
necessary every time a new option is added to a project.