I'm pretty sure we don't want to expose a raw ExecutorService. We are
pretty careful about exposing Gradle APIs that we have control over, rather
than APIs that we don't have control over.

One of the benefits of providing a specific API for parallel external
processes is that Gradle could automatically buffer the input/output,
provide progress reporting, etc. I haven't put a lot of thought into what
our Gradle-wide parallel mechanism will look like, but if we start with an
AsyncExecAction (or similar) we can later change AsyncExecAction to wrap
the new API.

If you want to create a completely separate service for this (instead of
extending ExecActionFactory) then that would be fine, too.

Daz

On Sat, Jul 5, 2014 at 1:20 PM, Daniel Lacasse <daniel.lacass...@gmail.com>
wrote:

> I was thinking about this Daz. Would it be more flexible, extensible and
> powerful if we would just inject a singleton whenever someone request it of
> a ExecutorService that is configured according to the parallel-threads
> count?
>
> Creating an AsyncExecAction is more code to maintain and support as
> opposed to letting the developers choose to just wrap an normal ExecAction
> into a Callable and submitting it to the ExecutorService.
>
> The pro is we get closer to option #2 and #3 for a Gradle-wide parallel
> mechanism. The con is do we really want to expose the actual
> ExecutorService?
>
> I realise that we should explore this a bit more. What are your thoughts
> on this?
>
>  ---
> Daniel
> ------------------------------
> On Thursday, July 3, 2014 11:09 PM, Daz DeBoer <
> darrell.deb...@gradleware.com> wrote:
>
>
>
>
>  On Wed, Jul 2, 2014 at 7:36 PM, Daniel Lacasse <
> daniel.lacass...@gmail.com> wrote:
>
>> Sounds like a better plan as it would add more building blocks to gradle.
>>
>> Correct me if I'm wrong. They would probably be a global ExecutorService
>> to avoid recreating it at ever task and share the threads between everyone
>> who use it.
>
>
>  Yes. ExecActionFactory is currently implemented by
> DefaultFileOperations, which is created per-project. So if you just make
> the change there you could have an ExecutorService per project. We could
> further improve this if we like by adding something to BuildScopeServices
> that is shared by all project instances.
>
>  For now, I'd keep the implementation of
> ExecActionFactory.createAsyncAction nice and simple, because Adam is sure
> to have some ideas on how this could be better structured, when he's back
> from holidays.
>
>  The problem I see - which could be a temporary thing until option #3 is
>> implemented - is parallel-threads will be the number of parallel task
>> executed at the same time as the number of compiler fork. For someone using
>> the parallel flags, it may be non-intuitive. It basically boils down to how
>> do we share the parallel-threads number between parallel task execution and
>> number of compiler fork? In my mind parallel-threads is the maximum number
>> of threads that Gradle should be allowed to create for his parallel
>> business.
>>
>
>  Yes, we'd be overloading the 'parallel-threads' setting, so that you'd
> have both N projects being built in parallel, as well as N files being
> compiled in parallel. But the end goal is to use a single setting to
> control all parallelism, and this is a step in that direction.
>
>
>> Thanks again Daz and I will move in the direction you are suggesting.
>>
>>  ---
>> Daniel
>> ------------------------------
>>   On Wednesday, July 2, 2014 09:34 AM, Daz DeBoer <
>> darrell.deb...@gradleware.com> wrote:
>>
>>    On Mon, Jun 30, 2014 at 7:24 PM, Daniel Lacasse <
>> daniel.lacass...@gmail.com> wrote:
>>
>>>  I did some research on how to implement option #1 and here is the
>>> implementation:
>>>
>>>    - In
>>>    org.gradle.nativebinaries.language.c.tasks.AbstractNativeCompilerTask:
>>>       - Add option int maximumNumberOfCompilerFork = 1
>>>       - 1 is to prevent any side effect. It will mainly behave just
>>>       like it was previously.
>>>       - I'm open to suggestion on the chosen name.
>>>       - No @Input on the new option
>>>    - In org.gradle.nativebinaries.toolchain.internal.NativeCompileSpec:
>>>       - set/getMaximumNumberOfCompilerFork
>>>    - In
>>>    org.gradle.nativebinaries.language.internal.AbstractNativeCompilerSpec:
>>>       - set/getMaximumNumberOfCompilerFork implementation
>>>    - In
>>>    
>>> org.gradle.nativebinaries.toolchain.internal.{gcc|msvcpp}.NativeCompilerSpec:
>>>       - Add modification to method WorkResult execute(T spec)
>>>       - Use a ThreadPoolExecutor with maximumPoolSize set to
>>>       maximumNumberOfCompileFork and corePoolSize set to 1
>>>       - Submit anonymous Callable<WorkResult> class to the
>>>       ThreadPoolExecutor
>>>       - Use the get method on each Future returned by Submit to join
>>>       all the work together.
>>>
>>>  This cover pretty much the option #1 for parallel compilation in the
>>> native extension. The 2 open issues would be:
>>>
>>>    - Is maximumNumberOfCompilerFork a good choice for the option name?
>>>    If not, what would be the appropriate name?
>>>
>>>   Let's avoid adding a configuration option for this at this stage.
>> What we really want is to make this configurable at a much higher level,
>> and auto-detect the optimal setting.
>>
>>  For now, let's use the value of 'parallel-threads' for this setting.
>> Even though this is a bit coarse grained, it takes us in the right
>> direction. So instead of passing the value from
>> Task->CompileSpec->NativeCompiler, we would access the value from
>> StartParameter#getParallelThreadCount.
>>
>>  I think the easiest way to do this would be to add a method to
>> ExecActionFactory that provided an AsyncExecAction, which would be similar
>> to ExecAction, but something like:
>>
>>   public interface AsyncExecAction extends ExecSpec {
>>      Future<ExecResult> submit();
>>  }
>>
>>  You could then modify
>> org.gradle.nativebinaries.toolchain.internal.CommandLineTool to use async
>> actions, and to present some sort of submit/collect API. This would mean
>> that the parallel functionality would be available everywhere that
>> CommandLineTool is used, which means both VisualCpp and Gcc based tool
>> chains.
>>
>>  How does this sound? While it may seem a bit more involved, the design
>> will be largely the same. You'll still need a ThreadPoolExecuter and code
>> to submit/collect, but this design takes your suggested solution and moves
>> most of the code out of the NativeCompiler implementations into the
>> CommandLineTool and ExecActionFactory.  The nice thing about this is that
>> it makes this feature more generally available, and makes is simpler for us
>> to have a global setting for parallelisation. (The funny thing is that this
>> is looking more like Option #2!)
>>
>>  *So native compilation would happen in parallel whenever --parallel
>> and/or --parallel-threads is used*. As Adam suggested, we should really
>> separate these 2 options so that --parallel is a separate option to enable
>> parallel project execution, while parallel-threads is a general purpose
>> setting that defaults to a reasonable value.
>> (Currently StartParameter#getParallelThreadCount defaults to zero if
>> neither --parallel or --parallel-threads is specified).
>>
>>>
>>>    - How can we test this new feature? The only way I can think of
>>>    right now is to compile 2 file with maximumNumberOfCompileFork set to 1 
>>> and
>>>    a second time with the option set to 2 and compare the execution time. 
>>> This
>>>    heavily depend on timing which will probably be non deterministic.
>>>
>>>   No, timing-sensitive tests are not the way to go. We could certainly
>> unit test the AsyncExecAction stuff, and also integration test with a few
>> 'sleep 1 second' actions and ensure that they don't take much more than 1
>> second in total. I guess we could integration test parallel native
>> compilation by using a 'sleep exe' in place of the actual compiler... I'll
>> think about this a little more.
>>
>>  Thanks for pushing to get this done. You're right that we really need
>> parallel compilation to be a serious C++ build tool.
>>
>>  Daz
>>
>>>
>>>
>>>
>>>
>>>  On Sun, Jun 29, 2014 at 11:02 PM, Adam Murdoch <
>>> adam.murd...@gradleware.com> wrote:
>>>
>>>>
>>>>   On 30 Jun 2014, at 12:21 pm, Daniel Lacasse <
>>>> daniel.lacass...@gmail.com> wrote:
>>>>
>>>>  Thanks Adam for your insight. I agree that option #2 would probably
>>>> be a really good start. Unfortunately, for someone who is pretty new to the
>>>> code base, I would rather start with #1 by exposing n on the compile task,
>>>> set it to one by default and have the logic there to fork compiler tag. I
>>>> would stress that it's a temporary fix and it will be stream line later
>>>> with #2 and #3. It would also be much easier for me to contribute #1 in a
>>>> reasonable time, say for 2.1, and take more time to implement a full
>>>> solution. How does that sound?
>>>>
>>>>
>>>>   Sounds good to me.
>>>>
>>>>
>>>>  If you strongly prefer #2 as a start point, could you point me to a
>>>> couple place where changes should be applied so I start looking into it?
>>>>
>>>>
>>>>  On Sun, Jun 29, 2014 at 9:25 PM, Adam Murdoch <
>>>> adam.murd...@gradleware.com> wrote:
>>>>
>>>>>
>>>>>   On 30 Jun 2014, at 1:51 am, Daniel Lacasse <
>>>>> daniel.lacass...@gmail.com> wrote:
>>>>>
>>>>>   I have been using the native extension for Gradle inside an actual
>>>>> project for a couple months. The biggest limitation I'm seeing is the
>>>>> inflexibility of the compile task when compared to other build tool in the
>>>>> industry. The --parallel switch works great for concurrent execution of
>>>>> tasks. When it comes to the compile task, all files are compiled one after
>>>>> the other. The native compiler are quite slow especially when it comes to
>>>>> compiling C++ templates. As a comparison, my dev box is mostly idle while
>>>>> compiling with Gradle as oppose to a fairly important load when compiling
>>>>> Visual Studio.
>>>>>
>>>>>  The main use case of this feature is the speed up of the compilation
>>>>> process for the native extension. To highlight how this feature is
>>>>> important, I will point out that some company where I previously worked at
>>>>> use system like Incredibuild to perform parallel distributed compilation.
>>>>> Even with such system, the compilation was still pretty time consuming. In
>>>>> it's present form, Gradle is not suitable in term of speed for those
>>>>> scenario. I talked to a couple Gradleware engineers during Gradle Summit
>>>>> 2014 and some insane features are planed to address this problem.
>>>>> Unfortunately, a quicker solution is needed in order to speed up the
>>>>> adoption of Gradle as a native build tool. I also want this feature to be
>>>>> in accordance to the long term Gradle road map.
>>>>>
>>>>>  I would like to start the discussion for contributing this into
>>>>> Gradle.
>>>>>
>>>>>
>>>>>   That would be great.
>>>>>
>>>>>   From my limiting knowledge of Gradle here are a couple open issues
>>>>> I have. I hope some brilliant minds from Gradleware can share there wisdom
>>>>> on where to move forward with this feature.
>>>>>
>>>>>  Open issues
>>>>>   - What is the current road map for such feature.
>>>>>
>>>>>
>>>>>   I think there are 3 potential steps we could take:
>>>>>
>>>>>  1. The compilation tasks do something specific, where they fork n
>>>>> concurrent compilations, and n is just some setting on the compilation
>>>>> tasks.
>>>>>
>>>>>  2. Then, we introduce some general service that tasks can use for
>>>>> coordinating concurrent work. This would be integrated with
>>>>> —parallel-threads. The compilation tasks, the test tasks, and the task
>>>>> executor would all use this service to ensure that an appropriate amount 
>>>>> of
>>>>> concurrent work happens at any given time. This would be a public service
>>>>> that any task implementation could use.
>>>>>
>>>>>  3. Then later, we add more capabilities to this so that the work can
>>>>> treated more like tasks - with their own up-to-date checks, dependencies,
>>>>> and so on.
>>>>>
>>>>>  We could start with #1 and later extract #2, or we could jump
>>>>> straight to #2. In some ways, it might be nice to start with #2.
>>>>>
>>>>>
>>>>>      - This could also be used in any language which require
>>>>> compilation such as Java.
>>>>>     - Allowing custom implementation of this feature could allow a
>>>>> company to plug Gradle in there current Incredibuild infrastructure or any
>>>>> other distributed framework.
>>>>>   - How this feature fits with the --parallel flag?
>>>>>
>>>>>
>>>>>   For every build, there should be two settings that you can tweak:
>>>>>
>>>>>  1. The maximum amount of parallel work that can be performed by
>>>>> Gradle.
>>>>>  2. Whether or not tasks should be executed in parallel.
>>>>>
>>>>>  That is, Gradle will be able to do stuff in parallel even if the
>>>>> tasks aren’t executed concurrently. It already does this with test
>>>>> execution.
>>>>>
>>>>>  I would change —parallel-threads to control the maximum work but to
>>>>> not enable parallel task execution. It would default to some ‘reasonable’
>>>>> value - the number of cores, say, at least to start with.
>>>>>
>>>>>
>>>>>    - How the number of parallel compilation unit will be configure
>>>>> aka number of files that can be compiled in parallel?
>>>>>
>>>>>
>>>>>   As above.
>>>>>
>>>>>    - Should this feature be always on by default or have a toggle
>>>>> flag?
>>>>>
>>>>>
>>>>>  Always on, I think. Why would you turn it off?
>>>>>
>>>>>
>>>>> --
>>>>>  Adam Murdoch
>>>>> Gradle Co-founder
>>>>> http://www.gradle.org
>>>>> CTO Gradleware Inc. - Gradle Training, Support, Consulting
>>>>> http://www.gradleware.com
>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>> --
>>>> Daniel
>>>>
>>>>
>>>>
>>>> --
>>>>  Adam Murdoch
>>>> Gradle Co-founder
>>>> http://www.gradle.org
>>>> CTO Gradleware Inc. - Gradle Training, Support, Consulting
>>>> http://www.gradleware.com
>>>>
>>>>
>>>>
>>>>
>>>
>>>
>>>   --
>>> Daniel
>>>
>>
>>
>>
>> --
>>  Darrell (Daz) DeBoer
>>  Principal Software Engineer, *Gradleware <http://gradleware.com>*
>>
>>  Join us for Gradle Summit 2014, June 12th and 13th in Santa Clara, CA:
>> http://www.gradlesummit.com
>>
>>
>
>
> --
>  Darrell (Daz) DeBoer
>  Principal Software Engineer, *Gradleware <http://gradleware.com>*
>
>  Join us for Gradle Summit 2014, June 12th and 13th in Santa Clara, CA:
> http://www.gradlesummit.com
>
>


-- 
Darrell (Daz) DeBoer
Principal Software Engineer, *Gradleware <http://gradleware.com>*

Join us for Gradle Summit 2014, June 12th and 13th in Santa Clara, CA:
http://www.gradlesummit.com

Reply via email to