ForkJoinTask.externalAwaitDone() co-operates only with commonPool?

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

ForkJoinTask.externalAwaitDone() co-operates only with commonPool?

Ruslan Cheremin
Tracing the execution of FJTask.join() I've found the code externalAwaitDone() (listed below), from which it is obvious external (non-FJP) thread will try to help to execute tasks _only from commonPool_, and just blocks otherwise. 

I was sure FJP.commonPool is not any kind special, just the same as any other FJPool. From the code below it looks like it is special: any external thread doing .join() will try to help only commonPool's tasks, but not any other FJPools.

Why it is implemented this way? Can't .join() always try to help the actual FJPool current FJTask is enqueued into?

It is also interesting: is there any other places in FJTask/Pool machinery there commonPool is treated specially?

--------- ForkJoinTask----

private int externalAwaitDone() {
        int s = ((this instanceof CountedCompleter) ? // try helping
                 ForkJoinPool.common.externalHelpComplete(
                     (CountedCompleter<?>)this, 0) :
                 ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : 0);
        if (s >= 0 && (s = status) >= 0) {
            boolean interrupted = false;
            do {
                if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
                    synchronized (this) {
                        if (status >= 0) {
                            try {
                                wait(0L);
                            } catch (InterruptedException ie) {
                                interrupted = true;
                            }
                        }
                        else
                            notifyAll();
                    }
                }
            } while ((s = status) >= 0);
            if (interrupted)
                Thread.currentThread().interrupt();
        }
        return s;
    }

----
Ruslan

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ForkJoinTask.externalAwaitDone() co-operates only with commonPool?

Doug Lea
On 02/05/2017 10:34 AM, Ruslan Cheremin wrote:
> Tracing the execution of FJTask.join() I've found the code
> externalAwaitDone() (listed below), from which it is obvious external
> (non-FJP) thread will try to help to execute tasks _only from
> commonPool_, and just blocks otherwise.

Threads in all cases try to help, but in non-commonPool they may
reach a point where they block sooner than in common pool,
where they must continue to find and help with tasks vs
block in case there are no other workers, until/unless they
are sure that they are not needed.

There are methods allowing manual control of this extra helping
in non-commonpool usage. For example helpQuiesce and helpComplete.
They are not performed otherwise because they can cause unnecessary
overhead.

-Doug


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ForkJoinTask.externalAwaitDone() co-operates only with commonPool?

Ruslan Cheremin
>Threads in all cases try to help, but in non-commonPool they may
reach a point where they block sooner than in common pool,
where they must continue to find and help with tasks vs
block in case there are no other workers, until/unless they
are sure that they are not needed.

May be I miss something important, but I can't see in code how do threads tries to help:

FJTask.join() invokes FJTask.doJoin(), which, indeed, do tryUnpush(this) and doExec(), but only if (currentThread instanceof FJPThread), otherwise doJoin() invokes .externalAwaitDone(), which tries to help only commonPool.

I see no way non-FJP-thread invoking FJTask.join() may help some pool other than commonPool...

Is it because there is no way to find out to which FJPool given FJTask was submitted?


----
Ruslan

2017-02-05 18:53 GMT+03:00 Doug Lea <[hidden email]>:
On 02/05/2017 10:34 AM, Ruslan Cheremin wrote:
Tracing the execution of FJTask.join() I've found the code
externalAwaitDone() (listed below), from which it is obvious external
(non-FJP) thread will try to help to execute tasks _only from
commonPool_, and just blocks otherwise.

Threads in all cases try to help, but in non-commonPool they may
reach a point where they block sooner than in common pool,
where they must continue to find and help with tasks vs
block in case there are no other workers, until/unless they
are sure that they are not needed.

There are methods allowing manual control of this extra helping
in non-commonpool usage. For example helpQuiesce and helpComplete.
They are not performed otherwise because they can cause unnecessary
overhead.

-Doug


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ForkJoinTask.externalAwaitDone() co-operates only with commonPool?

Doug Lea
On 02/05/2017 11:33 AM, Ruslan Cheremin wrote:

> May be I miss something important, but I can't see in code how do
> threads tries to help:

Oh, sorry to misinterpret your question. "External" threads
(non-ForkJoinWorkerThreads) by design do not help normal pools,
which makes them act like other ExecutorServices.
(I was referring to "internal" threads in previous answer.)
But they must help in commonPool, mainly because the
commonPool might not have any workers, due to system-wide
policies. Doing it this way enables parallelStreams etc to
still work in managed environments (although with no
possibility of speedup). But this is an add-on to
ForkJoinPools that doesn't apply in general.


>
> Is it because there is no way to find out to which FJPool given FJTask
> was submitted?
>

Yes, although that's more of a consequence rather than a cause.

-Doug

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ForkJoinTask.externalAwaitDone() co-operates only with commonPool?

Ruslan Cheremin
>mainly because the commonPool might not have any workers, due to system-wide policies. Doing it this way enables parallelStreams etc to still work in managed environments (although with no possibility of speedup)

Oh, so it is for purposes of fallback/graceful degradation. Very interesting, thank you for pointing this out, Doug.

But doesn't it put additional overhead on commonPool? I mean, every time I use .join() on non-commonPool tasks, current thread tries to steal task back from commonPool workQueue(s), which is never succeeded, but probably do some cache trashing anyway?


2017-02-06 0:44 GMT+03:00 Doug Lea <[hidden email]>:
On 02/05/2017 11:33 AM, Ruslan Cheremin wrote:

May be I miss something important, but I can't see in code how do
threads tries to help:

Oh, sorry to misinterpret your question. "External" threads
(non-ForkJoinWorkerThreads) by design do not help normal pools,
which makes them act like other ExecutorServices.
(I was referring to "internal" threads in previous answer.)
But they must help in commonPool, mainly because the
commonPool might not have any workers, due to system-wide
policies. Doing it this way enables parallelStreams etc to
still work in managed environments (although with no
possibility of speedup). But this is an add-on to
ForkJoinPools that doesn't apply in general.



Is it because there is no way to find out to which FJPool given FJTask
was submitted?


Yes, although that's more of a consequence rather than a cause.

-Doug



_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ForkJoinTask.externalAwaitDone() co-operates only with commonPool?

Kirk Pepperdine
In reply to this post by Doug Lea
Hi,

A while back I sifted through f-j and sorted out a way to instrument it with JMX. I am sure that my hack wasn’t the best way to instrument f-j but it did give me the information I needed at the time. Given the importance of the common thread-pool and f-j I am wondering if it might be a good idea to explore a way to add instrumentation so that important metrics can be exposed via the Platform MBean server to improve observability in the runtime?

Kind regards,
Kirk Pepperdine

> On Feb 5, 2017, at 10:44 PM, Doug Lea <[hidden email]> wrote:
>
> On 02/05/2017 11:33 AM, Ruslan Cheremin wrote:
>
>> May be I miss something important, but I can't see in code how do
>> threads tries to help:
>
> Oh, sorry to misinterpret your question. "External" threads
> (non-ForkJoinWorkerThreads) by design do not help normal pools,
> which makes them act like other ExecutorServices.
> (I was referring to "internal" threads in previous answer.)
> But they must help in commonPool, mainly because the
> commonPool might not have any workers, due to system-wide
> policies. Doing it this way enables parallelStreams etc to
> still work in managed environments (although with no
> possibility of speedup). But this is an add-on to
> ForkJoinPools that doesn't apply in general.
>
>
>>
>> Is it because there is no way to find out to which FJPool given FJTask
>> was submitted?
>>
>
> Yes, although that's more of a consequence rather than a cause.
>
> -Doug
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ForkJoinTask.externalAwaitDone() co-operates only with commonPool?

Doug Lea
In reply to this post by Ruslan Cheremin
On 02/05/2017 04:58 PM, Ruslan Cheremin wrote:

>>mainly because the commonPool might not have any workers, due to
> system-wide policies. Doing it this way enables parallelStreams etc
> to still work in managed environments (although with no possibility of
> speedup)
>
> Oh, so it is for purposes of fallback/graceful degradation. Very
> interesting, thank you for pointing this out, Doug.
>
> But doesn't it put additional overhead on commonPool? I mean, every time
> I use .join() on non-commonPool tasks, current thread tries to steal
> task back from commonPool workQueue(s), which is never succeeded, but
> probably do some cache trashing anyway?
>

You can concoct scenarios where this could have a measurable impact,
but it almost never does. In the usual case where
the commonPool is quiescent but your user pool is not,
it amounts to a table lookup on a variable that is not changing,
adding only a cache line or two to per-thread footprint.

-Doug


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: ForkJoinTask.externalAwaitDone() co-operates only with commonPool?

Doug Lea
In reply to this post by Kirk Pepperdine
On 02/06/2017 01:47 AM, [hidden email] wrote:

> Hi,
>
> A while back I sifted through f-j and sorted out a way to instrument
> it with JMX. I am sure that my hack wasn’t the best way to instrument
> f-j but it did give me the information I needed at the time. Given
> the importance of the common thread-pool and f-j I am wondering if it
> might be a good idea to explore a way to add instrumentation so that
> important metrics can be exposed via the Platform MBean server to
> improve observability in the runtime?
>

What metrics do you have in mind? Are they different than
what you can get by calling fjp.toString (which collects
up the status query methods)? Here's a sample output:

java.util.concurrent.ForkJoinPool@2ef5e5e3[Running, parallelism = 64,
size = 64, active = 0, running = 0, steals = 112778, tasks = 0,
submissions = 0]

In general, rather than linking to JMX etc, j.u.c components
have status query methods summarized in toString methods, that
we hope are easy to connect to any monitoring facility.

-Doug

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest