@@ -161,10 +161,11 @@ private[yarn] class YarnAllocator(
161
161
new LocalityPreferredContainerPlacementStrategy (sparkConf, conf, resource, resolver)
162
162
163
163
// The total number of numa node
164
- private [yarn] val totalNumaNumber = 2
165
- // Mapping from host to executor counter, we use the counter with a round-robin mode to
166
- // determine the numa node id that the executor should bind.
167
- private [yarn] val hostToNuma = new mutable.HashMap [String , Int ]()
164
+ private [yarn] val totalNumaNumber = sparkConf.get(SPARK_YARN_NUMA_NUMBER )
165
+ // Mapping from host to executor counter
166
+ private [yarn] case class NumaInfo (cotainer2numa : mutable.HashMap [String , Int ], numaUsed : Array [Int ])
167
+
168
+ private [yarn] val hostToNumaInfo = new mutable.HashMap [String , NumaInfo ]()
168
169
169
170
/**
170
171
* Use a different clock for YarnAllocator. This is mainly used for testing.
@@ -501,13 +502,19 @@ private[yarn] class YarnAllocator(
501
502
for (container <- containersToUse) {
502
503
executorIdCounter += 1
503
504
val executorHostname = container.getNodeId.getHost
504
- // Setting the numa id that the executor should binding. Just round robin from 0 to
505
- // totalNumaNumber for each host.
506
- // TODO: This is very ugly, however this is should be processed in resource
507
- // manager(such as yarn).
508
- val preSize = hostToNuma.getOrElseUpdate(executorHostname, 0 )
509
- val numaNodeId = (preSize % totalNumaNumber).toString
510
- hostToNuma.put(executorHostname, preSize + 1 )
505
+ // Setting the numa id that the executor should binding.
506
+ // new numaid binding method
507
+ val numaInfo = hostToNumaInfo.getOrElseUpdate(executorHostname,
508
+ NumaInfo (new mutable.HashMap [String , Int ], new Array [Int ](totalNumaNumber)))
509
+ val minUsed = numaInfo.numaUsed.min
510
+ val newNumaNodeId = numaInfo.numaUsed.indexOf(minUsed)
511
+ numaInfo.cotainer2numa.put(container.getId.toString, newNumaNodeId)
512
+ numaInfo.numaUsed(newNumaNodeId) += 1
513
+
514
+ val numaNodeId = newNumaNodeId.toString
515
+ logInfo(s " numaNodeId: $numaNodeId on host $executorHostname, " +
516
+ " container: " + container.getId.toString +
517
+ " , minUsed: " + minUsed)
511
518
512
519
val containerId = container.getId
513
520
val executorId = executorIdCounter.toString
@@ -598,6 +605,17 @@ private[yarn] class YarnAllocator(
598
605
// there are some exit status' we shouldn't necessarily count against us, but for
599
606
// now I think its ok as none of the containers are expected to exit.
600
607
val exitStatus = completedContainer.getExitStatus
608
+
609
+ var numaNodeId = - 1
610
+ val hostName = hostOpt.getOrElse(" nohost" )
611
+ val numaInfoOp = hostToNumaInfo.get(hostName)
612
+ numaInfoOp match {
613
+ case Some (numaInfo) =>
614
+ numaNodeId = numaInfo.cotainer2numa.get(containerId.toString).getOrElse(- 1 )
615
+ if (- 1 != numaNodeId) numaInfo.numaUsed(numaNodeId) -= 1
616
+ case _ => numaNodeId = - 1
617
+ }
618
+
601
619
val (exitCausedByApp, containerExitReason) = exitStatus match {
602
620
case ContainerExitStatus .SUCCESS =>
603
621
(false , s " Executor for container $containerId exited because of a YARN event (e.g., " +
@@ -621,7 +639,9 @@ private[yarn] class YarnAllocator(
621
639
failedExecutorsTimeStamps.enqueue(clock.getTimeMillis())
622
640
(true , " Container marked as failed: " + containerId + onHostStr +
623
641
" . Exit status: " + completedContainer.getExitStatus +
624
- " . Diagnostics: " + completedContainer.getDiagnostics)
642
+ " . Diagnostics: " + completedContainer.getDiagnostics +
643
+ " . numaNodeId: " + numaNodeId +
644
+ " . hostName: " + hostName)
625
645
626
646
}
627
647
if (exitCausedByApp) {
0 commit comments