Hi David and Robbin,

Could we consider  making the ServiceThread responsible for the ThreadIdTable 
resizing in the similar way how
it works for  StringTable  and ResolvedMethodTable, rather than having 
ThreadIdTable::add() method calling ThreadIdTable::grow()? 
As I understand It should solve  the current  issue and  address the concern 
that  the doing the resizing could be a relatively long and 
doing it without polling  for safepoints or while the holding Threads_lock is 
not desirable.

Thank you,
Daniil


On 10/2/19, 6:25 AM, "David Holmes" <david.hol...@oracle.com> wrote:

    Hi Robbin,
    
    On 2/10/2019 7:58 pm, Robbin Ehn wrote:
    > Hi David,
    > 
    >> What if the table is full and must be grown?
    > 
    > The table uses chaining, it just means load factor tip over what is 
    > considered a good backing array size.
    
    Coleen raised a good question in a separate discussion, which made me 
    realize that once the table has been initially populated all subsequent 
    additions, and hence all subsequent calls to grow() always happen with 
    the Threads_lock held. So we can't just defer the grow().
    
    >> That aside, I'd like to know how expensive it is to grow this table. 
    >> What are we talking about here?
    > 
    > We use global counter which on write_synchronize must scan all
    > threads to make sure they have seen the update (there some
    > optimization to avoid it if there is no readers at all). Since this
    > table contains the threads, we get double penalized, for each new
    > thread the synchronization cost increase AND the number of items.
    > 
    > With concurrent reads you still need many thousands of threads, but
    > I think I saw someone mentioning 100k threads, assuming concurrent
    > queries the resize can take hundreds of ms to finish. Note that reads
    > and inserts still in operate roughly at the same speed while 
    > resizing. So a longer resize is only problematic if we do not
    > respect safepoints.
    I think if anything were capable of running 100K threads we would be 
    hitting far worse scalability bottlenecks than this. But this does seem 
    problematic.
    
    Thanks,
    David
    -----
    
    > Thanks, Robbin
    > 
    >>
    >> David
    >>
    >>> /Robbin
    >>>
    >>> On 2019-10-02 08:46, David Holmes wrote:
    >>>> Hi Daniil,
    >>>>
    >>>> On 2/10/2019 4:13 pm, Daniil Titov wrote:
    >>>>> Please review a change that fixes the issue. The problem here is 
    >>>>> that that the thread is added to the ThreadIdTable  (introduced in 
    >>>>> [3]) while the Threads_lock is held by
    >>>>> JVM_StartThread. When new thread is added  to the thread table the 
    >>>>> table checks if its load factor is greater than required and if so 
    >>>>> it grows itself while polling for safepoints.
    >>>>> After changes [4]  an attempt to block the thread while holding the 
    >>>>> Threads_lock  results in assertion in 
    >>>>> Thread::check_possible_safepoint().
    >>>>>
    >>>>> The fix  proposed by David Holmes ( thank you, David!)  is to skip 
    >>>>> the ThreadBlockInVM inside ThreadIdTable::grow() method if the 
    >>>>> current thread owns the Threads_lock.
    >>>>
    >>>> Sorry but looking at the fix in context now I think it would be 
    >>>> better to do this:
    >>>>
    >>>>      while (gt.do_task(jt)) {
    >>>>        if (Threads_lock->owner() == jt) {
    >>>>          gt.pause(jt);
    >>>>          ThreadBlockInVM tbivm(jt);
    >>>>          gt.cont(jt);
    >>>>        }
    >>>>      }
    >>>>
    >>>> This way we don't waste time with the pause/cont when there's no 
    >>>> safepoint pause going to happen - and the owner() check is quicker 
    >>>> than owned_by_self(). That partially addresses a general concern I 
    >>>> have about how long it may take to grow the table, as we are 
    >>>> deferring safepoints until it is complete in this JVM_StartThread 
    >>>> usecase.
    >>>>
    >>>> In the test you don't need all of:
    >>>>
    >>>>    32  * @run clean ThreadStartTest
    >>>>    33  * @run build ThreadStartTest
    >>>>    34  * @run main ThreadStartTest
    >>>>
    >>>> just the last @run suffices to build and run the test.
    >>>>
    >>>> Thanks,
    >>>> David
    >>>> -----
    >>>>
    >>>>> Testing : Mach 5 tier1 and tier2 completed successfully, tier3 is 
    >>>>> in progress.
    >>>>>
    >>>>> [1] Webrev: http://cr.openjdk.java.net/~dtitov/8231666/webrev.01/
    >>>>> [2] Bug: https://bugs.openjdk.java.net/browse/JDK-8231666
    >>>>> [3] https://bugs.openjdk.java.net/browse/JDK-8185005
    >>>>> [4] https://bugs.openjdk.java.net/browse/JDK-8184732
    >>>>>
    >>>>> Best regards,
    >>>>> Danill
    >>>>>
    >>>>>
    


Reply via email to