For complete documentation of all methods and variables tagged as APIs, please see our Doxygen Module page.
The gem5 API
In efforts to improve product stability, the gem5 development team is gradually tagging methods and variables within gem5 as APIs which developers will need to undergo specific procedures to change. Our goal with the gem5 API is to provide a stable interface for users to build gem5 models, and extend the gem5 code-base, with guarantees these APIs will not change in a dramatic sudden manner between gem5 releases.
How is the gem5 API documented?
We document the gem5 APIs using the Doxygen documentation generation tool. This means you may see the API tagged
at the level of source-code and via our web-based documentation. We use Doxygen’s @ingroup
tag, to specify a
method/variables as part of the gem5 API. We break the API down into
sub-domains such as api_simobject
or api_ports
, though all the gem5 APIs
are tagged with the prefix api_
. For example, we tag SimObject’s params()
function as follows:
/**
* @return This function returns the cached copy of the object parameters.
*
* @ingroup api_simobject
*/
const Params *params() const { return _params; }
Via Doxygen automatic generation, the list of gem5 APIs can be found on the
Doxygen module page.
In this example, the entire list of SimObject APIs are noted in the
SimObject API page. The
definitions of different API groups can be found in
src/doxygen/group_definitions.hh
.
Notes for developers
If a developer wishes to tag a new method/variable as part of the gem5 API, the gem5 community should be consulted. APIs are intended to stay unaltered for some time. To avoid the gem5 project becoming encumbered with “too many APIs”, we strongly advise those wishing to extend the API to communicate to the gem5 development team as to why the API will be of value. The gem5 Discussion page is a good communication channel for this.
How can the API change?
We do not guarantee the gem5 API will never change over time. gem5 is a product under continual development which must adapt to the needs of the computer architecture research community. However, we guarantee that API changes will follow strict guidelines outlined below.
-
When an API method or variable is altered, it will be done so in a way in which the new API will exist alongside the old, with the old API tagged as deprecated and still functional.
-
The old, deprecated API will exist for two gem5 major cycles before being removed entirely from code-base, though gem5 developers may choose to keep a deprecated API in the code-base for longer. For example, if an API is tagged as deprecated in gem5 21.0, it will also still exist (still tagged as deprecated) in gem5 21.1. It may be removed entirely in gem5 21.2, though this will be left to the discretion of the gem5 developers.
-
The gem5 deprecated C++ APIs will be tagged with the C++ deprecated attribute (
[[deprecated(<msg>)]]
). When utilizing a deprecated C++ API, a warning will be given at compilation time specifying which API to transition to. The gem5 deprecated Python parameter APIs are wrapped with our bespokeDeprecatedParam
class. Python parameters wrapped in this class will throw an warning when used and specify which API to transition to.
Notes for Developers
Prior to making any changes to the gem5 API the gem5-dev mailing list should be consulted. Changing the API, for whatever reason, will be subject to higher scrutiny than other changes. Developers should be prepared to provide compelling arguments as to why the API needs changed. We strongly recommend API changes are discussed or they may be rejected during the code review.
When creating a new API the old API must be tagged as deprecated and the new API created to exist alongside the old. It is of upmost importance that the old, deprecated API is maintained and not deleted.
As an example, take the following code:
/**
* @ingroup api_bitfield
*/
inline uint64_t
mask(int first, int last)
{
return mbits((uint64_t)-1LL, first, last);
}
This function is part of the gem5 bitfield API. It is a basic mask function that takes the MSB (first) and the LSB (last) for the generation of a 64-bit. Let us assume there is a good argument that this function should be replaced with one that takes the MSB (first), and the length of the mask instead.
To start, the old API needs maintained (i.e., not changed) and tagged with the
[[deprecated(<msg>)]]
tag. The message (<msg>
) Should state the new API
to use, and the API tagging should be removed. The new API should then be
created and tagged. So, using our example:
[[deprecated("Use mask_length instead.")]]
inline uint64_t
mask(int first, int last)
{
return mbits((uint64_t)-1LL, first, last);
}
/**
* @ingroup api_bitfield
*/
inline uint64_t
mask_length(int first, int length)
{
return mbits((uint64_t)-1LL, first, first + length);
}
Here a new function, mask_length
, has been created. It has been tagged
correctly via Doxygen. The old API, mask
exists but has the
[[deprecated]]
annotation added. The message provided states which API
replaces it.
The developer then needs to replace all usage of mask
in the code-base with
mask_length
. A warning will be given at compile time if mask
is used,
stating that it is deprecated and to “Use mask_length instead.”.
Occasionally there may be need to change the python API interface, which relates to tagged APIs. For example, let’s take the below code:
class TLBCoalescer(ClockedObject):
type = 'TLBCoalescer'
cxx_class = 'TLBCoalescer'
cxx_header = 'gpu-compute/tlb_coalescer.hh'
...
slave = VectorResponsePort("Port on side closer to CPU/CU")
master = VectorRequestPort("Port on side closer to memory")
...
In recent revisions
the terms master
and slave
have been replaced. Though, the slave
and
master
terminology are widely used, so much so we consider them part of the
old API. We therefore wish to deprecate this API is a safe manner while
changing master
and slave
with cpu_side_ports
and mem_side_ports
. To
do so we would maintain the master
and slave
variables but utilize our
DeprecatedParam
Class
to produce warnings when and if these deprecated variables are used. Working on
our example, we would produce the following:
class TLBCoalescer(ClockedObject):
type = 'TLBCoalescer'
cxx_class = 'TLBCoalescer'
cxx_header = 'gpu-compute/tlb_coalescer.hh'
...
cpu_side_ports = VectorResponsePort("Port on side closer to CPU/CU")
slave = DeprecatedParam(cpu_side_ports,
'`slave` is now called `cpu_side_ports`')
mem_side_ports = VectorRequestPort("Port on side closer to memory")
master = DeprecatedParam(mem_side_ports,
'`master` is now called `mem_side_ports`')
...
Note the use of DeprecatedParam
that both ensures master
and slave
still
function by redirecting to mem_side_ports
and cpu_side_ports
respectively,
as well as providing a comment explaining why this API was deprecated. This
will be displayed to the user as a warning if master
or slave
are ever
used.
As with all changes to the gem5 source, these changes will have to go through
our Gerrit code review system before being merged into the develop
branch,
and eventually making its way to our stable
branch as part of a gem5 release.
In line with our API policy, these deprecated APIs must exist in a
marked-as-deprecated state for two gem5 major release cycles. After this they
may be removed though developers are under no requirement to do so.