@@ -27,10 +27,13 @@ import dotty.tools.dotc.core.Symbols
27
27
28
28
object Driver {
29
29
@ sharable lazy val executor =
30
- // fixed pool of 8 threads, because we have 8 cores
31
- val pool = java.util.concurrent.Executors .newFixedThreadPool(8 ).nn
30
+ // TODO: systemParallelism may change over time - is it possible to update the pool size?
31
+ val pool = java.util.concurrent.Executors .newFixedThreadPool(systemParallelism() ).nn
32
32
sys.addShutdownHook(pool.shutdown())
33
33
ExecutionContext .fromExecutor(pool)
34
+
35
+ /** 1 less than the system's own processor count (minimum 1) */
36
+ def systemParallelism () = math.max(1 , Runtime .getRuntime().nn.availableProcessors() - 1 )
34
37
}
35
38
36
39
/** Run the Dotty compiler.
@@ -59,12 +62,13 @@ class Driver {
59
62
val absParallelism = math.abs(maxParallelism)
60
63
val isParallel = maxParallelism >= 0
61
64
val parallelism =
62
- val ceiling = math.max( 1 , Runtime .getRuntime().nn.availableProcessors() - 1 )
65
+ val ceiling = Driver .systemParallelism( )
63
66
if absParallelism > 0 then math.min(absParallelism, ceiling)
64
67
else ceiling
65
68
66
69
// NOTE: sbt will delete this potentially as soon as you call `apiPhaseCompleted`
67
70
val pickleWriteOutput = ictx.settings.YearlyTastyOutput .valueIn(ictx.settingsState)
71
+ val profileDestination = ictx.settings.YprofileDestination .valueIn(ictx.settingsState)
68
72
69
73
val pickleWriteSource =
70
74
pickleWriteOutput.underlyingSource match
@@ -96,7 +100,14 @@ class Driver {
96
100
inContext(firstPassCtx):
97
101
doCompile(newCompiler, files)
98
102
99
- def secondPassCtx (group : List [AbstractFile ], promise : scala.concurrent.Promise [Unit ]): Context =
103
+ def secondPassCtx (id : Int , group : List [AbstractFile ], promise : scala.concurrent.Promise [Unit ]): Context =
104
+ val profileDestination0 =
105
+ if profileDestination.nonEmpty then
106
+ val ext = dotty.tools.io.Path .fileExtension(profileDestination)
107
+ val filename = dotty.tools.io.Path .fileName(profileDestination)
108
+ s " $filename-worker- $id${if ext.isEmpty then " " else s " . $ext" }"
109
+ else profileDestination
110
+
100
111
val baseCtx = initCtx.fresh
101
112
.setSettings(ictx.settingsState) // copy over the classpath arguments also
102
113
.setSetting(ictx.settings.YsecondPass , true )
@@ -105,6 +116,9 @@ class Driver {
105
116
.setDepsFinishPromise(promise)
106
117
.setReporter(if isParallel then new StoreReporter (ictx.reporter) else ictx.reporter)
107
118
119
+ if profileDestination0.nonEmpty then
120
+ baseCtx.setSetting(ictx.settings.YprofileDestination , profileDestination0)
121
+
108
122
// if ictx.settings.YoutlineClasspath.valueIn(ictx.settingsState).isEmpty then
109
123
// baseCtx.setSetting(baseCtx.settings.YoutlineClasspath, pickleWriteAsClasspath)
110
124
val fileNames : Array [String ] =
@@ -160,12 +174,13 @@ class Driver {
160
174
report.echo(s " Compiling $compilers groups of files ${if isParallel then " in parallel" else " sequentially" }" )(using firstPassCtx)
161
175
162
176
def compileEager (
177
+ id : Int ,
163
178
promise : Promise [Unit ],
164
179
fileGroup : List [AbstractFile ]
165
180
): Reporter = {
166
181
if ctx.settings.verbose.value then
167
182
report.echo(" #Compiling: " + fileGroup.take(3 ).mkString(" " , " , " , " ..." ))
168
- val secondCtx = secondPassCtx(fileGroup, promise)
183
+ val secondCtx = secondPassCtx(id, fileGroup, promise)
169
184
val reporter = inContext(secondCtx):
170
185
doCompile(newCompiler, fileGroup) // second pass
171
186
if ! secondCtx.reporter.hasErrors then
@@ -176,22 +191,26 @@ class Driver {
176
191
}
177
192
178
193
def compileFuture (
194
+ id : Int ,
179
195
promise : Promise [Unit ],
180
196
fileGroup : List [AbstractFile ]
181
197
)(using ExecutionContext ): Future [Reporter ] =
182
198
Future {
183
199
// println("#Compiling: " + fileGroup.mkString(" "))
184
- val secondCtx = secondPassCtx(fileGroup, promise)
200
+ val secondCtx = secondPassCtx(id, fileGroup, promise)
185
201
val reporter = inContext(secondCtx):
186
202
doCompile(newCompiler, fileGroup) // second pass
187
203
// println("#Done: " + fileGroup.mkString(" "))
188
204
reporter
189
205
}
190
206
207
+ def fileGroupIds = LazyList .iterate(0 )(_ + 1 ).take(compilers)
208
+ def taggedGroups = fileGroupIds.lazyZip(promises).lazyZip(fileGroups)
209
+
191
210
if isParallel then
192
211
// val executor = java.util.concurrent.Executors.newFixedThreadPool(compilers).nn
193
212
given ec : ExecutionContext = Driver .executor // ExecutionContext.fromExecutor(executor)
194
- val futureReporters = Future .sequence(promises.lazyZip(fileGroups) .map(compileFuture)).andThen {
213
+ val futureReporters = Future .sequence(taggedGroups .map(compileFuture)).andThen {
195
214
case Success (reporters) =>
196
215
reporters.foreach(_.flush()(using firstPassCtx))
197
216
case Failure (ex) =>
@@ -201,7 +220,7 @@ class Driver {
201
220
Await .ready(futureReporters, Duration .Inf )
202
221
// executor.shutdown()
203
222
else
204
- promises.lazyZip(fileGroups) .map(compileEager)
223
+ taggedGroups .map(compileEager)
205
224
firstPassCtx.reporter
206
225
else
207
226
ictx.withIncCallback(_.dependencyPhaseCompleted()) // may be just java files compiled
0 commit comments