Re: Pipes and data shaping

From: John Stickley <john_stickley_at_.....>
Date: Thu Jan 05 2006 - 14:32:55 PST
Shabtay,

Responses below. I tried as best I could to incorporate
what we discussed today to answer your questions and
added some more detailed examples. It hope you'll find
the responses fairly straightforward and that they
make common sense.

-- johnS

Shabtay Matalon wrote:
> John,
> 
> Your email response to Jason confirmed the following semantics for pipes.

>> > 
> 
>> > 3. The spec doesn’t explicitly define the HW/SW yield control 
> semantics when using pipes. Here is want we understand so far:
> 
>> > 
> 
>> > Pipe is empty and receive() is called - Yield to producer
> 
>> > Pipe is full and send() is called - Yield to consumer
> 
>> > Pipe is not empty and flush() is called - Yield to consumer
> 
>> > 
> 
>> > Is this correct? Shouldn’t the spec define explicitly the above 
> semantics?
> 
>> 
> 
>>johnS:
> 
>>Yes this is basically correct. We can add some more descriptive text*/ 
> /*there.
> 
>> 
> 
>>-- johnS
> 
>> 
> 
> I am wondering how the following scenario that uses data shaping would 
> work. I am looking at what you have defined as a nozzle meaning that the 
> BFM (producer) is writing elements one at a time, but the PM (consumer) 
> on the C side is reading the transaction (all the elements) as a whole.
> 
>  
> 
> 1.       Assume that pipe fills up while the producer has provided only 
> part of the elements and thus has not issued yet eom and flush. If this 
> cause the pipe to yield to the consumer (as defined above), the 
> dpi_pipe_c_receive method will still blocked until the entire 
> transaction is being written by the producer. This will result in a 
> deadlock as both sides are now waiting on each other. Is this correct or 
> I misunderstood how data shaping is supposed to work?

johnS:
This is solved by making the minimum granularity of the pipe
a full transaction where a transaction is defined as the
maximum # elements as defined on the H/W side in the pipe
declaration.

As we had discussed today, a pipe declaration is a fixed-named
function with a fixed-sized data argument width within at least
given module if not more globally.

The same declaration serves all instances of pipes within that
module distinguished by the intra-module pipe ID arguments.

The bit width of the data argument in the pipe corresponds
to the maximum possible number of elements making up the
transaction which is basically,

# bits of data width = max # elements * #bytes/element * 8

Data shaping can occur for elements within a transaction in
a number up to and including the max # elements - but not more.

To solve the issue you mention above, we make a requirement
that the minimum buffer granularity in the implementation of
the pipe is 1 transaction's worth of data.

So, an implementation can have a buffer size of 1 or more
transactions.

By doing this, we avoid any deadlock that could arise due
to a pipe filling up before all elements of a transaction
because if there is room for 1 element, there is guaranteed
room for all elements.

> 
>  
> 
> 2.       Assume also that the producer has chosen to call flush before 
> eom for whatever reason. The pipe protocol does not prohibit that by my 
> understanding. Correct? This is the “pipe is not empty; yield to 
> consumer” scenario. But again the consumer dpi_pipe_c_receive call will 
> still block as it is waiting on the entire transaction to be written. 
> What will happen in this case?

johnS:
This is solved by making any flush act as if a full
transaction has just been sent by the producer even
if only a partial one has.

So let's consider two scenarios:

-------------------------------------
Funnel:

Producer writes 5 elements then issues a flush

Consumer reads 1 element at a time.

The infrastructure will return from the producer's
send call when the 5th read has occured.

This case is pretty straightforward should raise no concerns.

-------------------------------------
Nozzle:

Producer writes 3 elements 1 element at a time
then does a flush.

Consumer reads 5 elements at a time.

This case is a little trickier. The producer has
only written a partial transaction, then performed
a flush.

In this case the infrastructure assumes the transaction
has been completed and this must satisfy the consumer's
read request in order to avoid deadlock.

The last 2 elements will be undefined in this case
but the read will be completed (i.e. return from
the consumer's call).

-------------------------------------
Also, be sure not to mix eom with flush semantics. The two
are completely independent.

eom is simply a user specified flag that can accompany any written
data. On the other end it will be read with the same data. How and
when it is used is completely up to the user. It can be thought
of a 1 bit extension of the user's data. It works completely
independently of flush.

That said, let's re-examine the two examples from the point
of view of eom:

-------------------------------------
Funnel:

Producer writes 5 elements and marks with eom.

Consumer reads 1 element at a time.

On the 5th call to the pipe the consumer
will see the eom flag set.

-------------------------------------
Nozzle:

Producer writes 3 elements 1 element at a time
The 3rd element is accompanied with eom.
The producer writes two more elements (neither
of which set eom).

Consumer reads 5 elements at a time. It sees eom
set because at least one of the element writes
making up the transaction had specified it.

-- johnS
<eom>

> 
>  
> 
> Thank,
> 
>  
> 
> Shabtay
> 
>  
> 
> PS. I’ll probably read your response after the holidays. Happy Holidays 
> to everybody.
> 
>  
> 
>  
> 
Received on Thu Jan 5 14:33:09 2006

This archive was generated by hypermail 2.1.8 : Thu Jan 05 2006 - 14:33:30 PST