diff mbox

[2/2] doc: userguide: add notes on threads and addressing scope

Message ID 1463630733-30902-2-git-send-email-bill.fischofer@linaro.org
State New
Headers show

Commit Message

Bill Fischofer May 19, 2016, 4:05 a.m. UTC
Expand thread section to explain rationale for threads not being ODP
objects and how this relates to addressability considerations for shared
resources.

Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>
---
 doc/users-guide/users-guide.adoc | 40 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 36 insertions(+), 4 deletions(-)

Comments

Christophe Milard May 19, 2016, 7:30 a.m. UTC | #1
On 19 May 2016 at 06:05, Bill Fischofer <bill.fischofer@linaro.org> wrote:

> Expand thread section to explain rationale for threads not being ODP
> objects and how this relates to addressability considerations for shared
> resources.
>
> Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>
> ---
>  doc/users-guide/users-guide.adoc | 40
> ++++++++++++++++++++++++++++++++++++----
>  1 file changed, 36 insertions(+), 4 deletions(-)
>
> diff --git a/doc/users-guide/users-guide.adoc
> b/doc/users-guide/users-guide.adoc
> index 745b85f..fbe745f 100755
> --- a/doc/users-guide/users-guide.adoc
> +++ b/doc/users-guide/users-guide.adoc
> @@ -288,6 +288,17 @@ _thread mask_ and _scheduler group_ that determine
> where they can run and
>  the type of work that they can handle. These will be discussed in greater
>  detail later.
>
> +It is important to note that threads are not ODP objects. This is
> intentional.
> +The ODP API is designed to abstract objects and functions that are
> relevant to
> +data plane programming, and that may find accelerated implementation
> across
> +diverse platforms and architectures. It is not, however, designed to
> abstract
> +operating system objects and concepts. As a result while ODP _refers_ to
> +threads, it does not _define_ threads in terms of their creation or
> management
> +from an operating system perspective. ODP does provide _helper_ functions
> that
> +permit Posix threads to be created and managed, however. Applications are
> free
> +to use these helpers or to manage threads in some other manner of their
> +choosing.
> +
>  === Event
>  Events are what threads process to perform their work. Events can
> represent
>  new work, such as the arrival of a packet that needs to be processed, or
> they
> @@ -332,6 +343,9 @@ ODP applications if desired.
>
>  Shared memory is represented by handles of abstract type `odp_shm_t`.
>
> +Note that addressability of shared memory is subject to operating system
> +considerations as described in <<Addressing Scope>>.
> +
>  === Buffer
>  A buffer is a fixed sized block of shared storage that is used by ODP
>  components and/or applications to realize their function. Buffers contain
> @@ -587,10 +601,28 @@ in response to an `odp_queue_deq()` call to get an
> event from a queue simply
>  indicates that the queue is empty.
>
>  === Addressing Scope
> -Unless specifically noted in the API, all ODP resources are global to the
> ODP
> -application, whether it runs as a single process or multiple processes.
> ODP
> -handles therefore have common meaning within an ODP application but have
> no
> -meaning outside the scope of the application.
> +ODP objects and their associated handles are intended to be global to an
> ODP
> +instance, _i.e.,_ to the thread that calls `odp_init_global()` and its
> +descendants.


This is saying that all ODP threads of a given ODP instance are descendant
of the ODP instantiation process. I already tried to define ODP threads
this way, but it was rejected, and the ODP instance number was added to the
API so that any thread/process could join any ODP instance.
I still get the feeling that, despite this add-on, we are still saying that
a odpthread belongs to the ODP instance it is a descendand of, rather than
the one specified in the "instance" parameter passed at odp_local_init()
time...
The only possible usage of the odp_instance parameter passed at
odp_local_init() time would then be on OSes which do not support process
hierarchy... Is any such OS known to suport ODP?
If not, I thing the odp_instance number should either be suppressed, or
clearly stated as meaningless on OS which have process hierarchy, as the
process hierarchy seems to take precedence over this parameter in all our
discussions.
I will post a patch on the glossary just stating that, see if we can at
least all agree on that little thing...

However, because ODP does not impose a threading model,
> +responsibility for achieving this is shared with both the ODP
> implementation as
> +well as the ODP application. In the odp-linux reference implementation,
> for
> +example, threads are assumed to be Posix-style threads that all share a
> single
>

*ODP* threads are assumed to be Posix-style threads...
This is for monarch only, right?

+address space. As a result, all ODP handles and any addresses derived from
> +them, are globally sharable throughout the ODP instance. Other
> implementations
> +may offer the same capabilities or may use a process-based threading
> model in
> +which individual threads execute in distinct address spaces.
>

Confused: are talking monarch or some later version? BTW is monarch the
name of the API version only or does the "monarch" name also include the
linux-generic  platform example?


> +
> +If a platform uses process that follow a Unix-style `fork()` model of
> process
> +creation, then for best portability ODP applications should be designed so
> +that any ODP resource creation (_e.g.,_ pools, shared memory objects,
> pktios)
>

"any  ODP resource": That includes everything, e.g. atomics, barrier,
timers... as well...right...?

+are created during initialization by the thread that creates the ODP
> instance
> +by calling `odp_init_global()` _before_ any other threads are
> +created/launched. This will allow any common objects to be visible in
> forked
> +processes.
>

well... yes... But the interesting point is really  not mentioned:

Either we say:
*ALL* odp objects *have to* be created between opd_init_global() and any
odp thread creation. That is clear but very  restrictive (it  would
includes everything: for instance, all atomics would have to be known in
advance. same for timers or barriers... while it is maybe clear for pools,
it is maybe harder to enforce this for these small objects). But at least
the definition would be clear...

or we say
SOME  odp objects *have to* be created between opd_init_global() and any
odp thread creation, in which case, we have to come with a clear list of
which ones we talk about and a precise description of how objects which are
not on that list behave, especially when created after fork. This
description could of course refer to the OS behavior, but should clearly
state what this OS rule applies to (e.g. a how buffer or packet alloc
performed after fork() behaves -I guess it depends on when the pool was
allocated...).

Saying that "most" ODP objects "would possibly" be defined at init time
does not really tell much...

+
> +If a platform uses some other process addressing model, then refer to that
> +platform for recommendations to achieve application-desired shared
> +addressability.
>
>  === Resources and Names
>  Many ODP resource objects, such as pools and queues, support an
> --
> 2.7.4
>
>
Thank you for trying, Bill. We need to succeed. I'll keep trying with you.

A french writter, Boileau, wrote " Ce qui se conçoit bien, s'énonce
clairement". I know you speak some french... I guess this guy would laugh
at us right now :-)

Christophe
Mike Holmes May 19, 2016, 4:11 p.m. UTC | #2
On 19 May 2016 at 03:30, Christophe Milard <christophe.milard@linaro.org>
wrote:

> On 19 May 2016 at 06:05, Bill Fischofer <bill.fischofer@linaro.org> wrote:
>
> > Expand thread section to explain rationale for threads not being ODP
> > objects and how this relates to addressability considerations for shared
> > resources.
> >
> > Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>
> > ---
> >  doc/users-guide/users-guide.adoc | 40
> > ++++++++++++++++++++++++++++++++++++----
> >  1 file changed, 36 insertions(+), 4 deletions(-)
> >
> > diff --git a/doc/users-guide/users-guide.adoc
> > b/doc/users-guide/users-guide.adoc
> > index 745b85f..fbe745f 100755
> > --- a/doc/users-guide/users-guide.adoc
> > +++ b/doc/users-guide/users-guide.adoc
> > @@ -288,6 +288,17 @@ _thread mask_ and _scheduler group_ that determine
> > where they can run and
> >  the type of work that they can handle. These will be discussed in
> greater
> >  detail later.
> >
> > +It is important to note that threads are not ODP objects. This is
> > intentional.
> > +The ODP API is designed to abstract objects and functions that are
> > relevant to
> > +data plane programming, and that may find accelerated implementation
> > across
> > +diverse platforms and architectures. It is not, however, designed to
> > abstract
> > +operating system objects and concepts. As a result while ODP _refers_ to
> > +threads, it does not _define_ threads in terms of their creation or
> > management
> > +from an operating system perspective. ODP does provide _helper_
> functions
> > that
> > +permit Posix threads to be created and managed, however. Applications
> are
> > free
> > +to use these helpers or to manage threads in some other manner of their
> > +choosing.
> > +
> >  === Event
> >  Events are what threads process to perform their work. Events can
> > represent
> >  new work, such as the arrival of a packet that needs to be processed, or
> > they
> > @@ -332,6 +343,9 @@ ODP applications if desired.
> >
> >  Shared memory is represented by handles of abstract type `odp_shm_t`.
> >
> > +Note that addressability of shared memory is subject to operating system
> > +considerations as described in <<Addressing Scope>>.
> > +
> >  === Buffer
> >  A buffer is a fixed sized block of shared storage that is used by ODP
> >  components and/or applications to realize their function. Buffers
> contain
> > @@ -587,10 +601,28 @@ in response to an `odp_queue_deq()` call to get an
> > event from a queue simply
> >  indicates that the queue is empty.
> >
> >  === Addressing Scope
> > -Unless specifically noted in the API, all ODP resources are global to
> the
> > ODP
> > -application, whether it runs as a single process or multiple processes.
> > ODP
> > -handles therefore have common meaning within an ODP application but have
> > no
> > -meaning outside the scope of the application.
> > +ODP objects and their associated handles are intended to be global to an
> > ODP
> > +instance, _i.e.,_ to the thread that calls `odp_init_global()` and its
> > +descendants.
>
>
> This is saying that all ODP threads of a given ODP instance are descendant
> of the ODP instantiation process. I already tried to define ODP threads
> this way, but it was rejected, and the ODP instance number was added to the
> API so that any thread/process could join any ODP instance.
> I still get the feeling that, despite this add-on, we are still saying that
> a odpthread belongs to the ODP instance it is a descendand of, rather than
> the one specified in the "instance" parameter passed at odp_local_init()
> time...
> The only possible usage of the odp_instance parameter passed at
> odp_local_init() time would then be on OSes which do not support process
> hierarchy... Is any such OS known to suport ODP?
> If not, I thing the odp_instance number should either be suppressed, or
> clearly stated as meaningless on OS which have process hierarchy, as the
> process hierarchy seems to take precedence over this parameter in all our
> discussions.
> I will post a patch on the glossary just stating that, see if we can at
> least all agree on that little thing...
>
> However, because ODP does not impose a threading model,
> > +responsibility for achieving this is shared with both the ODP
> > implementation as
> > +well as the ODP application. In the odp-linux reference implementation,
> > for
> > +example, threads are assumed to be Posix-style threads that all share a
> > single
> >
>
> *ODP* threads are assumed to be Posix-style threads...
> This is for monarch only, right?
>
> +address space. As a result, all ODP handles and any addresses derived from
> > +them, are globally sharable throughout the ODP instance. Other
> > implementations
> > +may offer the same capabilities or may use a process-based threading
> > model in
> > +which individual threads execute in distinct address spaces.
> >
>
> Confused: are talking monarch or some later version? BTW is monarch the
> name of the API version only or does the "monarch" name also include the
> linux-generic  platform example?
>
>
> > +
> > +If a platform uses process that follow a Unix-style `fork()` model of
> > process
> > +creation, then for best portability ODP applications should be designed
> so
> > +that any ODP resource creation (_e.g.,_ pools, shared memory objects,
> > pktios)
> >
>
> "any  ODP resource": That includes everything, e.g. atomics, barrier,
> timers... as well...right...?
>
> +are created during initialization by the thread that creates the ODP
> > instance
> > +by calling `odp_init_global()` _before_ any other threads are
> > +created/launched. This will allow any common objects to be visible in
> > forked
> > +processes.
> >
>
> well... yes... But the interesting point is really  not mentioned:
>
> Either we say:
> *ALL* odp objects *have to* be created between opd_init_global() and any
> odp thread creation. That is clear but very  restrictive (it  would
> includes everything: for instance, all atomics would have to be known in
> advance. same for timers or barriers... while it is maybe clear for pools,
> it is maybe harder to enforce this for these small objects). But at least
> the definition would be clear...
>
> or we say
> SOME  odp objects *have to* be created between opd_init_global() and any
> odp thread creation, in which case, we have to come with a clear list of
> which ones we talk about and a precise description of how objects which are
> not on that list behave, especially when created after fork. This
> description could of course refer to the OS behavior, but should clearly
> state what this OS rule applies to (e.g. a how buffer or packet alloc
> performed after fork() behaves -I guess it depends on when the pool was
> allocated...).
>
> Saying that "most" ODP objects "would possibly" be defined at init time
> does not really tell much...
>
> +
> > +If a platform uses some other process addressing model, then refer to
> that
> > +platform for recommendations to achieve application-desired shared
> > +addressability.
> >
> >  === Resources and Names
> >  Many ODP resource objects, such as pools and queues, support an
> > --
> > 2.7.4
> >
> >
> Thank you for trying, Bill. We need to succeed. I'll keep trying with you.
>
> A french writter, Boileau, wrote " Ce qui se conçoit bien, s'énonce
> clairement". I know you speak some french... I guess this guy would laugh
> at us right now :-)
>

What is conceived well is expressed clearly ?


>
> Christophe
>
> _______________________________________________
> > lng-odp mailing list
> > lng-odp@lists.linaro.org
> > https://lists.linaro.org/mailman/listinfo/lng-odp
> >
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> https://lists.linaro.org/mailman/listinfo/lng-odp
>
Bill Fischofer May 20, 2016, 3:23 a.m. UTC | #3
On Thu, May 19, 2016 at 2:30 AM, Christophe Milard <
christophe.milard@linaro.org> wrote:

>
>
> On 19 May 2016 at 06:05, Bill Fischofer <bill.fischofer@linaro.org> wrote:
>
>> Expand thread section to explain rationale for threads not being ODP
>> objects and how this relates to addressability considerations for shared
>> resources.
>>
>> Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>
>> ---
>>  doc/users-guide/users-guide.adoc | 40
>> ++++++++++++++++++++++++++++++++++++----
>>  1 file changed, 36 insertions(+), 4 deletions(-)
>>
>> diff --git a/doc/users-guide/users-guide.adoc
>> b/doc/users-guide/users-guide.adoc
>> index 745b85f..fbe745f 100755
>> --- a/doc/users-guide/users-guide.adoc
>> +++ b/doc/users-guide/users-guide.adoc
>> @@ -288,6 +288,17 @@ _thread mask_ and _scheduler group_ that determine
>> where they can run and
>>  the type of work that they can handle. These will be discussed in greater
>>  detail later.
>>
>> +It is important to note that threads are not ODP objects. This is
>> intentional.
>> +The ODP API is designed to abstract objects and functions that are
>> relevant to
>> +data plane programming, and that may find accelerated implementation
>> across
>> +diverse platforms and architectures. It is not, however, designed to
>> abstract
>> +operating system objects and concepts. As a result while ODP _refers_ to
>> +threads, it does not _define_ threads in terms of their creation or
>> management
>> +from an operating system perspective. ODP does provide _helper_
>> functions that
>> +permit Posix threads to be created and managed, however. Applications
>> are free
>> +to use these helpers or to manage threads in some other manner of their
>> +choosing.
>> +
>>  === Event
>>  Events are what threads process to perform their work. Events can
>> represent
>>  new work, such as the arrival of a packet that needs to be processed, or
>> they
>> @@ -332,6 +343,9 @@ ODP applications if desired.
>>
>>  Shared memory is represented by handles of abstract type `odp_shm_t`.
>>
>> +Note that addressability of shared memory is subject to operating system
>> +considerations as described in <<Addressing Scope>>.
>> +
>>  === Buffer
>>  A buffer is a fixed sized block of shared storage that is used by ODP
>>  components and/or applications to realize their function. Buffers contain
>> @@ -587,10 +601,28 @@ in response to an `odp_queue_deq()` call to get an
>> event from a queue simply
>>  indicates that the queue is empty.
>>
>>  === Addressing Scope
>> -Unless specifically noted in the API, all ODP resources are global to
>> the ODP
>> -application, whether it runs as a single process or multiple processes.
>> ODP
>> -handles therefore have common meaning within an ODP application but have
>> no
>> -meaning outside the scope of the application.
>> +ODP objects and their associated handles are intended to be global to an
>> ODP
>> +instance, _i.e.,_ to the thread that calls `odp_init_global()` and its
>> +descendants.
>
>
> This is saying that all ODP threads of a given ODP instance are descendant
> of the ODP instantiation process. I already tried to define ODP threads
> this way, but it was rejected, and the ODP instance number was added to the
> API so that any thread/process could join any ODP instance.
>

We should revisit that because without this assumption I don't think we can
define a consistent set of semantics for ODP object visibility.  For
example, if I create an ODP instance and then pass the instance ID
privately to a completely separate program, do we expect it to be able to
use that instance ID to join the (remote) ODP instance by calling
odp_init_local()?  Clearly not.


> I still get the feeling that, despite this add-on, we are still saying
> that a odpthread belongs to the ODP instance it is a descendand of, rather
> than the one specified in the "instance" parameter passed at
> odp_local_init() time...
> The only possible usage of the odp_instance parameter passed at
> odp_local_init() time would then be on OSes which do not support process
> hierarchy... Is any such OS known to suport ODP?
>

I concur. I think it's there more for potential future flexibility than
anything else since it's effectively a dummy parameter with a single
hard-coded value in odp-linux. I see no harm in it being there, but it's
presence doesn't change the fact that ODP instances only cover the
odp_global_init() caller and its descendants.


> If not, I thing the odp_instance number should either be suppressed, or
> clearly stated as meaningless on OS which have process hierarchy, as the
> process hierarchy seems to take precedence over this parameter in all our
> discussions.
> I will post a patch on the glossary just stating that, see if we can at
> least all agree on that little thing...
>
> However, because ODP does not impose a threading model,
>> +responsibility for achieving this is shared with both the ODP
>> implementation as
>> +well as the ODP application. In the odp-linux reference implementation,
>> for
>> +example, threads are assumed to be Posix-style threads that all share a
>> single
>>
>
> *ODP* threads are assumed to be Posix-style threads...
> This is for monarch only, right?
>

That's the only ODP we have at the moment, so yes.


>
> +address space. As a result, all ODP handles and any addresses derived from
>> +them, are globally sharable throughout the ODP instance. Other
>> implementations
>> +may offer the same capabilities or may use a process-based threading
>> model in
>> +which individual threads execute in distinct address spaces.
>>
>
> Confused: are talking monarch or some later version? BTW is monarch the
> name of the API version only or does the "monarch" name also include the
> linux-generic  platform example?
>

Both. Monarch is the current API level and odp-linux implements that level
of the ODP API. These statements will still be true of Monarch even after
we move on to Tiger Moth, which may or may not introduce additional
capabilities.


>
>
>> +
>> +If a platform uses process that follow a Unix-style `fork()` model of
>> process
>> +creation, then for best portability ODP applications should be designed
>> so
>> +that any ODP resource creation (_e.g.,_ pools, shared memory objects,
>> pktios)
>>
>
> "any  ODP resource": That includes everything, e.g. atomics, barrier,
> timers... as well...right...?
>

The key word here is creation, not declaration or allocation.  Atomics,
barriers, and locks are not created, they are declared and initialized, so
the caller is controlling the space that they occupy.  Similarly packets
and timers are allocated from pools that are created, so these objects
inherit their visibility from the pools they are drawn from. The
requirement is that the pools be created at a point of common
addressability for all descendants that reference the pool or similar
created object if the objects drawn from them are to be sharable across
process boundaries.

Queues are created, however they are created from the ODP instance itself,
so they automatically have ODP instance-wide visibility. It may be simpler
to just enumerate the APIs for which this caveat applies.  They are
odp_pool_create(), odp_timer_pool_create(), and odp_shm_reserve().
 odp_pktio_open() is another case due to the (implied) use of file
descriptors.  The traffic manager as currently implemented in odp-linux
assumes a single address space so we'll have to see what impacts there are
there for adding any process mode support, but my preference would be for
it to be treated more like queues than pools so that it is implicitly tied
directly to the ODP instance.

Note that the whole preallocation discussion was to root all of these
things to the ODP instance rather than the create() call itself to avoid
these subtleties.


>
> +are created during initialization by the thread that creates the ODP
>> instance
>> +by calling `odp_init_global()` _before_ any other threads are
>> +created/launched. This will allow any common objects to be visible in
>> forked
>> +processes.
>>
>
> well... yes... But the interesting point is really  not mentioned:
>
> Either we say:
> *ALL* odp objects *have to* be created between opd_init_global() and any
> odp thread creation. That is clear but very  restrictive (it  would
> includes everything: for instance, all atomics would have to be known in
> advance. same for timers or barriers... while it is maybe clear for pools,
> it is maybe harder to enforce this for these small objects). But at least
> the definition would be clear...
>

No, for reasons discussed above. There are a very small number of ODP
things that fall under this restriction, which I do not believe would be
overly onerous for most applications.


>
> or we say
> SOME  odp objects *have to* be created between opd_init_global() and any
> odp thread creation, in which case, we have to come with a clear list of
> which ones we talk about and a precise description of how objects which are
> not on that list behave, especially when created after fork. This
> description could of course refer to the OS behavior, but should clearly
> state what this OS rule applies to (e.g. a how buffer or packet alloc
> performed after fork() behaves -I guess it depends on when the pool was
> allocated...).
>
> Saying that "most" ODP objects "would possibly" be defined at init time
> does not really tell much...
>

Agree, we should enumerate the relevant APIs, as I've done above. I can do
so in a v2 of the patch.


>
> +
>> +If a platform uses some other process addressing model, then refer to
>> that
>> +platform for recommendations to achieve application-desired shared
>> +addressability.
>>
>>  === Resources and Names
>>  Many ODP resource objects, such as pools and queues, support an
>> --
>> 2.7.4
>>
>>
> Thank you for trying, Bill. We need to succeed. I'll keep trying with you.
>
> A french writter, Boileau, wrote " Ce qui se conçoit bien, s'énonce
> clairement". I know you speak some french... I guess this guy would laugh
> at us right now :-)
>
> Christophe
>
> _______________________________________________
>> lng-odp mailing list
>> lng-odp@lists.linaro.org
>> https://lists.linaro.org/mailman/listinfo/lng-odp
>>
>
>
Christophe Milard May 23, 2016, 8:38 a.m. UTC | #4
Am I understanding correctly if I try to rephrase your suggestion, Petri,
as follows:

1) " For simplicity all memory should be reserved from the system at global
init time.":
When calling init_global(), the application provides the total amount of
memory it will ever need, including everything (Buffer pools, packet pools,
queues...). I guess this means  that this amount is either found by try and
error when the application is written, or by having some knowledge of the
internal ODP implemenation (how much memory different ODP objects actually
consume). This provided total amount is also very much ODP implementation
dependent as differents implementations may implement some of the ODP
objects in HW.

2) The total amount is allocated at global_init() time, hence before any
fork(), and any ODP memory allocation that follows (for pools, queues or
whatever) is drawn from this initially allocated memory, hence actually
 guaranteeing sharable pointers over the complete ODP instance

3)" Only restriction would be on if pointers to data can be shared.": The
fact that pointers are sharable through the complete ODP instance is hidden
from the API which still claims that OS rules apply

Is this understanding correct?

Christophe.

On 23 May 2016 at 09:37, Savolainen, Petri (Nokia - FI/Espoo) <
petri.savolainen@nokia.com> wrote:

>
> > >>
> > >>  === Addressing Scope
> > >> -Unless specifically noted in the API, all ODP resources are global to
> > >> the ODP
> > >> -application, whether it runs as a single process or multiple
> > processes.
> > >> ODP
> > >> -handles therefore have common meaning within an ODP application but
> > have
> > >> no
> > >> -meaning outside the scope of the application.
> > >> +ODP objects and their associated handles are intended to be global to
> > an
> > >> ODP
> > >> +instance, _i.e.,_ to the thread that calls `odp_init_global()` and
> its
> > >> +descendants.
> > >
> > >
> > > This is saying that all ODP threads of a given ODP instance are
> > descendant
> > > of the ODP instantiation process. I already tried to define ODP threads
> > > this way, but it was rejected, and the ODP instance number was added to
> > the
> > > API so that any thread/process could join any ODP instance.
> > >
> >
> > We should revisit that because without this assumption I don't think we
> > can
> > define a consistent set of semantics for ODP object visibility.  For
> > example, if I create an ODP instance and then pass the instance ID
> > privately to a completely separate program, do we expect it to be able to
> > use that instance ID to join the (remote) ODP instance by calling
> > odp_init_local()?  Clearly not.
> >
>
> Yes, if the implementation supports that. E.g. there's no processes or
> pthreads in when an SDK runs in bare metal mode. Each cpu starts from C lib
> / SDK startup code and stops at some point to wait others. There's some
> shared memory set up at init phase. You could start up e.g. two separate
> ODP instances of ODP, so that half of the cpus joins the first instance and
> the other half joins the other instance.
>
> odp-linux would not support (at least at first) non-related processes to
> form an instance. But API would not limit, if support for it would be added
> later.
>
>
> >
> > > I still get the feeling that, despite this add-on, we are still saying
> > > that a odpthread belongs to the ODP instance it is a descendand of,
> > rather
> > > than the one specified in the "instance" parameter passed at
> > > odp_local_init() time...
> > > The only possible usage of the odp_instance parameter passed at
> > > odp_local_init() time would then be on OSes which do not support
> process
> > > hierarchy... Is any such OS known to suport ODP?
> > >
> >
> > I concur. I think it's there more for potential future flexibility than
> > anything else since it's effectively a dummy parameter with a single
> > hard-coded value in odp-linux. I see no harm in it being there, but it's
> > presence doesn't change the fact that ODP instances only cover the
> > odp_global_init() caller and its descendants.
>
>
> This is the point. Instance ID enables various thread setups (for linux,
> RTOS, bare metal, ...), odp-linux implements some of those.
>
>
> >
> >
> > > If not, I thing the odp_instance number should either be suppressed, or
> > > clearly stated as meaningless on OS which have process hierarchy, as
> the
> > > process hierarchy seems to take precedence over this parameter in all
> > our
> > > discussions.
>
>
> An implementation may use the instance ID any way it likes. It may carry a
> file name, file descriptor, index to shared memory, magic number, ... etc
> information to find the instance or just error check that global_init was
> indeed called before local_init was called. No need to state it meaningless
> for any implementation.
>
>
> > >
> > > Confused: are talking monarch or some later version? BTW is monarch the
> > > name of the API version only or does the "monarch" name also include
> the
> > > linux-generic  platform example?
> > >
> >
> > Both. Monarch is the current API level and odp-linux implements that
> level
> > of the ODP API. These statements will still be true of Monarch even after
> > we move on to Tiger Moth, which may or may not introduce additional
> > capabilities.
> >
>
> Monarch is API level and various implementations will be maintained for it
> for "a long time". E.g. during that time, odp-linux will be optimized
> further, new pktios may be added, process mode support will be added, new
> implementation specific configuration file / parameters may be introduced,
> ... API remains the same but implementations may evolve.
>
>
>
>
> >
> > >
> > >
> > >> +
> > >> +If a platform uses process that follow a Unix-style `fork()` model of
> > >> process
> > >> +creation, then for best portability ODP applications should be
> > designed
> > >> so
> > >> +that any ODP resource creation (_e.g.,_ pools, shared memory objects,
> > >> pktios)
> > >>
> > >
> > > "any  ODP resource": That includes everything, e.g. atomics, barrier,
> > > timers... as well...right...?
> > >
> >
> > The key word here is creation, not declaration or allocation.  Atomics,
> > barriers, and locks are not created, they are declared and initialized,
> so
> > the caller is controlling the space that they occupy.  Similarly packets
> > and timers are allocated from pools that are created, so these objects
> > inherit their visibility from the pools they are drawn from. The
> > requirement is that the pools be created at a point of common
> > addressability for all descendants that reference the pool or similar
> > created object if the objects drawn from them are to be sharable across
> > process boundaries.
> >
> > Queues are created, however they are created from the ODP instance
> itself,
> > so they automatically have ODP instance-wide visibility. It may be
> simpler
> > to just enumerate the APIs for which this caveat applies.  They are
> > odp_pool_create(), odp_timer_pool_create(), and odp_shm_reserve().
> >  odp_pktio_open() is another case due to the (implied) use of file
> > descriptors.  The traffic manager as currently implemented in odp-linux
> > assumes a single address space so we'll have to see what impacts there
> are
> > there for adding any process mode support, but my preference would be for
> > it to be treated more like queues than pools so that it is implicitly
> tied
> > directly to the ODP instance.
> >
> > Note that the whole preallocation discussion was to root all of these
> > things to the ODP instance rather than the create() call itself to avoid
> > these subtleties.
> >
>
>
> Any allocated object may consume lots of shared memory. E.g. 1B queues (or
> timers/timeouts or tm queues or classification rules or ...) would consume
> gigabytes of ODP internal memory, and in that perspective a 100MB pool
> creation would be in significant addition to the total shared memory
> consumption - and memory for that  pool could be very well included into
> ODP instance itself. So, there's no obvious preference order for odp-linux
> to state which objects are created at init time and which dynamically. For
> simplicity all memory should be reserved from the system at global init
> time.
>
> For application all handles should be sharable, no matter in which order
> the objects were created. Only restriction would be on if pointers to data
> can be shared.
>
> For example, two processes could
> * always share a packet handle
> * but in odp-linux, could share pointer to packet data (return value of
> odp_packet_data()) only if the packet pool was created before both of those
> processes were forked (from a common ancestor)
>
>
> -Petri
>
>
>
diff mbox

Patch

diff --git a/doc/users-guide/users-guide.adoc b/doc/users-guide/users-guide.adoc
index 745b85f..fbe745f 100755
--- a/doc/users-guide/users-guide.adoc
+++ b/doc/users-guide/users-guide.adoc
@@ -288,6 +288,17 @@  _thread mask_ and _scheduler group_ that determine where they can run and
 the type of work that they can handle. These will be discussed in greater
 detail later.
 
+It is important to note that threads are not ODP objects. This is intentional.
+The ODP API is designed to abstract objects and functions that are relevant to
+data plane programming, and that may find accelerated implementation across
+diverse platforms and architectures. It is not, however, designed to abstract
+operating system objects and concepts. As a result while ODP _refers_ to
+threads, it does not _define_ threads in terms of their creation or management
+from an operating system perspective. ODP does provide _helper_ functions that
+permit Posix threads to be created and managed, however. Applications are free
+to use these helpers or to manage threads in some other manner of their
+choosing.
+
 === Event
 Events are what threads process to perform their work. Events can represent
 new work, such as the arrival of a packet that needs to be processed, or they
@@ -332,6 +343,9 @@  ODP applications if desired.
 
 Shared memory is represented by handles of abstract type `odp_shm_t`.
 
+Note that addressability of shared memory is subject to operating system
+considerations as described in <<Addressing Scope>>.
+
 === Buffer
 A buffer is a fixed sized block of shared storage that is used by ODP
 components and/or applications to realize their function. Buffers contain
@@ -587,10 +601,28 @@  in response to an `odp_queue_deq()` call to get an event from a queue simply
 indicates that the queue is empty.
 
 === Addressing Scope
-Unless specifically noted in the API, all ODP resources are global to the ODP
-application, whether it runs as a single process or multiple processes. ODP
-handles therefore have common meaning within an ODP application but have no
-meaning outside the scope of the application.
+ODP objects and their associated handles are intended to be global to an ODP
+instance, _i.e.,_ to the thread that calls `odp_init_global()` and its
+descendants. However, because ODP does not impose a threading model,
+responsibility for achieving this is shared with both the ODP implementation as
+well as the ODP application. In the odp-linux reference implementation, for
+example, threads are assumed to be Posix-style threads that all share a single
+address space. As a result, all ODP handles and any addresses derived from
+them, are globally sharable throughout the ODP instance. Other implementations
+may offer the same capabilities or may use a process-based threading model in
+which individual threads execute in distinct address spaces.
+
+If a platform uses process that follow a Unix-style `fork()` model of process
+creation, then for best portability ODP applications should be designed so
+that any ODP resource creation (_e.g.,_ pools, shared memory objects, pktios)
+are created during initialization by the thread that creates the ODP instance
+by calling `odp_init_global()` _before_ any other threads are
+created/launched. This will allow any common objects to be visible in forked
+processes.
+
+If a platform uses some other process addressing model, then refer to that
+platform for recommendations to achieve application-desired shared
+addressability.
 
 === Resources and Names
 Many ODP resource objects, such as pools and queues, support an