diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/util/CgroupsLCEResourcesHandler.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/util/CgroupsLCEResourcesHandler.java index d5bd225..b175372 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/util/CgroupsLCEResourcesHandler.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/util/CgroupsLCEResourcesHandler.java @@ -59,7 +59,10 @@ private final String MTAB_FILE = "/proc/mounts"; private final String CGROUPS_FSTYPE = "cgroup"; private final String CONTROLLER_CPU = "cpu"; + private final String CPU_PERIOD_US = "cfs_period_us"; + private final String CPU_QUOTA_US = "cfs_quota_us"; private final int CPU_DEFAULT_WEIGHT = 1024; // set by kernel + private final long DEFAULT_PERIOD_US = 100000l; private final Map controllerPaths; // Controller -> path private long deleteCgroupTimeout; @@ -117,6 +120,14 @@ public void init(LinuxContainerExecutor lce) throws IOException { } initializeControllerPaths(); + + // cap overall usage to the number of cores allocated to YARN + int vcores = conf.getInt(YarnConfiguration.NM_VCORES, + YarnConfiguration.DEFAULT_NM_VCORES); + updateCgroup(CONTROLLER_CPU, "", CPU_PERIOD_US, + String.valueOf(DEFAULT_PERIOD_US)); + updateCgroup(CONTROLLER_CPU, "", CPU_QUOTA_US, + String.valueOf(DEFAULT_PERIOD_US * vcores)); } @@ -274,7 +285,7 @@ public String getResourcesOption(ContainerId containerId) { BufferedReader in = null; try { - in = new BufferedReader(new FileReader(new File(MTAB_FILE))); + in = new BufferedReader(new FileReader(new File(getMtabFileName()))); for (String str = in.readLine(); str != null; str = in.readLine()) { @@ -292,13 +303,13 @@ public String getResourcesOption(ContainerId containerId) { } } } catch (IOException e) { - throw new IOException("Error while reading " + MTAB_FILE, e); + throw new IOException("Error while reading " + getMtabFileName(), e); } finally { // Close the streams try { in.close(); } catch (IOException e2) { - LOG.warn("Error closing the stream: " + MTAB_FILE, e2); + LOG.warn("Error closing the stream: " + getMtabFileName(), e2); } } @@ -334,7 +345,12 @@ private void initializeControllerPaths() throws IOException { } } else { throw new IOException("Not able to enforce cpu weights; cannot find " - + "cgroup for cpu controller in " + MTAB_FILE); + + "cgroup for cpu controller in " + getMtabFileName()); } } + + @VisibleForTesting + String getMtabFileName() { + return MTAB_FILE; + } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/util/TestCgroupsLCEResourcesHandler.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/util/TestCgroupsLCEResourcesHandler.java index 611045e..0f155d3 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/util/TestCgroupsLCEResourcesHandler.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/util/TestCgroupsLCEResourcesHandler.java @@ -17,13 +17,16 @@ */ package org.apache.hadoop.yarn.server.nodemanager.util; +import org.apache.commons.io.FileUtils; +import org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor; import org.junit.Assert; import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.util.Clock; import org.junit.Test; -import java.io.File; -import java.io.FileOutputStream; +import java.io.*; +import java.util.List; +import java.util.Scanner; import java.util.UUID; import java.util.concurrent.CountDownLatch; @@ -70,4 +73,86 @@ public void run() { Assert.assertFalse(handler.deleteCgroup(file.getPath())); } + static class MockLinuxContainerExecutor extends LinuxContainerExecutor { + @Override + public void mountCgroups(List x, String y) { + } + } + + static class CustomCgroupsLCEResourceHandler extends + CgroupsLCEResourcesHandler { + + String mtabFile; + + void setMtabFile(String file) { + mtabFile = file; + } + + @Override + String getMtabFileName() { + return mtabFile; + } + } + + @Test + public void testInit() throws IOException { + int cores = 3; + int defaultPeriod = 100 * 1000; + int expectedQuota = cores * defaultPeriod; + LinuxContainerExecutor mockLCE = new MockLinuxContainerExecutor(); + CustomCgroupsLCEResourceHandler handler = + new CustomCgroupsLCEResourceHandler(); + YarnConfiguration conf = new YarnConfiguration(); + conf.setInt(YarnConfiguration.NM_VCORES, cores); + handler.setConf(conf); + handler.initConfig(); + + // create mock cgroup + File cgroupDir = new File("target", UUID.randomUUID().toString()); + if (!cgroupDir.mkdir()) { + String message = "Could not create dir " + cgroupDir.getAbsolutePath(); + throw new IOException(message); + } + File cgroupMountDir = new File(cgroupDir.getAbsolutePath(), "/hadoop-yarn"); + if (!cgroupMountDir.mkdir()) { + String message = + "Could not create dir " + cgroupMountDir.getAbsolutePath(); + throw new IOException(message); + } + + // create mock mtab + String mtabContent = + "none " + cgroupDir.getAbsolutePath() + " cgroup rw,relatime,cpu 0 0"; + File mockMtab = new File("target", UUID.randomUUID().toString()); + if (!mockMtab.exists()) { + if (!mockMtab.createNewFile()) { + String message = "Could not create file " + mockMtab.getAbsolutePath(); + throw new IOException(message); + } + } + FileWriter mtabWriter = new FileWriter(mockMtab.getAbsoluteFile()); + mtabWriter.write(mtabContent); + mtabWriter.close(); + mockMtab.deleteOnExit(); + + // setup our handler and call init() + handler.setMtabFile(mockMtab.getAbsolutePath()); + handler.init(mockLCE); + + // check values + int period = readIntFromFile(cgroupMountDir + "/" + "cpu.cfs_period_us"); + int quota = readIntFromFile(cgroupMountDir + "/" + "cpu.cfs_quota_us"); + Assert.assertEquals(defaultPeriod, period); + Assert.assertEquals(expectedQuota, quota); + FileUtils.deleteQuietly(cgroupDir); + + } + + private int readIntFromFile(String filename) throws IOException { + Scanner scanner = new Scanner(new File(filename)); + if (scanner.hasNextInt()) { + return scanner.nextInt(); + } + return -1; + } }