<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><div dir="ltr"><div>The MPI_Fetch_and_op version trying to implement Pavan's ideas as I 
understand it (no async progress necessary, but also tested with it 
enabled). I have also attached the original code mcs-lock.c with a comment about the adding lmem[nextRank] = -1 in the acquire function (which displays a different race condition behavior, advancing further)<br></div><div><p>I see same behavior in mpich-3.2 and mpich-3.3a2. The older versions mpich-3.1 and mpich-3.0.4 freezes immediately no matter which of the attached codes.</p></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Mar 14, 2017 at 5:50 AM, Balaji, Pavan <span dir="ltr"><<a target="_blank" href="mailto:balaji@anl.gov">balaji@anl.gov</a>></span> wrote:<br><blockquote style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex" class="gmail_quote"><br>
Can you send us the new code?<br>
<span class="gmail-HOEnZb"><font color="#888888"><br>
  -- Pavan<br>
</font></span><div class="gmail-HOEnZb"><div class="gmail-h5"><br>
> On Mar 13, 2017, at 2:48 PM, Ask Jakobsen <<a href="mailto:afj@qeye-labs.com">afj@qeye-labs.com</a>> wrote:<br>
><br>
> Pavan, I have followed your advice using MPI_MODE_NOCHECK and added some flushes, but I still get race conditions sometimes. I suspect that I have not followed your suggestion correctly or that something else is wrong at my end.<br>
><br>
> On Mon, Mar 13, 2017 at 7:43 PM, Ask Jakobsen <<a href="mailto:afj@qeye-labs.com">afj@qeye-labs.com</a>> wrote:<br>
> Thanks Pavan and Halim. You are right it progress in the Fetch_and_op version without the async progress environment variable. I will try to implement the MPI_MODE_NOCHECK as you suggested.<br>
><br>
> To make matters more complicated:<br>
><br>
> I have discovered that the code from the book in mcs-lock.c deviates from "High-Performance Distributed RMA Locks" pseudo code (see Listing 3 in paper) and the original MCS paper "Algorithms for scalable Sync on shared memory multiprocessors". If I add to the original mcs-lock.c code<br>
><br>
> lmem[nextRank]=-1;<br>
><br>
> before entering the MPI_win_lock_all in acquire the code *almost appears* to work! Sort of... when having a large number of processes there are still a rare race condition where a few processes don't get to the MPI_Win_free(&win) in main().<br>
><br>
><br>
> On Mon, Mar 13, 2017 at 6:15 PM, Halim Amer <<a href="mailto:aamer@anl.gov">aamer@anl.gov</a>> wrote:<br>
> To be precise, asynchronous progress is not required for this second implementation because the busy waiting loop is doing a Fetch_and_op. It is required, however, for the first implementation, from the tutorial book, because it busy waits with Win_sync.<br>
><br>
> Halim<br>
> <a target="_blank" rel="noreferrer" href="http://www.mcs.anl.gov/%7Eaamer">www.mcs.anl.gov/~aamer</a><br>
><br>
><br>
> On 3/13/17 8:46 AM, Balaji, Pavan wrote:<br>
><br>
> I should also point out that I don't think your implementation is assuming asynchronous progress.  You shouldn't have to do any of the asynchronous progress tweaks for it to work correctly.<br>
><br>
>   -- Pavan<br>
><br>
> On Mar 13, 2017, at 8:43 AM, Balaji, Pavan <<a href="mailto:balaji@anl.gov">balaji@anl.gov</a>> wrote:<br>
><br>
><br>
> OK, I spent a little more time going through the code.  The algorithm looks correct, except for some minor issues:<br>
><br>
> 1. mcs-lock-fop.c:72 -- you need a flush or flush_local.  You were lucky that this was working correctly since it's local, but the MPI standard doesn't guarantee it.<br>
><br>
> 2. You might be able to simplify mcs-lock-fop.c lines 72-90 as follows:<br>
><br>
>    do {<br>
>      MPI_Fetch_and_op(&dummy, &fetch_nextrank, MPI_INT,<br>
>                   myrank, nextRank, MPI_NO_OP, win);<br>
>      MPI_Win_flush(myrank, win);<br>
>    } while (fetch_nextrank==-1);<br>
><br>
> 3. Polling on the nextrank value is better than polling on a remote location.  However, you could further simplify this by using send/recv to notify the waiting process rather than RMA.  This allows the MPI implementation the opportunity to block waiting for progress, rather than poll (though in practice, current implementations poll anyway).<br>
><br>
> 4. Since you are always using the lock in shared mode, you should specify the hint MPI_MODE_NOCHECK in your lock_all epochs.<br>
><br>
> Now, coming to your bug, this does seem to be a bug in the MPI implementation.  We can dig into it further.  In the meanwhile, if you use the optimization #4 above, this will allow the MPI implementation to bypass the entire locking checks, which will get you past the bug for now.<br>
><br>
> Thanks for reporting the issue.<br>
><br>
>  -- Pavan<br>
><br>
> On Mar 13, 2017, at 3:06 AM, Ask Jakobsen <<a href="mailto:afj@qeye-labs.com">afj@qeye-labs.com</a>> wrote:<br>
><br>
> I don't think so. Rank 0 also holds the tail which is the process which most recently requested the mutex.<br>
><br>
> On Mon, Mar 13, 2017 at 2:55 AM, Balaji, Pavan <<a href="mailto:balaji@anl.gov">balaji@anl.gov</a>> wrote:<br>
><br>
> Shouldn't winsize be 3 integers in your code?  (sorry, I spent only 30 seconds looking at the code, so I might have missed something).<br>
><br>
>  -- Pavan<br>
><br>
> On Mar 12, 2017, at 2:44 PM, Ask Jakobsen <<a href="mailto:afj@qeye-labs.com">afj@qeye-labs.com</a>> wrote:<br>
><br>
> Interestingly, according to the paper you suggested it appears to include a similar test in pseudo code <a target="_blank" rel="noreferrer" href="https://htor.inf.ethz.ch/publications/img/hpclocks.pdf">https://htor.inf.ethz.ch/<wbr>publications/img/hpclocks.pdf</a> (see Listing 3 in paper).<br>
><br>
> Unfortunately, removing the test in the release protocol did not solve the problem. The race condition is much more difficult to provoke, but I managed when setting the size of the communicator to 3 (only tested even sizes so far).<br>
><br>
> From Jeff's suggestion I have attempted to rewrite the code removing local loads and stores in the MPI_Win_lock_all epochs using MPI_Fetch_and_op (see attached files).<br>
><br>
> This version behaves very similar to the original code and also fails from time to time. Putting a sleep into the acquire busy loop (usleep(100)) will make the code "much more robust" (I hack, I know, but indicating some underlying race condition?!). Let me know if you see any problems in the way I am using MPI_Fetch_and_op in a busy loop. Flushing or syncing is not necessary in this case, right?<br>
><br>
> All work is done with export MPIR_CVAR_ASYNC_PROGRESS=1 on mpich-3.2 and mpich-3.3a2<br>
><br>
> On Wed, Mar 8, 2017 at 4:21 PM, Halim Amer <<a href="mailto:aamer@anl.gov">aamer@anl.gov</a>> wrote:<br>
> I cannot claim that I thoroughly verified the correctness of that code, so take it with a grain of salt. Please keep in mind that it is a test code from a tutorial book; those codes are meant for learning purposes not for deployment.<br>
><br>
> If your goal is to have a high performance RMA lock, I suggest you to look into the recent HPDC'16 paper: "High-Performance Distributed RMA Locks".<br>
><br>
> Halim<br>
> <a target="_blank" rel="noreferrer" href="http://www.mcs.anl.gov/%7Eaamer">www.mcs.anl.gov/~aamer</a><br>
><br>
> On 3/8/17 3:06 AM, Ask Jakobsen wrote:<br>
> You are absolutely correct, Halim. Removing the test lmem[nextRank] == -1<br>
> in release fixes the problem. Great work. Now I will try to understand why<br>
> you are right. I hope the authors of the book will credit you for<br>
> discovering the bug.<br>
><br>
> So in conclusion you need to remove the above mentioned test AND enable<br>
> asynchronous progression using the environment variable<br>
> MPIR_CVAR_ASYNC_PROGRESS=1 in MPICH (BTW I still can't get the code to work<br>
> in openmpi).<br>
><br>
> On Tue, Mar 7, 2017 at 5:37 PM, Halim Amer <<a href="mailto:aamer@anl.gov">aamer@anl.gov</a>> wrote:<br>
><br>
> detect that another process is being or already enqueued in the MCS<br>
> queue.<br>
><br>
> Actually the problem occurs only when the waiting process already enqueued<br>
> itself, i.e., the accumulate operation on the nextRank field succeeded.<br>
><br>
> Halim<br>
> <a target="_blank" rel="noreferrer" href="http://www.mcs.anl.gov/%7Eaamer">www.mcs.anl.gov/~aamer</a> <<a target="_blank" rel="noreferrer" href="http://www.mcs.anl.gov/%7Eaamer">http://www.mcs.anl.gov/%<wbr>7Eaamer</a>><br>
><br>
><br>
> On 3/7/17 10:29 AM, Halim Amer wrote:<br>
><br>
> In the Release protocol, try removing this test:<br>
><br>
> if (lmem[nextRank] == -1) {<br>
>   If-Block;<br>
> }<br>
><br>
> but keep the If-Block.<br>
><br>
> The hang occurs because the process releasing the MCS lock fails to<br>
> detect that another process is being or already enqueued in the MCS queue.<br>
><br>
> Halim<br>
> <a target="_blank" rel="noreferrer" href="http://www.mcs.anl.gov/%7Eaamer">www.mcs.anl.gov/~aamer</a> <<a target="_blank" rel="noreferrer" href="http://www.mcs.anl.gov/%7Eaamer">http://www.mcs.anl.gov/%<wbr>7Eaamer</a>><br>
><br>
><br>
> On 3/7/17 6:43 AM, Ask Jakobsen wrote:<br>
><br>
> Thanks, Halim. I have now enabled asynchronous progress in MPICH (can't<br>
> find something similar in openmpi) and now all ranks acquire the lock and<br>
> the program finish as expected. However if I put a while(1) loop<br>
> around the<br>
> acquire-release code in main.c it will fail again at random and go<br>
> into an<br>
> infinite loop. The simple unfair lock does not have this problem.<br>
><br>
> On Tue, Mar 7, 2017 at 12:44 AM, Halim Amer <<a href="mailto:aamer@anl.gov">aamer@anl.gov</a>> wrote:<br>
><br>
> My understanding is that this code assumes asynchronous progress.<br>
> An example of when the processes hang is as follows:<br>
><br>
> 1) P0 Finishes MCSLockAcquire()<br>
> 2) P1 is busy waiting in MCSLockAcquire() at<br>
> do {<br>
>      MPI_Win_sync(win);<br>
>   } while (lmem[blocked] == 1);<br>
> 3) P0 executes MCSLockRelease()<br>
> 4) P0 waits on MPI_Win_lock_all() inside MCSLockRlease()<br>
><br>
> Hang!<br>
><br>
> For P1 to get out of the loop, P0 has to get out of<br>
> MPI_Win_lock_all() and<br>
> executes its Compare_and_swap().<br>
><br>
> For P0 to get out MPI_Win_lock_all(), it needs an ACK from P1 that it<br>
> got<br>
> the lock.<br>
><br>
> P1 does not make communication progress because MPI_Win_sync is not<br>
> required to do so. It only synchronizes private and public copies.<br>
><br>
> For this hang to disappear, one can either trigger progress manually by<br>
> using heavy-duty synchronization calls instead of Win_sync (e.g.,<br>
> Win_unlock_all + Win_lock_all), or enable asynchronous progress.<br>
><br>
> To enable asynchronous progress in MPICH, set the<br>
> MPIR_CVAR_ASYNC_PROGRESS<br>
> env var to 1.<br>
><br>
> Halim<br>
> <a target="_blank" rel="noreferrer" href="http://www.mcs.anl.gov/%7Eaamer">www.mcs.anl.gov/~aamer</a> <<a target="_blank" rel="noreferrer" href="http://www.mcs.anl.gov/%7Eaamer">http://www.mcs.anl.gov/%<wbr>7Eaamer</a>> <<br>
> <a target="_blank" rel="noreferrer" href="http://www.mcs.anl.gov/%7Eaamer">http://www.mcs.anl.gov/%<wbr>7Eaamer</a>><br>
><br>
><br>
> On 3/6/17 1:11 PM, Ask Jakobsen wrote:<br>
><br>
> I am testing on x86_64 platform.<br>
><br>
> I have tried to built both the mpich and the mcs lock code with -O0 to<br>
> avoid agressive optimization. After your suggestion I have also<br>
> tried to<br>
> make volatile int *pblocked pointing to lmem[blocked] in the<br>
> MCSLockAcquire<br>
> function and volatile int *pnextrank pointing to lmem[nextRank] in<br>
> MCSLockRelease, but it does not appear to make a difference.<br>
><br>
> On suggestion from Richard Warren I have also tried building the code<br>
> using<br>
> openmpi-2.0.2 without any luck (however it appears to acquire the<br>
> lock a<br>
> couple of extra times before failing) which I find troubling.<br>
><br>
> I think I will give up using local load/stores and will see if I can<br>
> figure<br>
> out if rewrite using MPI calls like MPI_Fetch_and_op  as you suggest.<br>
> Thanks for your help.<br>
><br>
> On Mon, Mar 6, 2017 at 7:20 PM, Jeff Hammond <<a href="mailto:jeff.science@gmail.com">jeff.science@gmail.com</a>><br>
> wrote:<br>
><br>
> What processor architecture are you testing?<br>
><br>
><br>
> Maybe set lmem to volatile or read it with MPI_Fetch_and_op rather<br>
> than a<br>
> load.  MPI_Win_sync cannot prevent the compiler from caching *lmem<br>
> in a<br>
> register.<br>
><br>
> Jeff<br>
><br>
> On Sat, Mar 4, 2017 at 12:30 AM, Ask Jakobsen <<a href="mailto:afj@qeye-labs.com">afj@qeye-labs.com</a>><br>
> wrote:<br>
><br>
> Hi,<br>
><br>
><br>
> I have downloaded the source code for the MCS lock from the excellent<br>
> book "Using Advanced MPI" from <a target="_blank" rel="noreferrer" href="http://www.mcs.anl.gov/researc">http://www.mcs.anl.gov/researc</a><br>
> h/projects/mpi/usingmpi/<wbr>examples-advmpi/rma2/mcs-lock.<wbr>c<br>
><br>
> I have made a very simple piece of test code for testing the MCS lock<br>
> but<br>
> it works at random and often never escapes the busy loops in the<br>
> acquire<br>
> and release functions (see attached source code). The code appears<br>
> semantically correct to my eyes.<br>
><br>
> #include <stdio.h><br>
> #include <mpi.h><br>
> #include "mcs-lock.h"<br>
><br>
> int main(int argc, char *argv[])<br>
> {<br>
>  MPI_Win win;<br>
>  MPI_Init( &argc, &argv );<br>
><br>
>  MCSLockInit(MPI_COMM_WORLD, &win);<br>
><br>
>  int rank, size;<br>
>  MPI_Comm_rank(MPI_COMM_WORLD, &rank);<br>
>  MPI_Comm_size(MPI_COMM_WORLD, &size);<br>
><br>
>  printf("rank: %d, size: %d\n", rank, size);<br>
><br>
><br>
>  MCSLockAcquire(win);<br>
>  printf("rank %d aquired lock\n", rank);   fflush(stdout);<br>
>  MCSLockRelease(win);<br>
><br>
><br>
>  MPI_Win_free(&win);<br>
>  MPI_Finalize();<br>
>  return 0;<br>
> }<br>
><br>
><br>
> I have tested on several hardware platforms and mpich-3.2 and<br>
> mpich-3.3a2<br>
> but with no luck.<br>
><br>
> It appears that the MPI_Win_Sync are not "refreshing" the local<br>
> data or<br>
> I<br>
> have a bug I can't spot.<br>
><br>
> A simple unfair lock like <a target="_blank" rel="noreferrer" href="http://www.mcs.anl.gov/researc">http://www.mcs.anl.gov/researc</a><br>
> h/projects/mpi/usingmpi/<wbr>examples-advmpi/rma2/ga_<wbr>mutex1.c works<br>
> perfectly.<br>
><br>
> Best regards, Ask Jakobsen<br>
><br>
><br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
><br>
><br>
><br>
> --<br>
> Jeff Hammond<br>
> <a href="mailto:jeff.science@gmail.com">jeff.science@gmail.com</a><br>
> <a target="_blank" rel="noreferrer" href="http://jeffhammond.github.io/">http://jeffhammond.github.io/</a><br>
><br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
><br>
><br>
><br>
><br>
><br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
> ______________________________<wbr>_________________<br>
><br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
><br>
><br>
><br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
><br>
><br>
><br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
> <main.c><mcs-lock-fop.c><mcs-<wbr>lock.h>_______________________<wbr>________________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
><br>
><br>
> --<br>
> Ask Jakobsen<br>
> R&D<br>
><br>
> Qeye Labs<br>
> Lersø Parkallé 107<br>
> 2100 Copenhagen Ø<br>
> Denmark<br>
><br>
> mobile: <a value="+4528346936" href="tel:%2B45%202834%206936">+45 2834 6936</a><br>
> email: afj@Qeye-Labs.com<br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
><br>
><br>
><br>
> --<br>
> Ask Jakobsen<br>
> R&D<br>
><br>
> Qeye Labs<br>
> Lersø Parkallé 107<br>
> 2100 Copenhagen Ø<br>
> Denmark<br>
><br>
> mobile: <a value="+4528346936" href="tel:%2B45%202834%206936">+45 2834 6936</a><br>
> email: afj@Qeye-Labs.com<br>
><br>
><br>
><br>
> --<br>
> Ask Jakobsen<br>
> R&D<br>
><br>
> Qeye Labs<br>
> Lersø Parkallé 107<br>
> 2100 Copenhagen Ø<br>
> Denmark<br>
><br>
> mobile: <a value="+4528346936" href="tel:%2B45%202834%206936">+45 2834 6936</a><br>
> email: afj@Qeye-Labs.com<br>
> ______________________________<wbr>_________________<br>
> discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
> To manage subscription options or unsubscribe:<br>
> <a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a><br>
<br>
______________________________<wbr>_________________<br>
discuss mailing list     <a href="mailto:discuss@mpich.org">discuss@mpich.org</a><br>
To manage subscription options or unsubscribe:<br>
<a target="_blank" rel="noreferrer" href="https://lists.mpich.org/mailman/listinfo/discuss">https://lists.mpich.org/<wbr>mailman/listinfo/discuss</a></div></div></blockquote></div><br></div></div>