|
@@ -18,6 +18,7 @@
|
|
|
|
|
|
package org.apache.hadoop.yarn.util;
|
|
|
|
|
|
+import static org.apache.hadoop.yarn.util.ProcfsBasedProcessTree.KB_TO_BYTES;
|
|
|
import static org.junit.Assert.fail;
|
|
|
|
|
|
import java.io.BufferedReader;
|
|
@@ -27,6 +28,7 @@ import java.io.FileNotFoundException;
|
|
|
import java.io.FileReader;
|
|
|
import java.io.FileWriter;
|
|
|
import java.io.IOException;
|
|
|
+import java.util.List;
|
|
|
import java.util.Random;
|
|
|
import java.util.Vector;
|
|
|
import java.util.regex.Matcher;
|
|
@@ -34,14 +36,18 @@ import java.util.regex.Pattern;
|
|
|
|
|
|
import org.apache.commons.logging.Log;
|
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
+import org.apache.hadoop.conf.Configuration;
|
|
|
import org.apache.hadoop.fs.FileContext;
|
|
|
import org.apache.hadoop.fs.FileUtil;
|
|
|
import org.apache.hadoop.fs.Path;
|
|
|
-import org.apache.hadoop.util.StringUtils;
|
|
|
import org.apache.hadoop.util.Shell;
|
|
|
import org.apache.hadoop.util.Shell.ExitCodeException;
|
|
|
import org.apache.hadoop.util.Shell.ShellCommandExecutor;
|
|
|
-import org.apache.hadoop.yarn.util.ProcfsBasedProcessTree;
|
|
|
+import org.apache.hadoop.util.StringUtils;
|
|
|
+import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
|
|
+import org.apache.hadoop.yarn.util.ProcfsBasedProcessTree.MemInfo;
|
|
|
+import org.apache.hadoop.yarn.util.ProcfsBasedProcessTree.ProcessSmapMemoryInfo;
|
|
|
+import org.apache.hadoop.yarn.util.ProcfsBasedProcessTree.ProcessTreeSmapMemInfo;
|
|
|
import org.junit.Assert;
|
|
|
import org.junit.Before;
|
|
|
import org.junit.Test;
|
|
@@ -52,9 +58,9 @@ import org.junit.Test;
|
|
|
public class TestProcfsBasedProcessTree {
|
|
|
|
|
|
private static final Log LOG = LogFactory
|
|
|
- .getLog(TestProcfsBasedProcessTree.class);
|
|
|
+ .getLog(TestProcfsBasedProcessTree.class);
|
|
|
protected static File TEST_ROOT_DIR = new File("target",
|
|
|
- TestProcfsBasedProcessTree.class.getName() + "-localDir");
|
|
|
+ TestProcfsBasedProcessTree.class.getName() + "-localDir");
|
|
|
|
|
|
private ShellCommandExecutor shexec = null;
|
|
|
private String pidFile, lowestDescendant;
|
|
@@ -66,19 +72,19 @@ public class TestProcfsBasedProcessTree {
|
|
|
public void run() {
|
|
|
try {
|
|
|
Vector<String> args = new Vector<String>();
|
|
|
- if(isSetsidAvailable()) {
|
|
|
+ if (isSetsidAvailable()) {
|
|
|
args.add("setsid");
|
|
|
}
|
|
|
args.add("bash");
|
|
|
args.add("-c");
|
|
|
- args.add(" echo $$ > " + pidFile + "; sh " +
|
|
|
- shellScript + " " + N + ";") ;
|
|
|
+ args.add(" echo $$ > " + pidFile + "; sh " + shellScript + " " + N
|
|
|
+ + ";");
|
|
|
shexec = new ShellCommandExecutor(args.toArray(new String[0]));
|
|
|
shexec.execute();
|
|
|
} catch (ExitCodeException ee) {
|
|
|
- LOG.info("Shell Command exit with a non-zero exit code. This is" +
|
|
|
- " expected as we are killing the subprocesses of the" +
|
|
|
- " task intentionally. " + ee);
|
|
|
+ LOG.info("Shell Command exit with a non-zero exit code. This is"
|
|
|
+ + " expected as we are killing the subprocesses of the"
|
|
|
+ + " task intentionally. " + ee);
|
|
|
} catch (IOException ioe) {
|
|
|
LOG.info("Error executing shell command " + ioe);
|
|
|
} finally {
|
|
@@ -104,15 +110,15 @@ public class TestProcfsBasedProcessTree {
|
|
|
@Before
|
|
|
public void setup() throws IOException {
|
|
|
FileContext.getLocalFSFileContext().delete(
|
|
|
- new Path(TEST_ROOT_DIR.getAbsolutePath()), true);
|
|
|
+ new Path(TEST_ROOT_DIR.getAbsolutePath()), true);
|
|
|
}
|
|
|
|
|
|
- @Test (timeout = 30000)
|
|
|
+ @Test(timeout = 30000)
|
|
|
public void testProcessTree() throws Exception {
|
|
|
|
|
|
if (!Shell.LINUX) {
|
|
|
System.out
|
|
|
- .println("ProcfsBasedProcessTree is not available on this system. Not testing");
|
|
|
+ .println("ProcfsBasedProcessTree is not available on this system. Not testing");
|
|
|
return;
|
|
|
|
|
|
}
|
|
@@ -139,24 +145,16 @@ public class TestProcfsBasedProcessTree {
|
|
|
tempFile.deleteOnExit();
|
|
|
pidFile = TEST_ROOT_DIR + File.separator + tempFile.getName();
|
|
|
|
|
|
- lowestDescendant = TEST_ROOT_DIR + File.separator + "lowestDescendantPidFile";
|
|
|
+ lowestDescendant =
|
|
|
+ TEST_ROOT_DIR + File.separator + "lowestDescendantPidFile";
|
|
|
|
|
|
// write to shell-script
|
|
|
try {
|
|
|
FileWriter fWriter = new FileWriter(shellScript);
|
|
|
- fWriter.write(
|
|
|
- "# rogue task\n" +
|
|
|
- "sleep 1\n" +
|
|
|
- "echo hello\n" +
|
|
|
- "if [ $1 -ne 0 ]\n" +
|
|
|
- "then\n" +
|
|
|
- " sh " + shellScript + " $(($1-1))\n" +
|
|
|
- "else\n" +
|
|
|
- " echo $$ > " + lowestDescendant + "\n" +
|
|
|
- " while true\n do\n" +
|
|
|
- " sleep 5\n" +
|
|
|
- " done\n" +
|
|
|
- "fi");
|
|
|
+ fWriter.write("# rogue task\n" + "sleep 1\n" + "echo hello\n"
|
|
|
+ + "if [ $1 -ne 0 ]\n" + "then\n" + " sh " + shellScript
|
|
|
+ + " $(($1-1))\n" + "else\n" + " echo $$ > " + lowestDescendant + "\n"
|
|
|
+ + " while true\n do\n" + " sleep 5\n" + " done\n" + "fi");
|
|
|
fWriter.close();
|
|
|
} catch (IOException ioe) {
|
|
|
LOG.info("Error: " + ioe);
|
|
@@ -172,7 +170,7 @@ public class TestProcfsBasedProcessTree {
|
|
|
LOG.info("ProcessTree: " + p.toString());
|
|
|
|
|
|
File leaf = new File(lowestDescendant);
|
|
|
- //wait till lowest descendant process of Rougue Task starts execution
|
|
|
+ // wait till lowest descendant process of Rougue Task starts execution
|
|
|
while (!leaf.exists()) {
|
|
|
try {
|
|
|
Thread.sleep(500);
|
|
@@ -208,16 +206,17 @@ public class TestProcfsBasedProcessTree {
|
|
|
|
|
|
LOG.info("Process-tree dump follows: \n" + processTreeDump);
|
|
|
Assert.assertTrue("Process-tree dump doesn't start with a proper header",
|
|
|
- processTreeDump.startsWith("\t|- PID PPID PGRPID SESSID CMD_NAME " +
|
|
|
- "USER_MODE_TIME(MILLIS) SYSTEM_TIME(MILLIS) VMEM_USAGE(BYTES) " +
|
|
|
- "RSSMEM_USAGE(PAGES) FULL_CMD_LINE\n"));
|
|
|
+ processTreeDump.startsWith("\t|- PID PPID PGRPID SESSID CMD_NAME "
|
|
|
+ + "USER_MODE_TIME(MILLIS) SYSTEM_TIME(MILLIS) VMEM_USAGE(BYTES) "
|
|
|
+ + "RSSMEM_USAGE(PAGES) FULL_CMD_LINE\n"));
|
|
|
for (int i = N; i >= 0; i--) {
|
|
|
- String cmdLineDump = "\\|- [0-9]+ [0-9]+ [0-9]+ [0-9]+ \\(sh\\)" +
|
|
|
- " [0-9]+ [0-9]+ [0-9]+ [0-9]+ sh " + shellScript + " " + i;
|
|
|
+ String cmdLineDump =
|
|
|
+ "\\|- [0-9]+ [0-9]+ [0-9]+ [0-9]+ \\(sh\\)"
|
|
|
+ + " [0-9]+ [0-9]+ [0-9]+ [0-9]+ sh " + shellScript + " " + i;
|
|
|
Pattern pat = Pattern.compile(cmdLineDump);
|
|
|
Matcher mat = pat.matcher(processTreeDump);
|
|
|
- Assert.assertTrue("Process-tree dump doesn't contain the cmdLineDump of " + i
|
|
|
- + "th process!", mat.find());
|
|
|
+ Assert.assertTrue("Process-tree dump doesn't contain the cmdLineDump of "
|
|
|
+ + i + "th process!", mat.find());
|
|
|
}
|
|
|
|
|
|
// Not able to join thread sometimes when forking with large N.
|
|
@@ -231,9 +230,9 @@ public class TestProcfsBasedProcessTree {
|
|
|
// ProcessTree is gone now. Any further calls should be sane.
|
|
|
p.updateProcessTree();
|
|
|
Assert.assertFalse("ProcessTree must have been gone", isAlive(pid));
|
|
|
- Assert.assertTrue("Cumulative vmem for the gone-process is "
|
|
|
- + p.getCumulativeVmem() + " . It should be zero.", p
|
|
|
- .getCumulativeVmem() == 0);
|
|
|
+ Assert.assertTrue(
|
|
|
+ "Cumulative vmem for the gone-process is " + p.getCumulativeVmem()
|
|
|
+ + " . It should be zero.", p.getCumulativeVmem() == 0);
|
|
|
Assert.assertTrue(p.toString().equals("[ ]"));
|
|
|
}
|
|
|
|
|
@@ -241,7 +240,8 @@ public class TestProcfsBasedProcessTree {
|
|
|
return new ProcfsBasedProcessTree(pid);
|
|
|
}
|
|
|
|
|
|
- protected ProcfsBasedProcessTree createProcessTree(String pid, String procfsRootDir) {
|
|
|
+ protected ProcfsBasedProcessTree createProcessTree(String pid,
|
|
|
+ String procfsRootDir) {
|
|
|
return new ProcfsBasedProcessTree(pid, procfsRootDir);
|
|
|
}
|
|
|
|
|
@@ -251,7 +251,7 @@ public class TestProcfsBasedProcessTree {
|
|
|
|
|
|
/**
|
|
|
* Get PID from a pid-file.
|
|
|
- *
|
|
|
+ *
|
|
|
* @param pidFileName
|
|
|
* Name of the pid-file.
|
|
|
* @return the PID string read from the pid-file. Returns null if the
|
|
@@ -328,23 +328,67 @@ public class TestProcfsBasedProcessTree {
|
|
|
// construct a line that mimics the procfs stat file.
|
|
|
// all unused numerical entries are set to 0.
|
|
|
public String getStatLine() {
|
|
|
- return String.format("%s (%s) S %s %s %s 0 0 0" +
|
|
|
- " 0 0 0 0 %s %s 0 0 0 0 0 0 0 %s %s 0 0" +
|
|
|
- " 0 0 0 0 0 0 0 0" +
|
|
|
- " 0 0 0 0 0",
|
|
|
- pid, name, ppid, pgrpId, session,
|
|
|
- utime, stime, vmem, rssmemPage);
|
|
|
+ return String.format("%s (%s) S %s %s %s 0 0 0"
|
|
|
+ + " 0 0 0 0 %s %s 0 0 0 0 0 0 0 %s %s 0 0" + " 0 0 0 0 0 0 0 0"
|
|
|
+ + " 0 0 0 0 0", pid, name, ppid, pgrpId, session, utime, stime, vmem,
|
|
|
+ rssmemPage);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public ProcessSmapMemoryInfo constructMemoryMappingInfo(String address,
|
|
|
+ String[] entries) {
|
|
|
+ ProcessSmapMemoryInfo info = new ProcessSmapMemoryInfo(address);
|
|
|
+ info.setMemInfo(MemInfo.SIZE.name(), entries[0]);
|
|
|
+ info.setMemInfo(MemInfo.RSS.name(), entries[1]);
|
|
|
+ info.setMemInfo(MemInfo.PSS.name(), entries[2]);
|
|
|
+ info.setMemInfo(MemInfo.SHARED_CLEAN.name(), entries[3]);
|
|
|
+ info.setMemInfo(MemInfo.SHARED_DIRTY.name(), entries[4]);
|
|
|
+ info.setMemInfo(MemInfo.PRIVATE_CLEAN.name(), entries[5]);
|
|
|
+ info.setMemInfo(MemInfo.PRIVATE_DIRTY.name(), entries[6]);
|
|
|
+ info.setMemInfo(MemInfo.REFERENCED.name(), entries[7]);
|
|
|
+ info.setMemInfo(MemInfo.ANONYMOUS.name(), entries[8]);
|
|
|
+ info.setMemInfo(MemInfo.ANON_HUGE_PAGES.name(), entries[9]);
|
|
|
+ info.setMemInfo(MemInfo.SWAP.name(), entries[10]);
|
|
|
+ info.setMemInfo(MemInfo.KERNEL_PAGE_SIZE.name(), entries[11]);
|
|
|
+ info.setMemInfo(MemInfo.MMU_PAGE_SIZE.name(), entries[12]);
|
|
|
+ return info;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void createMemoryMappingInfo(ProcessTreeSmapMemInfo[] procMemInfo) {
|
|
|
+ for (int i = 0; i < procMemInfo.length; i++) {
|
|
|
+ // Construct 4 memory mappings per process.
|
|
|
+ // As per min(Shared_Dirty, Pss) + Private_Clean + Private_Dirty
|
|
|
+ // and not including r--s, r-xs, we should get 100 KB per process
|
|
|
+ List<ProcessSmapMemoryInfo> memoryMappingList =
|
|
|
+ procMemInfo[i].getMemoryInfoList();
|
|
|
+ memoryMappingList.add(constructMemoryMappingInfo(
|
|
|
+ "7f56c177c000-7f56c177d000 "
|
|
|
+ + "rw-p 00010000 08:02 40371558 "
|
|
|
+ + "/grid/0/jdk1.7.0_25/jre/lib/amd64/libnio.so",
|
|
|
+ new String[] { "4", "4", "25", "4", "25", "15", "10", "4", "0", "0",
|
|
|
+ "0", "4", "4" }));
|
|
|
+ memoryMappingList.add(constructMemoryMappingInfo(
|
|
|
+ "7fb09382e000-7fb09382f000 r--s 00003000 " + "08:02 25953545",
|
|
|
+ new String[] { "4", "4", "25", "4", "0", "15", "10", "4", "0", "0",
|
|
|
+ "0", "4", "4" }));
|
|
|
+ memoryMappingList.add(constructMemoryMappingInfo(
|
|
|
+ "7e8790000-7e8b80000 r-xs 00000000 00:00 0", new String[] { "4", "4",
|
|
|
+ "25", "4", "0", "15", "10", "4", "0", "0", "0", "4", "4" }));
|
|
|
+ memoryMappingList.add(constructMemoryMappingInfo(
|
|
|
+ "7da677000-7e0dcf000 rw-p 00000000 00:00 0", new String[] { "4", "4",
|
|
|
+ "25", "4", "50", "15", "10", "4", "0", "0", "0", "4", "4" }));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * A basic test that creates a few process directories and writes
|
|
|
- * stat files. Verifies that the cpu time and memory is correctly
|
|
|
- * computed.
|
|
|
- * @throws IOException if there was a problem setting up the
|
|
|
- * fake procfs directories or files.
|
|
|
+ * A basic test that creates a few process directories and writes stat files.
|
|
|
+ * Verifies that the cpu time and memory is correctly computed.
|
|
|
+ *
|
|
|
+ * @throws IOException
|
|
|
+ * if there was a problem setting up the fake procfs directories or
|
|
|
+ * files.
|
|
|
*/
|
|
|
- @Test (timeout = 30000)
|
|
|
+ @Test(timeout = 30000)
|
|
|
public void testCpuAndMemoryForProcessTree() throws IOException {
|
|
|
|
|
|
// test processes
|
|
@@ -359,67 +403,108 @@ public class TestProcfsBasedProcessTree {
|
|
|
// create stat objects.
|
|
|
// assuming processes 100, 200, 300 are in tree and 400 is not.
|
|
|
ProcessStatInfo[] procInfos = new ProcessStatInfo[4];
|
|
|
- procInfos[0] = new ProcessStatInfo(new String[]
|
|
|
- {"100", "proc1", "1", "100", "100", "100000", "100", "1000", "200"});
|
|
|
- procInfos[1] = new ProcessStatInfo(new String[]
|
|
|
- {"200", "proc2", "100", "100", "100", "200000", "200", "2000", "400"});
|
|
|
- procInfos[2] = new ProcessStatInfo(new String[]
|
|
|
- {"300", "proc3", "200", "100", "100", "300000", "300", "3000", "600"});
|
|
|
- procInfos[3] = new ProcessStatInfo(new String[]
|
|
|
- {"400", "proc4", "1", "400", "400", "400000", "400", "4000", "800"});
|
|
|
-
|
|
|
- writeStatFiles(procfsRootDir, pids, procInfos);
|
|
|
+ procInfos[0] =
|
|
|
+ new ProcessStatInfo(new String[] { "100", "proc1", "1", "100", "100",
|
|
|
+ "100000", "100", "1000", "200" });
|
|
|
+ procInfos[1] =
|
|
|
+ new ProcessStatInfo(new String[] { "200", "proc2", "100", "100",
|
|
|
+ "100", "200000", "200", "2000", "400" });
|
|
|
+ procInfos[2] =
|
|
|
+ new ProcessStatInfo(new String[] { "300", "proc3", "200", "100",
|
|
|
+ "100", "300000", "300", "3000", "600" });
|
|
|
+ procInfos[3] =
|
|
|
+ new ProcessStatInfo(new String[] { "400", "proc4", "1", "400", "400",
|
|
|
+ "400000", "400", "4000", "800" });
|
|
|
+
|
|
|
+ ProcessTreeSmapMemInfo[] memInfo = new ProcessTreeSmapMemInfo[4];
|
|
|
+ memInfo[0] = new ProcessTreeSmapMemInfo("100");
|
|
|
+ memInfo[1] = new ProcessTreeSmapMemInfo("200");
|
|
|
+ memInfo[2] = new ProcessTreeSmapMemInfo("300");
|
|
|
+ memInfo[3] = new ProcessTreeSmapMemInfo("400");
|
|
|
+ createMemoryMappingInfo(memInfo);
|
|
|
+ writeStatFiles(procfsRootDir, pids, procInfos, memInfo);
|
|
|
|
|
|
// crank up the process tree class.
|
|
|
+ Configuration conf = new Configuration();
|
|
|
ProcfsBasedProcessTree processTree =
|
|
|
createProcessTree("100", procfsRootDir.getAbsolutePath());
|
|
|
+ processTree.setConf(conf);
|
|
|
// build the process tree.
|
|
|
processTree.updateProcessTree();
|
|
|
|
|
|
// verify cumulative memory
|
|
|
Assert.assertEquals("Cumulative virtual memory does not match", 600000L,
|
|
|
- processTree.getCumulativeVmem());
|
|
|
+ processTree.getCumulativeVmem());
|
|
|
|
|
|
// verify rss memory
|
|
|
- long cumuRssMem = ProcfsBasedProcessTree.PAGE_SIZE > 0 ?
|
|
|
- 600L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
|
|
|
- Assert.assertEquals("Cumulative rss memory does not match",
|
|
|
- cumuRssMem, processTree.getCumulativeRssmem());
|
|
|
+ long cumuRssMem =
|
|
|
+ ProcfsBasedProcessTree.PAGE_SIZE > 0
|
|
|
+ ? 600L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
|
|
|
+ Assert.assertEquals("Cumulative rss memory does not match", cumuRssMem,
|
|
|
+ processTree.getCumulativeRssmem());
|
|
|
|
|
|
// verify cumulative cpu time
|
|
|
- long cumuCpuTime = ProcfsBasedProcessTree.JIFFY_LENGTH_IN_MILLIS > 0 ?
|
|
|
- 7200L * ProcfsBasedProcessTree.JIFFY_LENGTH_IN_MILLIS : 0L;
|
|
|
- Assert.assertEquals("Cumulative cpu time does not match",
|
|
|
- cumuCpuTime, processTree.getCumulativeCpuTime());
|
|
|
+ long cumuCpuTime =
|
|
|
+ ProcfsBasedProcessTree.JIFFY_LENGTH_IN_MILLIS > 0
|
|
|
+ ? 7200L * ProcfsBasedProcessTree.JIFFY_LENGTH_IN_MILLIS : 0L;
|
|
|
+ Assert.assertEquals("Cumulative cpu time does not match", cumuCpuTime,
|
|
|
+ processTree.getCumulativeCpuTime());
|
|
|
+ // Check by enabling smaps
|
|
|
+ setSmapsInProceTree(processTree, true);
|
|
|
+ // RSS=Min(shared_dirty,PSS)+PrivateClean+PrivateDirty (exclude r-xs,
|
|
|
+ // r--s)
|
|
|
+ Assert.assertEquals("Cumulative rss memory does not match",
|
|
|
+ (100 * KB_TO_BYTES * 3), processTree.getCumulativeRssmem());
|
|
|
|
|
|
// test the cpu time again to see if it cumulates
|
|
|
- procInfos[0] = new ProcessStatInfo(new String[]
|
|
|
- {"100", "proc1", "1", "100", "100", "100000", "100", "2000", "300"});
|
|
|
- procInfos[1] = new ProcessStatInfo(new String[]
|
|
|
- {"200", "proc2", "100", "100", "100", "200000", "200", "3000", "500"});
|
|
|
- writeStatFiles(procfsRootDir, pids, procInfos);
|
|
|
+ procInfos[0] =
|
|
|
+ new ProcessStatInfo(new String[] { "100", "proc1", "1", "100", "100",
|
|
|
+ "100000", "100", "2000", "300" });
|
|
|
+ procInfos[1] =
|
|
|
+ new ProcessStatInfo(new String[] { "200", "proc2", "100", "100",
|
|
|
+ "100", "200000", "200", "3000", "500" });
|
|
|
+ writeStatFiles(procfsRootDir, pids, procInfos, memInfo);
|
|
|
|
|
|
// build the process tree.
|
|
|
processTree.updateProcessTree();
|
|
|
|
|
|
// verify cumulative cpu time again
|
|
|
- cumuCpuTime = ProcfsBasedProcessTree.JIFFY_LENGTH_IN_MILLIS > 0 ?
|
|
|
- 9400L * ProcfsBasedProcessTree.JIFFY_LENGTH_IN_MILLIS : 0L;
|
|
|
- Assert.assertEquals("Cumulative cpu time does not match",
|
|
|
- cumuCpuTime, processTree.getCumulativeCpuTime());
|
|
|
+ cumuCpuTime =
|
|
|
+ ProcfsBasedProcessTree.JIFFY_LENGTH_IN_MILLIS > 0
|
|
|
+ ? 9400L * ProcfsBasedProcessTree.JIFFY_LENGTH_IN_MILLIS : 0L;
|
|
|
+ Assert.assertEquals("Cumulative cpu time does not match", cumuCpuTime,
|
|
|
+ processTree.getCumulativeCpuTime());
|
|
|
} finally {
|
|
|
FileUtil.fullyDelete(procfsRootDir);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private void setSmapsInProceTree(ProcfsBasedProcessTree processTree,
|
|
|
+ boolean enableFlag) {
|
|
|
+ Configuration conf = processTree.getConf();
|
|
|
+ if (conf == null) {
|
|
|
+ conf = new Configuration();
|
|
|
+ }
|
|
|
+ conf.setBoolean(YarnConfiguration.PROCFS_USE_SMAPS_BASED_RSS_ENABLED, enableFlag);
|
|
|
+ processTree.setConf(conf);
|
|
|
+ processTree.updateProcessTree();
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
- * Tests that cumulative memory is computed only for
|
|
|
- * processes older than a given age.
|
|
|
- * @throws IOException if there was a problem setting up the
|
|
|
- * fake procfs directories or files.
|
|
|
+ * Tests that cumulative memory is computed only for processes older than a
|
|
|
+ * given age.
|
|
|
+ *
|
|
|
+ * @throws IOException
|
|
|
+ * if there was a problem setting up the fake procfs directories or
|
|
|
+ * files.
|
|
|
*/
|
|
|
- @Test (timeout = 30000)
|
|
|
+ @Test(timeout = 30000)
|
|
|
public void testMemForOlderProcesses() throws IOException {
|
|
|
+ testMemForOlderProcesses(false);
|
|
|
+ testMemForOlderProcesses(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void testMemForOlderProcesses(boolean smapEnabled) throws IOException {
|
|
|
// initial list of processes
|
|
|
String[] pids = { "100", "200", "300", "400" };
|
|
|
// create the fake procfs root directory.
|
|
@@ -432,87 +517,141 @@ public class TestProcfsBasedProcessTree {
|
|
|
// create stat objects.
|
|
|
// assuming 100, 200 and 400 are in tree, 300 is not.
|
|
|
ProcessStatInfo[] procInfos = new ProcessStatInfo[4];
|
|
|
- procInfos[0] = new ProcessStatInfo(new String[]
|
|
|
- {"100", "proc1", "1", "100", "100", "100000", "100"});
|
|
|
- procInfos[1] = new ProcessStatInfo(new String[]
|
|
|
- {"200", "proc2", "100", "100", "100", "200000", "200"});
|
|
|
- procInfos[2] = new ProcessStatInfo(new String[]
|
|
|
- {"300", "proc3", "1", "300", "300", "300000", "300"});
|
|
|
- procInfos[3] = new ProcessStatInfo(new String[]
|
|
|
- {"400", "proc4", "100", "100", "100", "400000", "400"});
|
|
|
-
|
|
|
- writeStatFiles(procfsRootDir, pids, procInfos);
|
|
|
+ procInfos[0] =
|
|
|
+ new ProcessStatInfo(new String[] { "100", "proc1", "1", "100", "100",
|
|
|
+ "100000", "100" });
|
|
|
+ procInfos[1] =
|
|
|
+ new ProcessStatInfo(new String[] { "200", "proc2", "100", "100",
|
|
|
+ "100", "200000", "200" });
|
|
|
+ procInfos[2] =
|
|
|
+ new ProcessStatInfo(new String[] { "300", "proc3", "1", "300", "300",
|
|
|
+ "300000", "300" });
|
|
|
+ procInfos[3] =
|
|
|
+ new ProcessStatInfo(new String[] { "400", "proc4", "100", "100",
|
|
|
+ "100", "400000", "400" });
|
|
|
+ // write smap information invariably for testing
|
|
|
+ ProcessTreeSmapMemInfo[] memInfo = new ProcessTreeSmapMemInfo[4];
|
|
|
+ memInfo[0] = new ProcessTreeSmapMemInfo("100");
|
|
|
+ memInfo[1] = new ProcessTreeSmapMemInfo("200");
|
|
|
+ memInfo[2] = new ProcessTreeSmapMemInfo("300");
|
|
|
+ memInfo[3] = new ProcessTreeSmapMemInfo("400");
|
|
|
+ createMemoryMappingInfo(memInfo);
|
|
|
+ writeStatFiles(procfsRootDir, pids, procInfos, memInfo);
|
|
|
|
|
|
// crank up the process tree class.
|
|
|
ProcfsBasedProcessTree processTree =
|
|
|
createProcessTree("100", procfsRootDir.getAbsolutePath());
|
|
|
- // build the process tree.
|
|
|
- processTree.updateProcessTree();
|
|
|
+ setSmapsInProceTree(processTree, smapEnabled);
|
|
|
|
|
|
// verify cumulative memory
|
|
|
- Assert.assertEquals("Cumulative memory does not match",
|
|
|
- 700000L, processTree.getCumulativeVmem());
|
|
|
-
|
|
|
+ Assert.assertEquals("Cumulative memory does not match", 700000L,
|
|
|
+ processTree.getCumulativeVmem());
|
|
|
// write one more process as child of 100.
|
|
|
String[] newPids = { "500" };
|
|
|
setupPidDirs(procfsRootDir, newPids);
|
|
|
|
|
|
ProcessStatInfo[] newProcInfos = new ProcessStatInfo[1];
|
|
|
- newProcInfos[0] = new ProcessStatInfo(new String[]
|
|
|
- {"500", "proc5", "100", "100", "100", "500000", "500"});
|
|
|
- writeStatFiles(procfsRootDir, newPids, newProcInfos);
|
|
|
+ newProcInfos[0] =
|
|
|
+ new ProcessStatInfo(new String[] { "500", "proc5", "100", "100",
|
|
|
+ "100", "500000", "500" });
|
|
|
+ ProcessTreeSmapMemInfo[] newMemInfos = new ProcessTreeSmapMemInfo[1];
|
|
|
+ newMemInfos[0] = new ProcessTreeSmapMemInfo("500");
|
|
|
+ createMemoryMappingInfo(newMemInfos);
|
|
|
+ writeStatFiles(procfsRootDir, newPids, newProcInfos, newMemInfos);
|
|
|
|
|
|
// check memory includes the new process.
|
|
|
processTree.updateProcessTree();
|
|
|
Assert.assertEquals("Cumulative vmem does not include new process",
|
|
|
- 1200000L, processTree.getCumulativeVmem());
|
|
|
- long cumuRssMem = ProcfsBasedProcessTree.PAGE_SIZE > 0 ?
|
|
|
- 1200L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
|
|
|
- Assert.assertEquals("Cumulative rssmem does not include new process",
|
|
|
- cumuRssMem, processTree.getCumulativeRssmem());
|
|
|
+ 1200000L, processTree.getCumulativeVmem());
|
|
|
+ if (!smapEnabled) {
|
|
|
+ long cumuRssMem =
|
|
|
+ ProcfsBasedProcessTree.PAGE_SIZE > 0
|
|
|
+ ? 1200L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
|
|
|
+ Assert.assertEquals("Cumulative rssmem does not include new process",
|
|
|
+ cumuRssMem, processTree.getCumulativeRssmem());
|
|
|
+ } else {
|
|
|
+ Assert.assertEquals("Cumulative rssmem does not include new process",
|
|
|
+ 100 * KB_TO_BYTES * 4, processTree.getCumulativeRssmem());
|
|
|
+ }
|
|
|
|
|
|
// however processes older than 1 iteration will retain the older value
|
|
|
- Assert.assertEquals("Cumulative vmem shouldn't have included new process",
|
|
|
- 700000L, processTree.getCumulativeVmem(1));
|
|
|
- cumuRssMem = ProcfsBasedProcessTree.PAGE_SIZE > 0 ?
|
|
|
- 700L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
|
|
|
- Assert.assertEquals("Cumulative rssmem shouldn't have included new process",
|
|
|
- cumuRssMem, processTree.getCumulativeRssmem(1));
|
|
|
+ Assert.assertEquals(
|
|
|
+ "Cumulative vmem shouldn't have included new process", 700000L,
|
|
|
+ processTree.getCumulativeVmem(1));
|
|
|
+ if (!smapEnabled) {
|
|
|
+ long cumuRssMem =
|
|
|
+ ProcfsBasedProcessTree.PAGE_SIZE > 0
|
|
|
+ ? 700L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
|
|
|
+ Assert.assertEquals(
|
|
|
+ "Cumulative rssmem shouldn't have included new process", cumuRssMem,
|
|
|
+ processTree.getCumulativeRssmem(1));
|
|
|
+ } else {
|
|
|
+ Assert.assertEquals(
|
|
|
+ "Cumulative rssmem shouldn't have included new process",
|
|
|
+ 100 * KB_TO_BYTES * 3, processTree.getCumulativeRssmem(1));
|
|
|
+ }
|
|
|
|
|
|
// one more process
|
|
|
- newPids = new String[]{ "600" };
|
|
|
+ newPids = new String[] { "600" };
|
|
|
setupPidDirs(procfsRootDir, newPids);
|
|
|
|
|
|
newProcInfos = new ProcessStatInfo[1];
|
|
|
- newProcInfos[0] = new ProcessStatInfo(new String[]
|
|
|
- {"600", "proc6", "100", "100", "100", "600000", "600"});
|
|
|
- writeStatFiles(procfsRootDir, newPids, newProcInfos);
|
|
|
+ newProcInfos[0] =
|
|
|
+ new ProcessStatInfo(new String[] { "600", "proc6", "100", "100",
|
|
|
+ "100", "600000", "600" });
|
|
|
+ newMemInfos = new ProcessTreeSmapMemInfo[1];
|
|
|
+ newMemInfos[0] = new ProcessTreeSmapMemInfo("600");
|
|
|
+ createMemoryMappingInfo(newMemInfos);
|
|
|
+ writeStatFiles(procfsRootDir, newPids, newProcInfos, newMemInfos);
|
|
|
|
|
|
// refresh process tree
|
|
|
processTree.updateProcessTree();
|
|
|
|
|
|
// processes older than 2 iterations should be same as before.
|
|
|
- Assert.assertEquals("Cumulative vmem shouldn't have included new processes",
|
|
|
- 700000L, processTree.getCumulativeVmem(2));
|
|
|
- cumuRssMem = ProcfsBasedProcessTree.PAGE_SIZE > 0 ?
|
|
|
- 700L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
|
|
|
- Assert.assertEquals("Cumulative rssmem shouldn't have included new processes",
|
|
|
- cumuRssMem, processTree.getCumulativeRssmem(2));
|
|
|
+ Assert.assertEquals(
|
|
|
+ "Cumulative vmem shouldn't have included new processes", 700000L,
|
|
|
+ processTree.getCumulativeVmem(2));
|
|
|
+ if (!smapEnabled) {
|
|
|
+ long cumuRssMem =
|
|
|
+ ProcfsBasedProcessTree.PAGE_SIZE > 0
|
|
|
+ ? 700L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
|
|
|
+ Assert.assertEquals(
|
|
|
+ "Cumulative rssmem shouldn't have included new processes",
|
|
|
+ cumuRssMem, processTree.getCumulativeRssmem(2));
|
|
|
+ } else {
|
|
|
+ Assert.assertEquals(
|
|
|
+ "Cumulative rssmem shouldn't have included new processes",
|
|
|
+ 100 * KB_TO_BYTES * 3, processTree.getCumulativeRssmem(2));
|
|
|
+ }
|
|
|
|
|
|
// processes older than 1 iteration should not include new process,
|
|
|
// but include process 500
|
|
|
- Assert.assertEquals("Cumulative vmem shouldn't have included new processes",
|
|
|
- 1200000L, processTree.getCumulativeVmem(1));
|
|
|
- cumuRssMem = ProcfsBasedProcessTree.PAGE_SIZE > 0 ?
|
|
|
- 1200L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
|
|
|
- Assert.assertEquals("Cumulative rssmem shouldn't have included new processes",
|
|
|
- cumuRssMem, processTree.getCumulativeRssmem(1));
|
|
|
+ Assert.assertEquals(
|
|
|
+ "Cumulative vmem shouldn't have included new processes", 1200000L,
|
|
|
+ processTree.getCumulativeVmem(1));
|
|
|
+ if (!smapEnabled) {
|
|
|
+ long cumuRssMem =
|
|
|
+ ProcfsBasedProcessTree.PAGE_SIZE > 0
|
|
|
+ ? 1200L * ProcfsBasedProcessTree.PAGE_SIZE : 0L;
|
|
|
+ Assert.assertEquals(
|
|
|
+ "Cumulative rssmem shouldn't have included new processes",
|
|
|
+ cumuRssMem, processTree.getCumulativeRssmem(1));
|
|
|
+ } else {
|
|
|
+ Assert.assertEquals(
|
|
|
+ "Cumulative rssmem shouldn't have included new processes",
|
|
|
+ 100 * KB_TO_BYTES * 4, processTree.getCumulativeRssmem(1));
|
|
|
+ }
|
|
|
|
|
|
// no processes older than 3 iterations, this should be 0
|
|
|
- Assert.assertEquals("Getting non-zero vmem for processes older than 3 iterations",
|
|
|
- 0L, processTree.getCumulativeVmem(3));
|
|
|
- Assert.assertEquals("Getting non-zero rssmem for processes older than 3 iterations",
|
|
|
- 0L, processTree.getCumulativeRssmem(3));
|
|
|
+ Assert.assertEquals(
|
|
|
+ "Getting non-zero vmem for processes older than 3 iterations", 0L,
|
|
|
+ processTree.getCumulativeVmem(3));
|
|
|
+ Assert.assertEquals(
|
|
|
+ "Getting non-zero rssmem for processes older than 3 iterations", 0L,
|
|
|
+ processTree.getCumulativeRssmem(3));
|
|
|
+ Assert.assertEquals(
|
|
|
+ "Getting non-zero rssmem for processes older than 3 iterations", 0L,
|
|
|
+ processTree.getCumulativeRssmem(3));
|
|
|
} finally {
|
|
|
FileUtil.fullyDelete(procfsRootDir);
|
|
|
}
|
|
@@ -522,10 +661,12 @@ public class TestProcfsBasedProcessTree {
|
|
|
* Verifies ProcfsBasedProcessTree.checkPidPgrpidForMatch() in case of
|
|
|
* 'constructProcessInfo() returning null' by not writing stat file for the
|
|
|
* mock process
|
|
|
- * @throws IOException if there was a problem setting up the
|
|
|
- * fake procfs directories or files.
|
|
|
+ *
|
|
|
+ * @throws IOException
|
|
|
+ * if there was a problem setting up the fake procfs directories or
|
|
|
+ * files.
|
|
|
*/
|
|
|
- @Test (timeout = 30000)
|
|
|
+ @Test(timeout = 30000)
|
|
|
public void testDestroyProcessTree() throws IOException {
|
|
|
// test process
|
|
|
String pid = "100";
|
|
@@ -539,8 +680,8 @@ public class TestProcfsBasedProcessTree {
|
|
|
createProcessTree(pid, procfsRootDir.getAbsolutePath());
|
|
|
|
|
|
// Let us not create stat file for pid 100.
|
|
|
- Assert.assertTrue(ProcfsBasedProcessTree.checkPidPgrpidForMatch(
|
|
|
- pid, procfsRootDir.getAbsolutePath()));
|
|
|
+ Assert.assertTrue(ProcfsBasedProcessTree.checkPidPgrpidForMatch(pid,
|
|
|
+ procfsRootDir.getAbsolutePath()));
|
|
|
} finally {
|
|
|
FileUtil.fullyDelete(procfsRootDir);
|
|
|
}
|
|
@@ -551,9 +692,8 @@ public class TestProcfsBasedProcessTree {
|
|
|
*
|
|
|
* @throws IOException
|
|
|
*/
|
|
|
- @Test (timeout = 30000)
|
|
|
- public void testProcessTreeDump()
|
|
|
- throws IOException {
|
|
|
+ @Test(timeout = 30000)
|
|
|
+ public void testProcessTreeDump() throws IOException {
|
|
|
|
|
|
String[] pids = { "100", "200", "300", "400", "500", "600" };
|
|
|
|
|
@@ -566,18 +706,32 @@ public class TestProcfsBasedProcessTree {
|
|
|
int numProcesses = pids.length;
|
|
|
// Processes 200, 300, 400 and 500 are descendants of 100. 600 is not.
|
|
|
ProcessStatInfo[] procInfos = new ProcessStatInfo[numProcesses];
|
|
|
- procInfos[0] = new ProcessStatInfo(new String[] {
|
|
|
- "100", "proc1", "1", "100", "100", "100000", "100", "1000", "200"});
|
|
|
- procInfos[1] = new ProcessStatInfo(new String[] {
|
|
|
- "200", "proc2", "100", "100", "100", "200000", "200", "2000", "400"});
|
|
|
- procInfos[2] = new ProcessStatInfo(new String[] {
|
|
|
- "300", "proc3", "200", "100", "100", "300000", "300", "3000", "600"});
|
|
|
- procInfos[3] = new ProcessStatInfo(new String[] {
|
|
|
- "400", "proc4", "200", "100", "100", "400000", "400", "4000", "800"});
|
|
|
- procInfos[4] = new ProcessStatInfo(new String[] {
|
|
|
- "500", "proc5", "400", "100", "100", "400000", "400", "4000", "800"});
|
|
|
- procInfos[5] = new ProcessStatInfo(new String[] {
|
|
|
- "600", "proc6", "1", "1", "1", "400000", "400", "4000", "800"});
|
|
|
+ procInfos[0] =
|
|
|
+ new ProcessStatInfo(new String[] { "100", "proc1", "1", "100", "100",
|
|
|
+ "100000", "100", "1000", "200" });
|
|
|
+ procInfos[1] =
|
|
|
+ new ProcessStatInfo(new String[] { "200", "proc2", "100", "100",
|
|
|
+ "100", "200000", "200", "2000", "400" });
|
|
|
+ procInfos[2] =
|
|
|
+ new ProcessStatInfo(new String[] { "300", "proc3", "200", "100",
|
|
|
+ "100", "300000", "300", "3000", "600" });
|
|
|
+ procInfos[3] =
|
|
|
+ new ProcessStatInfo(new String[] { "400", "proc4", "200", "100",
|
|
|
+ "100", "400000", "400", "4000", "800" });
|
|
|
+ procInfos[4] =
|
|
|
+ new ProcessStatInfo(new String[] { "500", "proc5", "400", "100",
|
|
|
+ "100", "400000", "400", "4000", "800" });
|
|
|
+ procInfos[5] =
|
|
|
+ new ProcessStatInfo(new String[] { "600", "proc6", "1", "1", "1",
|
|
|
+ "400000", "400", "4000", "800" });
|
|
|
+
|
|
|
+ ProcessTreeSmapMemInfo[] memInfos = new ProcessTreeSmapMemInfo[6];
|
|
|
+ memInfos[0] = new ProcessTreeSmapMemInfo("100");
|
|
|
+ memInfos[1] = new ProcessTreeSmapMemInfo("200");
|
|
|
+ memInfos[2] = new ProcessTreeSmapMemInfo("300");
|
|
|
+ memInfos[3] = new ProcessTreeSmapMemInfo("400");
|
|
|
+ memInfos[4] = new ProcessTreeSmapMemInfo("500");
|
|
|
+ memInfos[5] = new ProcessTreeSmapMemInfo("600");
|
|
|
|
|
|
String[] cmdLines = new String[numProcesses];
|
|
|
cmdLines[0] = "proc1 arg1 arg2";
|
|
@@ -587,11 +741,12 @@ public class TestProcfsBasedProcessTree {
|
|
|
cmdLines[4] = "proc5 arg9 arg10";
|
|
|
cmdLines[5] = "proc6 arg11 arg12";
|
|
|
|
|
|
- writeStatFiles(procfsRootDir, pids, procInfos);
|
|
|
+ createMemoryMappingInfo(memInfos);
|
|
|
+ writeStatFiles(procfsRootDir, pids, procInfos, memInfos);
|
|
|
writeCmdLineFiles(procfsRootDir, pids, cmdLines);
|
|
|
|
|
|
- ProcfsBasedProcessTree processTree = createProcessTree(
|
|
|
- "100", procfsRootDir.getAbsolutePath());
|
|
|
+ ProcfsBasedProcessTree processTree =
|
|
|
+ createProcessTree("100", procfsRootDir.getAbsolutePath());
|
|
|
// build the process tree.
|
|
|
processTree.updateProcessTree();
|
|
|
|
|
@@ -600,50 +755,52 @@ public class TestProcfsBasedProcessTree {
|
|
|
|
|
|
LOG.info("Process-tree dump follows: \n" + processTreeDump);
|
|
|
Assert.assertTrue("Process-tree dump doesn't start with a proper header",
|
|
|
- processTreeDump.startsWith("\t|- PID PPID PGRPID SESSID CMD_NAME " +
|
|
|
- "USER_MODE_TIME(MILLIS) SYSTEM_TIME(MILLIS) VMEM_USAGE(BYTES) " +
|
|
|
- "RSSMEM_USAGE(PAGES) FULL_CMD_LINE\n"));
|
|
|
+ processTreeDump.startsWith("\t|- PID PPID PGRPID SESSID CMD_NAME "
|
|
|
+ + "USER_MODE_TIME(MILLIS) SYSTEM_TIME(MILLIS) VMEM_USAGE(BYTES) "
|
|
|
+ + "RSSMEM_USAGE(PAGES) FULL_CMD_LINE\n"));
|
|
|
for (int i = 0; i < 5; i++) {
|
|
|
ProcessStatInfo p = procInfos[i];
|
|
|
Assert.assertTrue(
|
|
|
- "Process-tree dump doesn't contain the cmdLineDump of process "
|
|
|
- + p.pid, processTreeDump.contains("\t|- " + p.pid + " "
|
|
|
- + p.ppid + " " + p.pgrpId + " " + p.session + " (" + p.name
|
|
|
- + ") " + p.utime + " " + p.stime + " " + p.vmem + " "
|
|
|
- + p.rssmemPage + " " + cmdLines[i]));
|
|
|
+ "Process-tree dump doesn't contain the cmdLineDump of process "
|
|
|
+ + p.pid,
|
|
|
+ processTreeDump.contains("\t|- " + p.pid + " " + p.ppid + " "
|
|
|
+ + p.pgrpId + " " + p.session + " (" + p.name + ") " + p.utime
|
|
|
+ + " " + p.stime + " " + p.vmem + " " + p.rssmemPage + " "
|
|
|
+ + cmdLines[i]));
|
|
|
}
|
|
|
|
|
|
// 600 should not be in the dump
|
|
|
ProcessStatInfo p = procInfos[5];
|
|
|
Assert.assertFalse(
|
|
|
- "Process-tree dump shouldn't contain the cmdLineDump of process "
|
|
|
- + p.pid, processTreeDump.contains("\t|- " + p.pid + " " + p.ppid
|
|
|
- + " " + p.pgrpId + " " + p.session + " (" + p.name + ") "
|
|
|
- + p.utime + " " + p.stime + " " + p.vmem + " " + cmdLines[5]));
|
|
|
+ "Process-tree dump shouldn't contain the cmdLineDump of process "
|
|
|
+ + p.pid,
|
|
|
+ processTreeDump.contains("\t|- " + p.pid + " " + p.ppid + " "
|
|
|
+ + p.pgrpId + " " + p.session + " (" + p.name + ") " + p.utime + " "
|
|
|
+ + p.stime + " " + p.vmem + " " + cmdLines[5]));
|
|
|
} finally {
|
|
|
FileUtil.fullyDelete(procfsRootDir);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
protected static boolean isSetsidAvailable() {
|
|
|
- ShellCommandExecutor shexec = null;
|
|
|
- boolean setsidSupported = true;
|
|
|
- try {
|
|
|
- String[] args = {"setsid", "bash", "-c", "echo $$"};
|
|
|
- shexec = new ShellCommandExecutor(args);
|
|
|
- shexec.execute();
|
|
|
- } catch (IOException ioe) {
|
|
|
- LOG.warn("setsid is not available on this machine. So not using it.");
|
|
|
- setsidSupported = false;
|
|
|
- } finally { // handle the exit code
|
|
|
- LOG.info("setsid exited with exit code " + shexec.getExitCode());
|
|
|
- }
|
|
|
- return setsidSupported;
|
|
|
+ ShellCommandExecutor shexec = null;
|
|
|
+ boolean setsidSupported = true;
|
|
|
+ try {
|
|
|
+ String[] args = { "setsid", "bash", "-c", "echo $$" };
|
|
|
+ shexec = new ShellCommandExecutor(args);
|
|
|
+ shexec.execute();
|
|
|
+ } catch (IOException ioe) {
|
|
|
+ LOG.warn("setsid is not available on this machine. So not using it.");
|
|
|
+ setsidSupported = false;
|
|
|
+ } finally { // handle the exit code
|
|
|
+ LOG.info("setsid exited with exit code " + shexec.getExitCode());
|
|
|
+ }
|
|
|
+ return setsidSupported;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Is the root-process alive?
|
|
|
- * Used only in tests.
|
|
|
+ * Is the root-process alive? Used only in tests.
|
|
|
+ *
|
|
|
* @return true if the root-process is alive, false otherwise.
|
|
|
*/
|
|
|
private static boolean isAlive(String pid) {
|
|
@@ -662,16 +819,16 @@ public class TestProcfsBasedProcessTree {
|
|
|
|
|
|
private static void sendSignal(String pid, int signal) throws IOException {
|
|
|
ShellCommandExecutor shexec = null;
|
|
|
- String[] arg = { "kill", "-" + signal, pid };
|
|
|
- shexec = new ShellCommandExecutor(arg);
|
|
|
+ String[] arg = { "kill", "-" + signal, pid };
|
|
|
+ shexec = new ShellCommandExecutor(arg);
|
|
|
shexec.execute();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Is any of the subprocesses in the process-tree alive?
|
|
|
- * Used only in tests.
|
|
|
- * @return true if any of the processes in the process-tree is
|
|
|
- * alive, false otherwise.
|
|
|
+ * Is any of the subprocesses in the process-tree alive? Used only in tests.
|
|
|
+ *
|
|
|
+ * @return true if any of the processes in the process-tree is alive, false
|
|
|
+ * otherwise.
|
|
|
*/
|
|
|
private static boolean isAnyProcessInTreeAlive(
|
|
|
ProcfsBasedProcessTree processTree) {
|
|
@@ -685,11 +842,13 @@ public class TestProcfsBasedProcessTree {
|
|
|
|
|
|
/**
|
|
|
* Create a directory to mimic the procfs file system's root.
|
|
|
- * @param procfsRootDir root directory to create.
|
|
|
- * @throws IOException if could not delete the procfs root directory
|
|
|
+ *
|
|
|
+ * @param procfsRootDir
|
|
|
+ * root directory to create.
|
|
|
+ * @throws IOException
|
|
|
+ * if could not delete the procfs root directory
|
|
|
*/
|
|
|
- public static void setupProcfsRootDir(File procfsRootDir)
|
|
|
- throws IOException {
|
|
|
+ public static void setupProcfsRootDir(File procfsRootDir) throws IOException {
|
|
|
// cleanup any existing process root dir.
|
|
|
if (procfsRootDir.exists()) {
|
|
|
Assert.assertTrue(FileUtil.fullyDelete(procfsRootDir));
|
|
@@ -701,18 +860,22 @@ public class TestProcfsBasedProcessTree {
|
|
|
|
|
|
/**
|
|
|
* Create PID directories under the specified procfs root directory
|
|
|
- * @param procfsRootDir root directory of procfs file system
|
|
|
- * @param pids the PID directories to create.
|
|
|
- * @throws IOException If PID dirs could not be created
|
|
|
+ *
|
|
|
+ * @param procfsRootDir
|
|
|
+ * root directory of procfs file system
|
|
|
+ * @param pids
|
|
|
+ * the PID directories to create.
|
|
|
+ * @throws IOException
|
|
|
+ * If PID dirs could not be created
|
|
|
*/
|
|
|
public static void setupPidDirs(File procfsRootDir, String[] pids)
|
|
|
- throws IOException {
|
|
|
+ throws IOException {
|
|
|
for (String pid : pids) {
|
|
|
File pidDir = new File(procfsRootDir, pid);
|
|
|
pidDir.mkdir();
|
|
|
if (!pidDir.exists()) {
|
|
|
- throw new IOException ("couldn't make process directory under " +
|
|
|
- "fake procfs");
|
|
|
+ throw new IOException("couldn't make process directory under "
|
|
|
+ + "fake procfs");
|
|
|
} else {
|
|
|
LOG.info("created pid dir");
|
|
|
}
|
|
@@ -720,43 +883,67 @@ public class TestProcfsBasedProcessTree {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Write stat files under the specified pid directories with data
|
|
|
- * setup in the corresponding ProcessStatInfo objects
|
|
|
- * @param procfsRootDir root directory of procfs file system
|
|
|
- * @param pids the PID directories under which to create the stat file
|
|
|
- * @param procs corresponding ProcessStatInfo objects whose data should be
|
|
|
- * written to the stat files.
|
|
|
- * @throws IOException if stat files could not be written
|
|
|
+ * Write stat files under the specified pid directories with data setup in the
|
|
|
+ * corresponding ProcessStatInfo objects
|
|
|
+ *
|
|
|
+ * @param procfsRootDir
|
|
|
+ * root directory of procfs file system
|
|
|
+ * @param pids
|
|
|
+ * the PID directories under which to create the stat file
|
|
|
+ * @param procs
|
|
|
+ * corresponding ProcessStatInfo objects whose data should be written
|
|
|
+ * to the stat files.
|
|
|
+ * @throws IOException
|
|
|
+ * if stat files could not be written
|
|
|
*/
|
|
|
public static void writeStatFiles(File procfsRootDir, String[] pids,
|
|
|
- ProcessStatInfo[] procs) throws IOException {
|
|
|
- for (int i=0; i<pids.length; i++) {
|
|
|
+ ProcessStatInfo[] procs, ProcessTreeSmapMemInfo[] smaps)
|
|
|
+ throws IOException {
|
|
|
+ for (int i = 0; i < pids.length; i++) {
|
|
|
File statFile =
|
|
|
new File(new File(procfsRootDir, pids[i]),
|
|
|
- ProcfsBasedProcessTree.PROCFS_STAT_FILE);
|
|
|
+ ProcfsBasedProcessTree.PROCFS_STAT_FILE);
|
|
|
BufferedWriter bw = null;
|
|
|
try {
|
|
|
FileWriter fw = new FileWriter(statFile);
|
|
|
bw = new BufferedWriter(fw);
|
|
|
bw.write(procs[i].getStatLine());
|
|
|
- LOG.info("wrote stat file for " + pids[i] +
|
|
|
- " with contents: " + procs[i].getStatLine());
|
|
|
+ LOG.info("wrote stat file for " + pids[i] + " with contents: "
|
|
|
+ + procs[i].getStatLine());
|
|
|
} finally {
|
|
|
// not handling exception - will throw an error and fail the test.
|
|
|
if (bw != null) {
|
|
|
bw.close();
|
|
|
}
|
|
|
}
|
|
|
+ if (smaps != null) {
|
|
|
+ File smapFile =
|
|
|
+ new File(new File(procfsRootDir, pids[i]),
|
|
|
+ ProcfsBasedProcessTree.SMAPS);
|
|
|
+ bw = null;
|
|
|
+ try {
|
|
|
+ FileWriter fw = new FileWriter(smapFile);
|
|
|
+ bw = new BufferedWriter(fw);
|
|
|
+ bw.write(smaps[i].toString());
|
|
|
+ bw.flush();
|
|
|
+ LOG.info("wrote smap file for " + pids[i] + " with contents: "
|
|
|
+ + smaps[i].toString());
|
|
|
+ } finally {
|
|
|
+ // not handling exception - will throw an error and fail the test.
|
|
|
+ if (bw != null) {
|
|
|
+ bw.close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private static void writeCmdLineFiles(File procfsRootDir, String[] pids,
|
|
|
- String[] cmdLines)
|
|
|
- throws IOException {
|
|
|
+ String[] cmdLines) throws IOException {
|
|
|
for (int i = 0; i < pids.length; i++) {
|
|
|
File statFile =
|
|
|
new File(new File(procfsRootDir, pids[i]),
|
|
|
- ProcfsBasedProcessTree.PROCFS_CMDLINE_FILE);
|
|
|
+ ProcfsBasedProcessTree.PROCFS_CMDLINE_FILE);
|
|
|
BufferedWriter bw = null;
|
|
|
try {
|
|
|
bw = new BufferedWriter(new FileWriter(statFile));
|