You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by bu...@apache.org on 2020/02/18 18:31:51 UTC

[Bug 64155] New: Tomcat 7 Performance: acceptor thread bottleneck at getPoolSize() located at TaskQueue offer function

https://bz.apache.org/bugzilla/show_bug.cgi?id=64155

            Bug ID: 64155
           Summary: Tomcat 7 Performance: acceptor thread bottleneck at
                    getPoolSize() located at TaskQueue offer function
           Product: Tomcat 7
           Version: trunk
          Hardware: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Catalina
          Assignee: dev@tomcat.apache.org
          Reporter: torres.yang@broadcom.com
  Target Milestone: ---

Created attachment 37022
  --> https://bz.apache.org/bugzilla/attachment.cgi?id=37022&action=edit
Reduced getPoolSize

Tomcat 7 Performance:

During our performance testing, we found out that the acceptor thread
bottleneck at the getPoolSize() located at TaskQueue offer function, which is
an expensive call to AbstractQueuedSynchronizer acquire lock. 


Proposed fix is to store and use poolSize as local variable. This reduces 2-3
expensive calls down to 1 for each request.

    @Override
    public boolean offer(Runnable o) {
      //we can't do any checks
      if (parent == null) return super.offer(o);
      // getPoolSize() is expensive call to AbstractQueuedSynchronizer acquire
lock
      final int poolSize = parent.getPoolSize();
      //we are maxed out on threads, simply queue the object
      if (poolSize == parent.getMaximumPoolSize()) return super.offer(o);
      //we have idle threads, just add it to the queue
      if (parent.getSubmittedCount() <= poolSize) return super.offer(o);
      //if we have less threads than maximum force creation of a new thread
      if (poolSize < parent.getMaximumPoolSize()) return false;
      //if we reached here, we need to add it to the queue
      return super.offer(o);
    }

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 64155] Tomcat 7 Performance: acceptor thread bottleneck at getPoolSize() located at TaskQueue offer function

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=64155

Mark Thomas <ma...@apache.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|REOPENED                    |NEEDINFO

--- Comment #6 from Mark Thomas <ma...@apache.org> ---
I've built various test cases, some load testing Tomcat, some testing
ThreadPoolExecutor directly and I am unable to reproduce any results that show
contention on getPoolSize().

Please provide the simplest possible test case (i.e. one that tests
ThreadPoolExecutor directly) that demonstrates decreasing performance with
increasing concurrency.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 64155] Tomcat 7 Performance: acceptor thread bottleneck at getPoolSize() located at TaskQueue offer function

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=64155

Mark Thomas <ma...@apache.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 OS|                            |All
         Resolution|---                         |INVALID

--- Comment #2 from Mark Thomas <ma...@apache.org> ---
parent is an instance of o.a.t.u.threads.ThreadPoolExecutor

It inherits getPoolSize() from j.u.c.ThreadPoolExecutor

That method returns an int with no synchronization.

There is no use of AbstractQueuedSynchronizer in that call path.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 64155] Tomcat 7 Performance: acceptor thread bottleneck at getPoolSize() located at TaskQueue offer function

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=64155

--- Comment #5 from Torres Yang <to...@broadcom.com> ---
For our test setup, our gateway have 2000 tomcat threads waiting in the pool.
At the same time, we simulate more than 100 virtual users try to hit the
service on gateway.

You can image that under heavy load, we are expect to see slowness because of
this getPoolSize() lock.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 64155] Tomcat 7 Performance: acceptor thread bottleneck at getPoolSize() located at TaskQueue offer function

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=64155

Mark Thomas <ma...@apache.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|INVALID                     |---

--- Comment #4 from Mark Thomas <ma...@apache.org> ---
Ah. I see appears to have been added at some point in Java 7.

Under what test conditions does this bottleneck appear?

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 64155] Tomcat 7 Performance: acceptor thread bottleneck at getPoolSize() located at TaskQueue offer function

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=64155

Mark Thomas <ma...@apache.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|---                         |WORKSFORME
             Status|NEEDINFO                    |RESOLVED

--- Comment #7 from Mark Thomas <ma...@apache.org> ---
Two months have passed with no further information being provided. Absent a
text case that demonstrates the issue, I am resolving this as WORKSFORME. If
the issue persists, feel free to re-open this provided the request test case is
supplied.

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 64155] Tomcat 7 Performance: acceptor thread bottleneck at getPoolSize() located at TaskQueue offer function

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=64155

--- Comment #3 from Torres Yang <to...@broadcom.com> ---
Hi Mark,


Thanks for your prompt reply, o.a.t.u.threads.ThreadPoolExecutor indeed extends
the j.u.c.ThreadPoolExecutor, and it inherits the getPoolSize() from
j.u.c.ThreadPoolExecutor as well.

However, the j.u.c.ThreadPoolExecutor's getPoolSize() implementation has
ReentrantLock in-placed.


Here is the code from Java 8:

    /**
     * Returns the current number of threads in the pool.
     *
     * @return the number of threads
     */
    public int getPoolSize() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // Remove rare and surprising possibility of
            // isTerminated() && getPoolSize() > 0
            return runStateAtLeast(ctl.get(), TIDYING) ? 0
                : workers.size();
        } finally {
            mainLock.unlock();
        }
    }


It's very obvious that whenever go into this function, it must first obtain the
lock before anything.


Hope this explain your question or concern.



Bests,


Torres

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[Bug 64155] Tomcat 7 Performance: acceptor thread bottleneck at getPoolSize() located at TaskQueue offer function

Posted by bu...@apache.org.
https://bz.apache.org/bugzilla/show_bug.cgi?id=64155

--- Comment #1 from Mark Thomas <ma...@apache.org> ---
*** Bug 64156 has been marked as a duplicate of this bug. ***

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org