@@ -998,9 +998,14 @@ struct Diagnostic {
998
998
999
999
#[ derive( PartialEq , Clone , Copy , Debug ) ]
1000
1000
enum MainThreadWorkerState {
1001
+ /// Doing nothing.
1001
1002
Idle ,
1003
+
1004
+ /// Doing codegen, i.e. MIR-to-LLVM-IR conversion.
1002
1005
Codegenning ,
1003
- LLVMing ,
1006
+
1007
+ /// Idle, but lending the compiler process's Token to an LLVM thread so it can do useful work.
1008
+ Lending ,
1004
1009
}
1005
1010
1006
1011
fn start_executing_work < B : ExtraBackendMethods > (
@@ -1296,7 +1301,13 @@ fn start_executing_work<B: ExtraBackendMethods>(
1296
1301
let mut tokens = Vec :: new ( ) ;
1297
1302
1298
1303
let mut main_thread_worker_state = MainThreadWorkerState :: Idle ;
1299
- let mut running = 0 ;
1304
+
1305
+ // How many LLVM worker threads are running while holding a Token. This
1306
+ // *excludes* the LLVM worker thread that the main thread is lending a
1307
+ // Token to (when the main thread is in the `Lending` state).
1308
+ // In other words, the number of LLVM threads is actually equal to
1309
+ // `running + if main_thread_worker_state == Lending { 1 } else { 0 }`.
1310
+ let mut running_with_own_token = 0 ;
1300
1311
1301
1312
let prof = & cgcx. prof ;
1302
1313
let mut llvm_start_time: Option < VerboseTimingGuard < ' _ > > = None ;
@@ -1307,8 +1318,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
1307
1318
// only apply if codegen hasn't been aborted as they represent pending
1308
1319
// work to be done.
1309
1320
while codegen_state == Ongoing
1310
- || running > 0
1311
- || main_thread_worker_state == MainThreadWorkerState :: LLVMing
1321
+ || running_with_own_token > 0
1322
+ || main_thread_worker_state == MainThreadWorkerState :: Lending
1312
1323
|| ( codegen_state == Completed
1313
1324
&& !( work_items. is_empty ( )
1314
1325
&& needs_fat_lto. is_empty ( )
@@ -1323,13 +1334,14 @@ fn start_executing_work<B: ExtraBackendMethods>(
1323
1334
if main_thread_worker_state == MainThreadWorkerState :: Idle {
1324
1335
// Compute the number of workers that will be running once we've taken as many
1325
1336
// items from the work queue as we can, plus one for the main thread. It's not
1326
- // critically important that we use this instead of just `running`, but it
1327
- // prevents the `queue_full_enough` heuristic from fluctuating just because a
1328
- // worker finished up and we decreased the `running` count, even though we're
1329
- // just going to increase it right after this when we put a new worker to work.
1330
- let extra_tokens = tokens. len ( ) . checked_sub ( running) . unwrap ( ) ;
1337
+ // critically important that we use this instead of just
1338
+ // `running_with_own_token`, but it prevents the `queue_full_enough` heuristic
1339
+ // from fluctuating just because a worker finished up and we decreased the
1340
+ // `running_with_own_token` count, even though we're just going to increase it
1341
+ // right after this when we put a new worker to work.
1342
+ let extra_tokens = tokens. len ( ) . checked_sub ( running_with_own_token) . unwrap ( ) ;
1331
1343
let additional_running = std:: cmp:: min ( extra_tokens, work_items. len ( ) ) ;
1332
- let anticipated_running = running + additional_running + 1 ;
1344
+ let anticipated_running = running_with_own_token + additional_running + 1 ;
1333
1345
1334
1346
if !queue_full_enough ( work_items. len ( ) , anticipated_running) {
1335
1347
// The queue is not full enough, process more codegen units:
@@ -1352,7 +1364,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
1352
1364
cgcx. config ( item. module_kind ( ) ) ,
1353
1365
& mut llvm_start_time,
1354
1366
) ;
1355
- main_thread_worker_state = MainThreadWorkerState :: LLVMing ;
1367
+ main_thread_worker_state = MainThreadWorkerState :: Lending ;
1356
1368
spawn_work ( cgcx, item) ;
1357
1369
}
1358
1370
}
@@ -1363,7 +1375,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
1363
1375
// going to LTO and then push a bunch of work items onto our
1364
1376
// queue to do LTO
1365
1377
if work_items. is_empty ( )
1366
- && running == 0
1378
+ && running_with_own_token == 0
1367
1379
&& main_thread_worker_state == MainThreadWorkerState :: Idle
1368
1380
{
1369
1381
assert ! ( !started_lto) ;
@@ -1401,7 +1413,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
1401
1413
cgcx. config ( item. module_kind ( ) ) ,
1402
1414
& mut llvm_start_time,
1403
1415
) ;
1404
- main_thread_worker_state = MainThreadWorkerState :: LLVMing ;
1416
+ main_thread_worker_state = MainThreadWorkerState :: Lending ;
1405
1417
spawn_work ( cgcx, item) ;
1406
1418
} else {
1407
1419
// There is no unstarted work, so let the main thread
@@ -1410,16 +1422,16 @@ fn start_executing_work<B: ExtraBackendMethods>(
1410
1422
// We reduce the `running` counter by one. The
1411
1423
// `tokens.truncate()` below will take care of
1412
1424
// giving the Token back.
1413
- debug_assert ! ( running > 0 ) ;
1414
- running -= 1 ;
1415
- main_thread_worker_state = MainThreadWorkerState :: LLVMing ;
1425
+ debug_assert ! ( running_with_own_token > 0 ) ;
1426
+ running_with_own_token -= 1 ;
1427
+ main_thread_worker_state = MainThreadWorkerState :: Lending ;
1416
1428
}
1417
1429
}
1418
1430
MainThreadWorkerState :: Codegenning => bug ! (
1419
1431
"codegen worker should not be codegenning after \
1420
1432
codegen was already completed"
1421
1433
) ,
1422
- MainThreadWorkerState :: LLVMing => {
1434
+ MainThreadWorkerState :: Lending => {
1423
1435
// Already making good use of that token
1424
1436
}
1425
1437
}
@@ -1431,7 +1443,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
1431
1443
1432
1444
// Spin up what work we can, only doing this while we've got available
1433
1445
// parallelism slots and work left to spawn.
1434
- while codegen_state != Aborted && !work_items. is_empty ( ) && running < tokens. len ( ) {
1446
+ while codegen_state != Aborted
1447
+ && !work_items. is_empty ( )
1448
+ && running_with_own_token < tokens. len ( )
1449
+ {
1435
1450
let ( item, _) = work_items. pop ( ) . unwrap ( ) ;
1436
1451
1437
1452
maybe_start_llvm_timer ( prof, cgcx. config ( item. module_kind ( ) ) , & mut llvm_start_time) ;
@@ -1440,22 +1455,22 @@ fn start_executing_work<B: ExtraBackendMethods>(
1440
1455
CodegenContext { worker : get_worker_id ( & mut free_worker_ids) , ..cgcx. clone ( ) } ;
1441
1456
1442
1457
spawn_work ( cgcx, item) ;
1443
- running += 1 ;
1458
+ running_with_own_token += 1 ;
1444
1459
}
1445
1460
1446
- // Relinquish accidentally acquired extra tokens
1447
- tokens. truncate ( running ) ;
1461
+ // Relinquish accidentally acquired extra tokens.
1462
+ tokens. truncate ( running_with_own_token ) ;
1448
1463
1449
1464
// If a thread exits successfully then we drop a token associated
1450
- // with that worker and update our `running ` count. We may later
1451
- // re-acquire a token to continue running more work. We may also not
1452
- // actually drop a token here if the worker was running with an
1453
- // "ephemeral token"
1465
+ // with that worker and update our `running_with_own_token ` count.
1466
+ // We may later re-acquire a token to continue running more work.
1467
+ // We may also not actually drop a token here if the worker was
1468
+ // running with an "ephemeral token".
1454
1469
let mut free_worker = |worker_id| {
1455
- if main_thread_worker_state == MainThreadWorkerState :: LLVMing {
1470
+ if main_thread_worker_state == MainThreadWorkerState :: Lending {
1456
1471
main_thread_worker_state = MainThreadWorkerState :: Idle ;
1457
1472
} else {
1458
- running -= 1 ;
1473
+ running_with_own_token -= 1 ;
1459
1474
}
1460
1475
1461
1476
free_worker_ids. push ( worker_id) ;
@@ -1471,13 +1486,13 @@ fn start_executing_work<B: ExtraBackendMethods>(
1471
1486
Ok ( token) => {
1472
1487
tokens. push ( token) ;
1473
1488
1474
- if main_thread_worker_state == MainThreadWorkerState :: LLVMing {
1489
+ if main_thread_worker_state == MainThreadWorkerState :: Lending {
1475
1490
// If the main thread token is used for LLVM work
1476
1491
// at the moment, we turn that thread into a regular
1477
1492
// LLVM worker thread, so the main thread is free
1478
1493
// to react to codegen demand.
1479
1494
main_thread_worker_state = MainThreadWorkerState :: Idle ;
1480
- running += 1 ;
1495
+ running_with_own_token += 1 ;
1481
1496
}
1482
1497
}
1483
1498
Err ( e) => {
@@ -1523,7 +1538,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
1523
1538
// to exit as soon as possible, but we want to make sure all
1524
1539
// existing work has finished. Flag codegen as being done, and
1525
1540
// then conditions above will ensure no more work is spawned but
1526
- // we'll keep executing this loop until `running` hits 0.
1541
+ // we'll keep executing this loop until `running_with_own_token`
1542
+ // hits 0.
1527
1543
Message :: CodegenAborted => {
1528
1544
codegen_state = Aborted ;
1529
1545
}
0 commit comments