[prev in list] [next in list] [prev in thread] [next in thread] 

List:       hadoop-commits
Subject:    [hadoop] branch trunk updated: YARN-11196. NUMA support in DefaultContainerExecutor  (#4742)
From:       prabhujoseph () apache ! org
Date:       2022-08-30 5:10:00
Message-ID: 166183620066.2105694.435130189919858146 () gitbox2-he-fi ! apache ! org
[Download RAW message or body]

This is an automated email from the ASF dual-hosted git repository.

prabhujoseph pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/hadoop.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 2c050157162 YARN-11196. NUMA support in DefaultContainerExecutor  (#4742)
2c050157162 is described below

commit 2c0501571626b8c23718d83fd53b44e308eb6628
Author: Samrat <decorde.apex@gmail.com>
AuthorDate: Tue Aug 30 10:39:41 2022 +0530

    YARN-11196. NUMA support in DefaultContainerExecutor  (#4742)
---
 .../nodemanager/DefaultContainerExecutor.java      | 155 ++++++++++++++-
 .../WindowsSecureContainerExecutor.java            |   4 +-
 .../resources/numa/NumaResourceAllocator.java      |   2 +-
 .../nodemanager/TestDefaultContainerExecutor.java  | 221 ++++++++++++++++++++-
 .../resources/numa/TestNumaResourceAllocator.java  |   2 +-
 5 files changed, 369 insertions(+), 15 deletions(-)

diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nod \
emanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java \
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/sr \
c/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java \
                index 7d18016d95a..705ef88dee3 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanage \
r/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java
                
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanage \
r/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java
 @@ -20,6 +20,7 @@ package org.apache.hadoop.yarn.server.nodemanager;
 
 import static org.apache.hadoop.fs.CreateFlag.CREATE;
 import static org.apache.hadoop.fs.CreateFlag.OVERWRITE;
+import static org.apache.hadoop.yarn.conf.YarnConfiguration.numaAwarenessEnabled;
 
 import org.apache.hadoop.classification.VisibleForTesting;
 import java.io.DataOutputStream;
@@ -28,12 +29,13 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintStream;
 import java.net.InetSocketAddress;
-import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+
 import org.apache.commons.lang3.RandomUtils;
 import org.apache.hadoop.classification.InterfaceAudience.Private;
 import org.apache.hadoop.fs.FileContext;
@@ -51,14 +53,19 @@ import org.apache.hadoop.yarn.api.records.ContainerId;
 import org.apache.hadoop.yarn.api.records.Resource;
 import org.apache.hadoop.yarn.conf.YarnConfiguration;
 import org.apache.hadoop.yarn.exceptions.ConfigurationException;
+import org.apache.hadoop.yarn.exceptions.YarnException;
 import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider;
 import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
  import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerDiagnosticsUpdateEvent;
  import org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch;
 +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.ResourceHandlerException;
 +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.numa.NumaResourceAllocation;
 +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.numa.NumaResourceAllocator;
  import org.apache.hadoop.yarn.server.nodemanager.containermanager.localizer.ContainerLocalizer;
  import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.ContainerExecutionException;
  import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerExecContext;
 import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerLivenessContext;
+import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerReacquisitionContext;
  import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerReapContext;
 import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerSignalContext;
 import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerStartContext;
@@ -86,6 +93,10 @@ public class DefaultContainerExecutor extends ContainerExecutor {
 
   private String logDirPermissions = null;
 
+  private NumaResourceAllocator numaResourceAllocator;
+
+
+  private String numactl;
   /**
    * Default constructor for use in testing.
    */
@@ -137,7 +148,19 @@ public class DefaultContainerExecutor extends ContainerExecutor \
{  
   @Override
   public void init(Context nmContext) throws IOException {
-    // nothing to do or verify here
+    if(numaAwarenessEnabled(getConf())) {
+      numaResourceAllocator = new NumaResourceAllocator(nmContext);
+      numactl = this.getConf().get(YarnConfiguration.NM_NUMA_AWARENESS_NUMACTL_CMD,
+              YarnConfiguration.DEFAULT_NM_NUMA_AWARENESS_NUMACTL_CMD);
+      try {
+        numaResourceAllocator.init(this.getConf());
+        LOG.info("NUMA resources allocation is enabled in DefaultContainer \
Executor," + +                " Successfully initialized NUMA resources allocator.");
+      } catch (YarnException e) {
+        LOG.warn("Improper NUMA configuration provided.", e);
+        throw new IOException("Failed to initialize configured numa subsystem!");
+      }
+    }
   }
 
   @Override
@@ -300,11 +323,28 @@ public class DefaultContainerExecutor extends ContainerExecutor \
{  setScriptExecutable(launchDst, user);
       setScriptExecutable(sb.getWrapperScriptPath(), user);
 
+      // adding numa commands based on configuration
+      String[] numaCommands = new String[]{};
+
+      if (numaResourceAllocator != null) {
+        try {
+          NumaResourceAllocation numaResourceAllocation =
+                  numaResourceAllocator.allocateNumaNodes(container);
+          if (numaResourceAllocation != null) {
+            numaCommands = getNumaCommands(numaResourceAllocation);
+          }
+        } catch (ResourceHandlerException e) {
+          LOG.error("NumaResource Allocation failed!", e);
+          throw new IOException("NumaResource Allocation Error!", e);
+        }
+      }
+
       shExec = buildCommandExecutor(sb.getWrapperScriptPath().toString(),
-          containerIdStr, user, pidFile, container.getResource(),
-          new File(containerWorkDir.toUri().getPath()),
-          container.getLaunchContext().getEnvironment());
-      
+              containerIdStr, user, pidFile, container.getResource(),
+              new File(containerWorkDir.toUri().getPath()),
+              container.getLaunchContext().getEnvironment(),
+              numaCommands);
+
       if (isContainerActive(containerId)) {
         shExec.execute();
       } else {
@@ -350,6 +390,7 @@ public class DefaultContainerExecutor extends ContainerExecutor {
       return exitCode;
     } finally {
       if (shExec != null) shExec.close();
+      postComplete(containerId);
     }
     return 0;
   }
@@ -372,16 +413,22 @@ public class DefaultContainerExecutor extends ContainerExecutor \
                {
    * as the current working directory for the command. If null,
    * the current working directory is not modified.
    * @param environment the container environment
+   * @param numaCommands list of prefix numa commands
    * @return the new {@link ShellCommandExecutor}
    * @see ShellCommandExecutor
    */
-  protected CommandExecutor buildCommandExecutor(String wrapperScriptPath, 
-      String containerIdStr, String user, Path pidFile, Resource resource,
-      File workDir, Map<String, String> environment) {
-    
+  protected CommandExecutor buildCommandExecutor(String wrapperScriptPath,
+                            String containerIdStr, String user, Path pidFile, \
Resource resource, +                            File workDir, Map<String, String> \
environment, String[] numaCommands) { +
     String[] command = getRunCommand(wrapperScriptPath,
         containerIdStr, user, pidFile, this.getConf(), resource);
 
+    // check if numa commands are passed and append it as prefix commands
+    if(numaCommands != null && numaCommands.length!=0) {
+      command = concatStringCommands(numaCommands, command);
+    }
+
     LOG.info("launchContainer: {}", Arrays.toString(command));
     return new ShellCommandExecutor(
         command,
@@ -1040,4 +1087,92 @@ public class DefaultContainerExecutor extends \
ContainerExecutor {  String appId, String spec) throws IOException {
     throw new ServiceStateException("Implementation unavailable");
   }
+
+  @Override
+  public int reacquireContainer(ContainerReacquisitionContext ctx)
+          throws IOException, InterruptedException {
+    try {
+      if (numaResourceAllocator != null) {
+        numaResourceAllocator.recoverNumaResource(ctx.getContainerId());
+      }
+      return super.reacquireContainer(ctx);
+    } finally {
+      postComplete(ctx.getContainerId());
+    }
+  }
+
+  /**
+   * clean up and release of resources.
+   *
+   * @param containerId containerId of running container
+   */
+  public void postComplete(final ContainerId containerId) {
+    if (numaResourceAllocator != null) {
+      try {
+        numaResourceAllocator.releaseNumaResource(containerId);
+      } catch (ResourceHandlerException e) {
+        LOG.warn("NumaResource release failed for " +
+                "containerId: {}. Exception: ", containerId, e);
+      }
+    }
+  }
+
+  /**
+   * @param resourceAllocation NonNull NumaResourceAllocation object reference
+   * @return Array of numa specific commands
+   */
+  String[] getNumaCommands(NumaResourceAllocation resourceAllocation) {
+    String[] numaCommand = new String[3];
+    numaCommand[0] = numactl;
+    numaCommand[1] = "--interleave=" + String.join(",", \
resourceAllocation.getMemNodes()); +    numaCommand[2] = "--cpunodebind=" + \
String.join(",", resourceAllocation.getCpuNodes()); +    return numaCommand;
+
+  }
+
+  /**
+   * @param firstStringArray  Array of String
+   * @param secondStringArray Array of String
+   * @return combined array of string where first elements are from firstStringArray
+   * and later are the elements from secondStringArray
+   */
+  String[] concatStringCommands(String[] firstStringArray, String[] \
secondStringArray) { +
+    if(firstStringArray == null && secondStringArray == null) {
+      return secondStringArray;
+    }
+
+    else if(firstStringArray == null || firstStringArray.length == 0) {
+      return secondStringArray;
+    }
+
+    else if(secondStringArray == null || secondStringArray.length == 0){
+      return firstStringArray;
+    }
+
+    int len = firstStringArray.length + secondStringArray.length;
+
+    String[] ret = new String[len];
+    int idx = 0;
+    for (String s : firstStringArray) {
+      ret[idx] = s;
+      idx++;
+    }
+    for (String s : secondStringArray) {
+      ret[idx] = s;
+      idx++;
+    }
+    return ret;
+  }
+
+  @VisibleForTesting
+  public void setNumaResourceAllocator(NumaResourceAllocator numaResourceAllocator) \
{ +    this.numaResourceAllocator = numaResourceAllocator;
+  }
+
+  @VisibleForTesting
+  public void setNumactl(String numactl) {
+    this.numactl = numactl;
+  }
+
 }
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nod \
emanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/WindowsSecureContainerExecutor.java \
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/sr \
c/main/java/org/apache/hadoop/yarn/server/nodemanager/WindowsSecureContainerExecutor.java
 index 6132e579ef9..9d57f8fff4f 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanage \
r/src/main/java/org/apache/hadoop/yarn/server/nodemanager/WindowsSecureContainerExecutor.java
                
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanage \
r/src/main/java/org/apache/hadoop/yarn/server/nodemanager/WindowsSecureContainerExecutor.java
 @@ -718,10 +718,10 @@ public class WindowsSecureContainerExecutor extends \
DefaultContainerExecutor {  @Override
   protected CommandExecutor buildCommandExecutor(String wrapperScriptPath,
       String containerIdStr, String userName, Path pidFile, Resource resource,
-      File wordDir, Map<String, String> environment) {
+      File wordDir, Map<String, String> environment, String[] numaCommands) {
      return new WintuilsProcessStubExecutor(
          wordDir.toString(),
-         containerIdStr, userName, pidFile.toString(), 
+         containerIdStr, userName, pidFile.toString(),
          "cmd /c " + wrapperScriptPath);
    }
    
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nod \
emanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/numa/NumaResourceAllocator.java \
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/sr \
c/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/numa/NumaResourceAllocator.java
 index 48d5bfe95a2..2deaf16880a 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanage \
r/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/numa/NumaResourceAllocator.java
                
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanage \
r/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/numa/NumaResourceAllocator.java
 @@ -143,7 +143,7 @@ public class NumaResourceAllocator {
   }
 
   @VisibleForTesting
-  String executeNGetCmdOutput(Configuration conf) throws YarnException {
+  public String executeNGetCmdOutput(Configuration conf) throws YarnException {
     String numaCtlCmd = conf.get(
         YarnConfiguration.NM_NUMA_AWARENESS_NUMACTL_CMD,
         YarnConfiguration.DEFAULT_NM_NUMA_AWARENESS_NUMACTL_CMD);
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nod \
emanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestDefaultContainerExecutor.java \
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/sr \
c/test/java/org/apache/hadoop/yarn/server/nodemanager/TestDefaultContainerExecutor.java
 index a5c115283a0..473292f35f7 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanage \
r/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestDefaultContainerExecutor.java
                
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanage \
r/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestDefaultContainerExecutor.java
 @@ -20,8 +20,8 @@ package org.apache.hadoop.yarn.server.nodemanager;
 
 import static org.apache.hadoop.fs.CreateFlag.CREATE;
 import static org.apache.hadoop.fs.CreateFlag.OVERWRITE;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.isA;
@@ -39,10 +39,12 @@ import java.io.FileNotFoundException;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.CommonConfigurationKeys;
@@ -60,23 +62,32 @@ import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
 import org.apache.hadoop.yarn.api.records.ApplicationId;
 import org.apache.hadoop.yarn.api.records.ContainerId;
 import org.apache.hadoop.yarn.api.records.ContainerLaunchContext;
+import org.apache.hadoop.yarn.api.records.Resource;
 import org.apache.hadoop.yarn.conf.YarnConfiguration;
 import org.apache.hadoop.yarn.exceptions.ConfigurationException;
 import org.apache.hadoop.yarn.exceptions.YarnException;
+import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
 import org.apache.hadoop.yarn.server.nodemanager.api.LocalizationProtocol;
 import org.apache.hadoop.yarn.server.nodemanager.api.ResourceLocalizationSpec;
 import org.apache.hadoop.yarn.server.nodemanager.api.protocolrecords.LocalizerAction;
  import org.apache.hadoop.yarn.server.nodemanager.api.protocolrecords.LocalizerStatus;
  import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
  import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ContainerDiagnosticsUpdateEvent;
 +import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ResourceMappings;
 +import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.ResourceMappings.AssignedResources;
  import org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch;
 +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.numa.NumaResourceAllocation;
 +import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources.numa.NumaResourceAllocator;
  import org.apache.hadoop.yarn.server.nodemanager.containermanager.localizer.ContainerLocalizer;
  import org.apache.hadoop.yarn.server.nodemanager.containermanager.localizer.MockLocalizerHeartbeatResponse;
 +import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerReacquisitionContext;
  import org.apache.hadoop.yarn.server.nodemanager.executor.ContainerStartContext;
 import org.apache.hadoop.yarn.server.nodemanager.executor.DeletionAsUserContext;
 import org.apache.hadoop.yarn.server.nodemanager.executor.LocalizerStartContext;
+import org.apache.hadoop.yarn.server.nodemanager.recovery.NMStateStoreService;
 import org.junit.AfterClass;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
@@ -86,6 +97,14 @@ public class TestDefaultContainerExecutor {
   private static Path BASE_TMP_PATH = new Path("target",
       TestDefaultContainerExecutor.class.getSimpleName());
 
+  private YarnConfiguration yarnConfiguration;
+
+  private DefaultContainerExecutor containerExecutor;
+
+  private Container mockContainer;
+
+  private NumaResourceAllocator numaResourceAllocator;
+
   @AfterClass
   public static void deleteTmpFiles() throws IOException {
     FileContext lfs = FileContext.getLocalFSFileContext();
@@ -736,4 +755,204 @@ public class TestDefaultContainerExecutor {
 //        new FsPermission(ApplicationLocalizer.LOGDIR_PERM), true);
 //  }
 
+  @Before
+  public void setUp() throws IOException, YarnException {
+    yarnConfiguration = new YarnConfiguration();
+    setNumaConfig();
+    Context mockContext = createAndGetMockContext();
+    NMStateStoreService nmStateStoreService =
+            mock(NMStateStoreService.class);
+    when(mockContext.getNMStateStore()).thenReturn(nmStateStoreService);
+    numaResourceAllocator = new NumaResourceAllocator(mockContext) {
+      @Override
+      public String executeNGetCmdOutput(Configuration config)
+              throws YarnRuntimeException {
+        return getNumaCmdOutput();
+      }
+    };
+
+    numaResourceAllocator.init(yarnConfiguration);
+    FileContext lfs = FileContext.getLocalFSFileContext();
+    containerExecutor = new DefaultContainerExecutor(lfs) {
+      @Override
+      public Configuration getConf() {
+        return yarnConfiguration;
+      }
+    };
+    containerExecutor.setNumaResourceAllocator(numaResourceAllocator);
+    mockContainer = mock(Container.class);
+  }
+
+  private void setNumaConfig() {
+    yarnConfiguration.set(YarnConfiguration.NM_NUMA_AWARENESS_ENABLED, "true");
+    yarnConfiguration.set(YarnConfiguration.NM_NUMA_AWARENESS_READ_TOPOLOGY, \
"true"); +    yarnConfiguration.set(YarnConfiguration.NM_NUMA_AWARENESS_NUMACTL_CMD, \
"/usr/bin/numactl"); +  }
+
+
+  private String getNumaCmdOutput() {
+    // architecture of 8 cpu cores
+    // randomly picked size of memory
+    return "available: 2 nodes (0-1)\n\t"
+            + "node 0 cpus: 0 2 4 6\n\t"
+            + "node 0 size: 73717 MB\n\t"
+            + "node 0 free: 73717 MB\n\t"
+            + "node 1 cpus: 1 3 5 7\n\t"
+            + "node 1 size: 73717 MB\n\t"
+            + "node 1 free: 73717 MB\n\t"
+            + "node distances:\n\t"
+            + "node 0 1\n\t"
+            + "0: 10 20\n\t"
+            + "1: 20 10";
+  }
+
+  private Context createAndGetMockContext() {
+    Context mockContext = mock(Context.class);
+    @SuppressWarnings("unchecked")
+    ConcurrentHashMap<ContainerId, Container> mockContainers = mock(
+            ConcurrentHashMap.class);
+    mockContainer = mock(Container.class);
+    when(mockContainer.getResourceMappings())
+            .thenReturn(new ResourceMappings());
+    when(mockContainers.get(any())).thenReturn(mockContainer);
+    when(mockContext.getContainers()).thenReturn(mockContainers);
+    when(mockContainer.getResource()).thenReturn(Resource.newInstance(2048, 2));
+    return mockContext;
+  }
+
+  private void testAllocateNumaResource(String containerId, Resource resource,
+                                        String memNodes, String cpuNodes) throws \
Exception { +    when(mockContainer.getContainerId())
+            .thenReturn(ContainerId.fromString(containerId));
+    when(mockContainer.getResource()).thenReturn(resource);
+    NumaResourceAllocation numaResourceAllocation =
+            numaResourceAllocator.allocateNumaNodes(mockContainer);
+    containerExecutor.setNumactl(containerExecutor.getConf().get(YarnConfiguration.NM_NUMA_AWARENESS_NUMACTL_CMD,
 +            YarnConfiguration.DEFAULT_NM_NUMA_AWARENESS_NUMACTL_CMD));
+    String[] commands = containerExecutor.getNumaCommands(numaResourceAllocation);
+    assertEquals(Arrays.asList(commands), Arrays.asList("/usr/bin/numactl",
+            "--interleave=" + memNodes, "--cpunodebind=" + cpuNodes));
+  }
+
+  @Test
+  public void testAllocateNumaMemoryResource() throws Exception {
+    // keeping cores constant for testing memory resources
+
+    // allocates node 0 for memory and cpu
+    testAllocateNumaResource("container_1481156246874_0001_01_000001",
+            Resource.newInstance(2048, 2), "0", "0");
+
+    // allocates node 1 for memory and cpu since allocator uses round robin \
assignment +    testAllocateNumaResource("container_1481156246874_0001_01_000002",
+            Resource.newInstance(60000, 2), "1", "1");
+
+    // allocates node 0,1 for memory since there is no sufficient memory in any one \
node +    testAllocateNumaResource("container_1481156246874_0001_01_000003",
+            Resource.newInstance(80000, 2), "0,1", "0");
+
+    // returns null since there are no sufficient resources available for the \
request +    when(mockContainer.getContainerId()).thenReturn(
+            ContainerId.fromString("container_1481156246874_0001_01_000004"));
+    when(mockContainer.getResource())
+            .thenReturn(Resource.newInstance(80000, 2));
+    Assert.assertNull(numaResourceAllocator.allocateNumaNodes(mockContainer));
+
+    // allocates node 1 for memory and cpu
+    testAllocateNumaResource("container_1481156246874_0001_01_000005",
+            Resource.newInstance(1024, 2), "1", "1");
+  }
+
+  @Test
+  public void testAllocateNumaCpusResource() throws Exception {
+    // keeping memory constant
+
+    // allocates node 0 for memory and cpu
+    testAllocateNumaResource("container_1481156246874_0001_01_000001",
+            Resource.newInstance(2048, 2), "0", "0");
+
+    // allocates node 1 for memory and cpu since allocator uses round robin \
assignment +    testAllocateNumaResource("container_1481156246874_0001_01_000002",
+            Resource.newInstance(2048, 2), "1", "1");
+
+    // allocates node 0,1 for cpus since there is are no sufficient cpus available \
in any one node +    \
testAllocateNumaResource("container_1481156246874_0001_01_000003", +            \
Resource.newInstance(2048, 3), "0", "0,1"); +
+    // returns null since there are no sufficient resources available for the \
request +    when(mockContainer.getContainerId()).thenReturn(
+            ContainerId.fromString("container_1481156246874_0001_01_000004"));
+    when(mockContainer.getResource()).thenReturn(Resource.newInstance(2048, 2));
+    Assert.assertNull(numaResourceAllocator.allocateNumaNodes(mockContainer));
+
+    // allocates node 1 for memory and cpu
+    testAllocateNumaResource("container_1481156246874_0001_01_000005",
+            Resource.newInstance(2048, 1), "1", "1");
+  }
+
+  @Test
+  public void testReacquireContainer() throws Exception {
+    @SuppressWarnings("unchecked")
+    ConcurrentHashMap<ContainerId, Container> mockContainers = mock(
+            ConcurrentHashMap.class);
+    Context mockContext = mock(Context.class);
+    NMStateStoreService mock = mock(NMStateStoreService.class);
+    when(mockContext.getNMStateStore()).thenReturn(mock);
+    ResourceMappings resourceMappings = new ResourceMappings();
+    AssignedResources assignedRscs = new AssignedResources();
+    when(mockContainer.getResource())
+            .thenReturn(Resource.newInstance(147434, 2));
+    ContainerId cid = \
ContainerId.fromString("container_1481156246874_0001_01_000001"); +    \
when(mockContainer.getContainerId()).thenReturn(cid); +    NumaResourceAllocation \
numaResourceAllocation = +            \
numaResourceAllocator.allocateNumaNodes(mockContainer); +    \
assignedRscs.updateAssignedResources(Arrays.asList(numaResourceAllocation)); +    \
resourceMappings.addAssignedResources("numa", assignedRscs); +    \
when(mockContainer.getResourceMappings()).thenReturn(resourceMappings); +    \
when(mockContainers.get(any())).thenReturn(mockContainer); +    \
when(mockContext.getContainers()).thenReturn(mockContainers); +
+    // recovered numa resources should be added to the used resources and
+    // remaining will be available for further allocation.
+
+    ContainerReacquisitionContext containerReacquisitionContext =
+            new ContainerReacquisitionContext.Builder()
+                    .setContainerId(cid)
+                    .setUser("user")
+                    .setContainer(mockContainer)
+                    .build();
+
+    containerExecutor.reacquireContainer(containerReacquisitionContext);
+
+    // reacquireContainer recovers all the numa resources ,
+    // that should be free to use next
+    testAllocateNumaResource("container_1481156246874_0001_01_000001",
+            Resource.newInstance(147434, 2), "0,1", "1");
+    when(mockContainer.getContainerId()).thenReturn(
+            ContainerId.fromString("container_1481156246874_0001_01_000004"));
+    when(mockContainer.getResource())
+            .thenReturn(Resource.newInstance(1024, 2));
+
+    // returns null since there are no sufficient resources available for the \
request +    Assert.assertNull(numaResourceAllocator.allocateNumaNodes(mockContainer));
 +  }
+
+  @Test
+  public void testConcatStringCommands() {
+    // test one array of string as null
+    assertEquals(containerExecutor.concatStringCommands(null, new \
String[]{"hello"})[0], +            new String[]{"hello"}[0]);
+    // test both array of string as null
+    Assert.assertNull(containerExecutor.concatStringCommands(null, null));
+    // test case when both arrays are not null and of equal length
+    String[] res = containerExecutor.concatStringCommands(new String[]{"one"},
+            new String[]{"two"});
+    assertEquals(res[0]+res[1], "one" + "two");
+    // test both array of different length
+    res = containerExecutor.concatStringCommands(new String[]{"one"},
+            new String[]{"two", "three"});
+    assertEquals(res[0] + res[1] + res[2], "one" + "two" + "three");
+
+  }
+
+
 }
diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nod \
emanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/numa/TestNumaResourceAllocator.java \
b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/sr \
c/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/numa/TestNumaResourceAllocator.java
 index c8072c327a9..42c495c88f8 100644
--- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanage \
r/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/numa/TestNumaResourceAllocator.java
                
+++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanage \
r/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/numa/TestNumaResourceAllocator.java
 @@ -95,7 +95,7 @@ public class TestNumaResourceAllocator {
         + "1: 20 10";
     numaResourceAllocator = new NumaResourceAllocator(mock(Context.class)) {
       @Override
-      String executeNGetCmdOutput(Configuration config)
+      public String executeNGetCmdOutput(Configuration config)
           throws YarnRuntimeException {
         return cmdOutput;
       }


---------------------------------------------------------------------
To unsubscribe, e-mail: common-commits-unsubscribe@hadoop.apache.org
For additional commands, e-mail: common-commits-help@hadoop.apache.org


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic