-
Notifications
You must be signed in to change notification settings - Fork 195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
More efficient use of GroovyCategorySupport
#877
Conversation
} | ||
}); | ||
public Outcome run0(final Outcome cn) { | ||
Next n = cn.resumeFrom(e,k); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(ignore WS)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, my main concerns with this kind of change were that it might introduce complex cross-script memory leaks and/or security issues. Looking at GroovyCategorySupport.java
though, I don't really see any obvious problems, mainly given "Groovy (at least the v2 we run) does not offer an API to permanently install a hook" and cloudbees/groovy-cps#16.
One thing to note though is that user-defined category methods and use
do work in @NonCPS
methods (although use
is not allowed in the sandbox by default), so it is at least possible for users to interact with user-defined categories in limited ways. Calls like https://github.com/apache/groovy/blob/41b990d0a20e442f29247f0e04cbed900f3dcad4/src/main/org/codehaus/groovy/runtime/GroovyCategorySupport.java#L187 in the implementation could end up storing user-defined classes in the global ClassInfo
cache, but this seems no different than just using the class directly in a script, and CpsFlowExecution.cleanUpGlobalClassValue
will clean all of that up when the Pipeline completes, so that seems fine.
Right. The categories is just a list of (plugin-defined) classes, and even a This was not a flake. While
This seems to have been due to a core problem unrelated to I will run this through PCT. |
… of things in a test case: `Computer.threadPoolForRemoting` was creating threads using an inappropriate group.
More efficient use of `GroovyCategorySupport` (cherry picked from commit d0f0248)
Follows up #124 / cloudbees/groovy-cps#56 by calling
GroovyCategorySupport.use
only once per thread, rather than on every chunk.Background:
CpsVmExecutorService
has a subtle design in that it is physically hosted on a fairly generic elastic thread pool; the CPS VM “thread” associated with a Pipeline build is virtual (does not correspond to any permanent JavaThread
) and just makes use of some free physical thread whenever it has a chunk of work to run. Typically a chunk would involve as much Groovy logic as can run synchronously (milliseconds’ worth, you hope), up to the point where an asynchronous operation needs to take place, such as starting a step. (parallel
is actually coöperative multitasking: step implementations can certainly run concurrently, but any interactions with the Groovy program are single-threaded. Thus the maximum number of physical threads potentially needed is the number of concurrently running builds, regardless of the number of branches in a single build.)Now in order to support some Groovy hacks we do to make normal-looking language idioms transparently run in CPS mode (#124), we use
GroovyCategorySupport
which sets up some hooks in a dynamic scope (applicable to the currentThread
), and its sole API is to take aClosure
to run with those hooks in effect. Normally setting up and tearing down the hooks is expected to be very quick, but in a heavily loaded controller with complex Pipeline libraries it seems it can be slow and even a source of contention: pool threads from unrelated builds are waiting on the same static (global) lock. (CloudBees-internal reference: SECO-3635)The repeated setup and teardown of categories is actually entirely wasted work, since we set the same hooks for all builds, but Groovy (at least the v2 we run) does not offer an API to permanently install a hook. So to minimize the frequency with which we acquire this global lock, this PR passes Groovy a closure which runs any number of chunks of work from one or more builds in sequence, saving most of the overhead. Java still manages the thread pool as before, creating new threads when there are a lot of concurrent builds doing significant Groovy work, and discarding them when idle.
Note that we do not currently support categories from user code (cloudbees/groovy-cps#16) and it was never clear how we could.