Re: [PATCH v3] CodeSamples/count: add necessary partial memory barriers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Mar 29, 2023 at 08:43:33AM +0900, Akira Yokosawa wrote:
> On Tue, 28 Mar 2023 10:58:24 -0400, Alan Huang wrote:
> > This patch add several necessary partial memory barriers, the first one
> > change READ_ONCE to smp_load_acquire to makes sure the reading from theftp[t]
> > happens before the reading from counterp[t]. The litmus testing below
> > represents the original code pattern, and the result is "Sometimes":
> > 
> > C counter_sig
> > 
> > {}
> > 
> > P0(int *theft, int *counter)
> > {
> >     int r0;
> >     int r1;
> > 
> >     r0 = READ_ONCE(*theft);
> >     r1 = READ_ONCE(*counter);
> > }
> > 
> > P1(int *theft, int *counter)
> > {
> >     WRITE_ONCE(*counter, 1);
> >     smp_mb();
> >     WRITE_ONCE(*theft, 1);
> > }
> > 
> > exists (0:r0=1 /\ 0:r1=0)
> > 
> > Second one change WRITE_ONCE to smp_store_release to make sure that setting
> > counterp[t] happens before the setting theftp[p] to THEFT_IDLE. Here is the
> > litmus testing, The result is "Sometimes":
> > 
> > C counter_sig_2
> > 
> > {
> >     int theft = 1;
> >     int counter = 1;
> > }
> > 
> > P0(int *theft, int *counter)
> > {
> >     WRITE_ONCE(*counter, 0);
> >     WRITE_ONCE(*theft, 0);
> > }
> > 
> > P1(int *theft, int *counter)
> > {
> >     if (READ_ONCE(*theft) == 0)
> >     {
> >         WRITE_ONCE(*counter, READ_ONCE(*counter)+1);
> >     }
> > }
> > 
> > P2(int *counter)
> > {
> >     int r0;
> > 
> >     r0 = READ_ONCE(*counter);
> > }
> > 
> > exists (2:r0=2)
> > 
> > Note that I also changed the reading of theft variable
> > to smp_load_acquire in add_count/sub_count's fast path
> > to make sure that reading theft happens before reading
> > counter.
> > 
> > Signed-off-by: Alan Huang <mmpgouride@xxxxxxxxx>
> 
> Looks good to me.
> Reviewed-by: Akira Yokosawa <akiyks@xxxxxxxxx>

Thank you both!

> Paul, there is a question for you.
> Please see below.
> 
> > ---
> >  CodeSamples/count/count_lim_sig.c | 8 ++++----
> >  1 file changed, 4 insertions(+), 4 deletions(-)
> > 
> > diff --git a/CodeSamples/count/count_lim_sig.c b/CodeSamples/count/count_lim_sig.c
> > index 023d6215..59da8077 100644
> > --- a/CodeSamples/count/count_lim_sig.c
> > +++ b/CodeSamples/count/count_lim_sig.c
> > @@ -81,7 +81,7 @@ static void flush_local_count(void)			//\lnlbl{flush:b}
> >  	for_each_tid(t, tid) {				//\lnlbl{flush:loop2:b}
> >  		if (theftp[t] == NULL)			//\lnlbl{flush:skip:nonexist}
> >  			continue;			//\lnlbl{flush:next2}
> > -		while (READ_ONCE(*theftp[t]) != THEFT_READY) {//\lnlbl{flush:loop3:b}
> > +		while (smp_load_acquire(theftp[t]) != THEFT_READY) {//\lnlbl{flush:loop3:b}
> >  			poll(NULL, 0, 1);		//\lnlbl{flush:block}
> >  			if (READ_ONCE(*theftp[t]) == THEFT_REQ)//\lnlbl{flush:check:REQ}
> >  				pthread_kill(tid, SIGUSR1);//\lnlbl{flush:signal2}
> > @@ -90,7 +90,7 @@ static void flush_local_count(void)			//\lnlbl{flush:b}
> >  		*counterp[t] = 0;
> >  		globalreserve -= *countermaxp[t];
> >  		*countermaxp[t] = 0;			//\lnlbl{flush:thiev:e}
> > -		WRITE_ONCE(*theftp[t], THEFT_IDLE);	//\lnlbl{flush:IDLE}
> > +		smp_store_release(theftp[t], THEFT_IDLE);	//\lnlbl{flush:IDLE}
> >  	}						//\lnlbl{flush:loop2:e}
> >  }							//\lnlbl{flush:e}
> >  
> > @@ -116,7 +116,7 @@ int add_count(unsigned long delta)			//\lnlbl{b}
> >  
> >  	WRITE_ONCE(counting, 1);			//\lnlbl{fast:b}
> >  	barrier();					//\lnlbl{barrier:1}
> > -	if (READ_ONCE(theft) <= THEFT_REQ &&		//\lnlbl{check:b}
> > +	if (smp_load_acquire(&theft) <= THEFT_REQ &&		//\lnlbl{check:b}
> >  	    countermax - counter >= delta) {		//\lnlbl{check:e}
> >  		WRITE_ONCE(counter, counter + delta);	//\lnlbl{add:f}
> >  		fastpath = 1;				//\lnlbl{fasttaken}
> > @@ -155,7 +155,7 @@ int sub_count(unsigned long delta)
> >  
> >  	WRITE_ONCE(counting, 1);
> >  	barrier();
> > -	if (READ_ONCE(theft) <= THEFT_REQ &&
> > +	if (smp_load_acquire(&theft) <= THEFT_REQ &&
> >  	    counter >= delta) {
> >  		WRITE_ONCE(counter, counter - delta);
> >  		fastpath = 1;
> 
> In add_count() and sub_count(), is the plain accesses to counter
> guaranteed to see the value stored in flush_local_count()?
> 
> I'm asking because counter is declared as a thread-local variable:
> 
> In this code, as each of the plain loads of counter is the first
> access to the variable in each function, there is not much room
> for compilers to exploit the plainness, I suppose.
> 
> What do you think?

Well, gitk thinks that the last deliberate change to this code was in
2010, before READ_ONCE() and WRITE_ONCE(), let alone LKMM.  So it needs
careful scrutiny, along with the other counting algorithms.

This commit looks like a step in the right direction, so I am applying
it, thank you both!

Alan, would you like to drag the counting code kicking and screaming
into the 2020s?  ;-)

							Thanx, Paul



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux