pax_global_header00006660000000000000000000000064116724771220014523gustar00rootroot0000000000000052 comment=80f12d088a43fee2fb09732cd7e1bab15cd45456 jenkinsci-extras-memory-monitor-b9edd8f/000077500000000000000000000000001167247712200205665ustar00rootroot00000000000000jenkinsci-extras-memory-monitor-b9edd8f/pom.xml000066400000000000000000000046131167247712200221070ustar00rootroot00000000000000 org.jenkins-ci jenkins 1.21 4.0.0 memory-monitor 1.7 memory-monitor Code for monitoring memory/swap usage maven-jar-plugin org.jvnet.hudson.MemoryMonitor maven-assembly-plugin jar-with-dependencies org.jvnet.hudson.MemoryMonitor attached package net.java.dev.jna jna 3.0.3-patch-1 junit junit 3.8.1 test MIT License http://jenkins-ci.org/mit-license scm:git:git://github.com/jenkinsci/extras-memory-monitor.git scm:git:git@github.com:jenkinsci/extras-memory-monitor.git https://github.com/jenkinsci/extras-memory-monitor m.g.o-public http://maven.glassfish.org/content/groups/public/ jenkinsci-extras-memory-monitor-b9edd8f/src/000077500000000000000000000000001167247712200213555ustar00rootroot00000000000000jenkinsci-extras-memory-monitor-b9edd8f/src/main/000077500000000000000000000000001167247712200223015ustar00rootroot00000000000000jenkinsci-extras-memory-monitor-b9edd8f/src/main/java/000077500000000000000000000000001167247712200232225ustar00rootroot00000000000000jenkinsci-extras-memory-monitor-b9edd8f/src/main/java/org/000077500000000000000000000000001167247712200240115ustar00rootroot00000000000000jenkinsci-extras-memory-monitor-b9edd8f/src/main/java/org/jvnet/000077500000000000000000000000001167247712200251375ustar00rootroot00000000000000jenkinsci-extras-memory-monitor-b9edd8f/src/main/java/org/jvnet/hudson/000077500000000000000000000000001167247712200264375ustar00rootroot00000000000000AbstractMemoryMonitorImpl.java000066400000000000000000000037331167247712200343570ustar00rootroot00000000000000jenkinsci-extras-memory-monitor-b9edd8f/src/main/java/org/jvnet/hudson/* * The MIT License * * Copyright (c) 2008-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.jvnet.hudson; /** * @author Kohsuke Kawaguchi */ abstract class AbstractMemoryMonitorImpl extends MemoryMonitor { protected long parse(String token) { token = token.toLowerCase().trim(); long multiplier = 1; if(token.endsWith("b")) token = cutTail(token); if(token.endsWith("k")) { multiplier = 1024L; token = cutTail(token); } if(token.endsWith("m")) { multiplier = 1024L*1024; token = cutTail(token); } if(token.endsWith("g")) { multiplier = 1024L*1024*1024; token = cutTail(token); } return (long)(Float.parseFloat(token)*multiplier); } protected String cutTail(String token) { return token.substring(0,token.length()-1); } } jenkinsci-extras-memory-monitor-b9edd8f/src/main/java/org/jvnet/hudson/MemoryMonitor.java000066400000000000000000000070071167247712200321260ustar00rootroot00000000000000/* * The MIT License * * Copyright (c) 2008-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.jvnet.hudson; import java.io.File; import java.io.IOException; import java.util.logging.ConsoleHandler; import java.util.logging.Level; import java.util.logging.Logger; /** * Encapsulates how to compute {@link MemoryUsage}. * * @author Kohsuke Kawaguchi */ public abstract class MemoryMonitor { /** * Obtains the memory usage statistics. * * @return * always non-null object. * @throws IOException * If the computation fails for some reason. */ public abstract MemoryUsage monitor() throws IOException; /** * Obtains the {@link MemoryMonitor} implementation suitable * for the current platform. * * @throws IOException * if no applicable implementation is found. */ public static MemoryMonitor get() throws IOException { if(INSTANCE==null) INSTANCE = obtain(); return INSTANCE; } private static MemoryMonitor obtain() throws IOException { if(File.pathSeparatorChar==';') return new Windows(); if(new File("/proc/meminfo").exists()) return new ProcMemInfo(); // Linux has this. Exactly since when, I don't know. // is 'top' available? if so, use it try { Top top = new Top(); top.monitor(); return top; } catch (Throwable _) { // fall through next } // Solaris? try { Solaris solaris = new Solaris(); solaris.monitor(); return solaris; } catch(Throwable _) { // next } throw new IOException(String.format("No suitable implementation found: os.name=%s os.arch=%s sun.arch.data.model=%s", System.getProperty("os.name"),System.getProperty("os.arch"),System.getProperty("sun.arch.data.model"))); } /** * Main for test */ public static void main(String[] args) throws Exception { Logger l = Logger.getLogger(MemoryMonitor.class.getPackage().getName()); l.setLevel(Level.FINE); ConsoleHandler h = new ConsoleHandler(); h.setLevel(Level.FINE); l.addHandler(h); MemoryMonitor t = get(); System.out.println("implementation is "+t.getClass().getName()); System.out.println(t.monitor()); } private static volatile MemoryMonitor INSTANCE = null; } jenkinsci-extras-memory-monitor-b9edd8f/src/main/java/org/jvnet/hudson/MemoryUsage.java000066400000000000000000000056421167247712200315460ustar00rootroot00000000000000/* * The MIT License * * Copyright (c) 2008-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.jvnet.hudson; import java.io.IOException; import java.io.Serializable; /** * Memory usage. Immutable. * * @author Kohsuke Kawaguchi */ public class MemoryUsage implements Serializable { /** * Total physical memory of the system, in bytes. * -1 if unknown. */ public final long totalPhysicalMemory; /** * Of the total physical memory of the system, available bytes. * -1 if unknown. */ public final long availablePhysicalMemory; /** * Total number of swap space in bytes. * -1 if unknown. */ public final long totalSwapSpace; /** * Available swap space in bytes. * -1 if unknown. */ public final long availableSwapSpace; public MemoryUsage(long totalPhysicalMemory, long availablePhysicalMemory, long totalSwapSpace, long availableSwapSpace) { this.totalPhysicalMemory = totalPhysicalMemory; this.availablePhysicalMemory = availablePhysicalMemory; this.totalSwapSpace = totalSwapSpace; this.availableSwapSpace = availableSwapSpace; } MemoryUsage(long[] v) throws IOException { this(v[0],v[1],v[2],v[3]); if(!hasData(v)) throw new IOException("No data available"); } public String toString() { return String.format("Memory:%d/%dMB Swap:%d/%dMB", toMB(availablePhysicalMemory), toMB(totalPhysicalMemory), toMB(availableSwapSpace), toMB(totalSwapSpace)); } private static long toMB(long l) { return l/(1024*1024); } /*package*/ static boolean hasData(long[] values) { for (long v : values) if(v!=-1) return true; return false; } private static final long serialVersionUID = 1L; } jenkinsci-extras-memory-monitor-b9edd8f/src/main/java/org/jvnet/hudson/ProcMemInfo.java000066400000000000000000000072021167247712200314610ustar00rootroot00000000000000/* * The MIT License * * Copyright (c) 2008-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.jvnet.hudson; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.Arrays; /** * {@link MemoryMonitor} implementation that relies in /proc/meminfo * @author Kohsuke Kawaguchi */ final class ProcMemInfo extends MemoryMonitor { public MemoryUsage monitor() throws IOException { BufferedReader r = new BufferedReader(new FileReader("/proc/meminfo")); try { long[] values = new long[4]; Arrays.fill(values,-1); String line; while((line=r.readLine())!=null) { for( int i=0; i/proc/meminfo that we care about. */ private static final String[] HEADERS = new String[] { "MemTotal:", "MemFree:", "SwapTotal:", "SwapFree:" }; /** * I've only seen "1234 kB" notation, but just to be safe. */ private static final Suffix[] SUFFIXES = new Suffix[] { new Suffix("KB",1024), new Suffix("MB",1024*1024), new Suffix("GB",1024*1024*1024) }; private static final Suffix NONE = new Suffix("",1); private static class Suffix { final String name; final long multiplier; private Suffix(String name, long multiplier) { this.name = name; this.multiplier = multiplier; } static Suffix find(String line) { for (Suffix s : SUFFIXES) if( line.substring(line.length()-s.name.length()).equalsIgnoreCase(s.name) ) return s; return NONE; } } } jenkinsci-extras-memory-monitor-b9edd8f/src/main/java/org/jvnet/hudson/Solaris.java000066400000000000000000000106401167247712200307170ustar00rootroot00000000000000/* * The MIT License * * Copyright (c) 2008-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.jvnet.hudson; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * For Solaris, where top(1) is an optional install. * * @author Kohsuke Kawaguchi */ public class Solaris extends AbstractMemoryMonitorImpl { @Override public MemoryUsage monitor() throws IOException { long[] v = getSwap(); return new MemoryUsage( getTotalPhysicalMemory(), getAvailablePhysicalMemory(), v[0],v[1] ); } private long getTotalPhysicalMemory() throws IOException { Process proc = startProcess("/usr/sbin/prtdiag"); BufferedReader r = new BufferedReader(new InputStreamReader(proc.getInputStream())); try { String line; while ((line=r.readLine())!=null) { if (line.contains("Memory size:")) { line = line.substring(line.indexOf(':')+1).trim(); return parse(line); } } return -1; } finally { r.close(); } } private long getAvailablePhysicalMemory() throws IOException { Process proc = startProcess("vmstat"); BufferedReader r = new BufferedReader(new InputStreamReader(proc.getInputStream())); try { String line; while ((line=r.readLine())!=null) { if (NUMBER_ONLY.matcher(line).matches()) { return Long.parseLong(line.trim().split(" +")[4])*1024; } } return -1; } finally { r.close(); } } /** * Returns total/availablae. */ private long[] getSwap() throws IOException { long[] v = new long[]{-1,-1}; Process proc = startProcess("/usr/sbin/swap","-s"); BufferedReader r = new BufferedReader(new InputStreamReader(proc.getInputStream())); /* output $ uname -a; swap -s SunOS kohsuke2 5.9 Generic_112233-12 sun4u sparc SUNW,Sun-Blade-2500 Solaris total: 800296k bytes allocated + 181784k reserved = 982080k used, 6014528k available */ try { String line = r.readLine().toLowerCase(); Matcher m = USED_SWAP.matcher(line); if (m.find()) { v[0] = Long.parseLong(m.group(1))*1024; } m = AVAILABLE_SWAP.matcher(line); if (m.find()) { v[1] = Long.parseLong(m.group(1))*1024; } // we want total/available, not used/available. if (v[0]!=-1 && v[1]!=-1) v[0] += v[1]; return v; } finally { r.close(); } } private Process startProcess(String... cmd) throws IOException { ProcessBuilder pb = new ProcessBuilder(cmd); pb.redirectErrorStream(true); Process proc = pb.start(); proc.getOutputStream().close(); return proc; } private static final Pattern NUMBER_ONLY = Pattern.compile("[0-9 ]+"); private static final Pattern USED_SWAP = Pattern.compile(" ([0-9]+)k used"); private static final Pattern AVAILABLE_SWAP = Pattern.compile(" ([0-9]+)k available"); } jenkinsci-extras-memory-monitor-b9edd8f/src/main/java/org/jvnet/hudson/Top.java000066400000000000000000000307721167247712200300550ustar00rootroot00000000000000/* * The MIT License * * Copyright (c) 2008-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, Stephen Wolf * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.jvnet.hudson; import java.io.IOException; import java.io.InputStreamReader; import java.io.BufferedReader; import java.util.List; import java.util.ArrayList; import java.util.Arrays; import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.regex.Matcher; /** * {@link MemoryMonitor} that parses the output from the top command. * @author Kohsuke Kawaguchi */ final class Top extends AbstractMemoryMonitorImpl { private boolean macOsTopFailed; private boolean plainTopFailed; public MemoryUsage monitor() throws IOException { if(!macOsTopFailed) { // MacOS X doesn't understand the -b option (for batch mode), // moreover to run it in a non-terminal one needs to use the "-l1" option // and to view the swap usage also add the "-S" option. // This fails probably anywhere except on MacOS X. MemoryUsage r = monitor("top","-S","-l1"); if(r!=null) return r; // if this failed, don't make the same mistake again LOGGER.fine("failed: top -S -l1"); macOsTopFailed=true; } if(!plainTopFailed) { // MacOS X doesn't understand the -b option (for batch mode), // so first try without any argument. This fails on Ubuntu. MemoryUsage r = monitor("top"); if(r!=null) return r; // if this failed, don't make the same mistake again LOGGER.fine("failed: top"); plainTopFailed=true; } // if 'top' w/o any argument fails to obtain data, like Ubuntu, // then run with the -b option in the hope that it works. MemoryUsage r = monitor("top","-b"); if(r!=null) return r; LOGGER.fine("failed: top -b"); // out of luck. bail out throw new IOException("'top' unavailable"); } private MemoryUsage monitor(String... args) throws IOException { ProcessBuilder pb = new ProcessBuilder(args); pb.redirectErrorStream(true); Process proc = pb.start(); proc.getOutputStream().close(); // obtain first 16 lines, then kill 'top' // output is converted to lower case to simplify matching. List lines = new ArrayList(); { BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream())); String line; while((line=in.readLine())!=null && lines.size()<16) { line = ESCAPE_SEQUENCE.matcher(line.toLowerCase()).replaceAll(""); LOGGER.fine("| "+line); lines.add(line); } proc.destroy(); in.close(); } long[] values = new long[6]; Arrays.fill(values,-1); OUTER: for( int i=0; i * JNA requires that the class and interface be public. * * @author Kohsuke Kawaguchi */ public final class Windows extends MemoryMonitor { public MemoryUsage monitor() { MEMORYSTATUSEX mse = new MEMORYSTATUSEX(); Kernel32.INSTANCE.GlobalMemoryStatusEx(mse); mse.read(); return new MemoryUsage( mse.ullTotalPhys, mse.ullAvailPhys, mse.ullTotalPageFile, mse.ullAvailPageFile); } public interface Kernel32 extends StdCallLibrary { boolean GlobalMemoryStatusEx(MEMORYSTATUSEX p); Kernel32 INSTANCE = (Kernel32)Native.loadLibrary("kernel32",Kernel32.class); } public static final class MEMORYSTATUSEX extends Structure { public int dwLength = size(); public int dwMemoryLoad; public long ullTotalPhys; public long ullAvailPhys; public long ullTotalPageFile; public long ullAvailPageFile; public long ullTotalVirtual; public long ullAvailVirtual; public long ullAvailExtendedVirtual; } } jenkinsci-extras-memory-monitor-b9edd8f/src/test/000077500000000000000000000000001167247712200223345ustar00rootroot00000000000000jenkinsci-extras-memory-monitor-b9edd8f/src/test/java/000077500000000000000000000000001167247712200232555ustar00rootroot00000000000000jenkinsci-extras-memory-monitor-b9edd8f/src/test/java/org/000077500000000000000000000000001167247712200240445ustar00rootroot00000000000000jenkinsci-extras-memory-monitor-b9edd8f/src/test/java/org/jvnet/000077500000000000000000000000001167247712200251725ustar00rootroot00000000000000jenkinsci-extras-memory-monitor-b9edd8f/src/test/java/org/jvnet/hudson/000077500000000000000000000000001167247712200264725ustar00rootroot00000000000000jenkinsci-extras-memory-monitor-b9edd8f/src/test/java/org/jvnet/hudson/MemoryMonitorTest.java000066400000000000000000000007101167247712200330130ustar00rootroot00000000000000package org.jvnet.hudson; import junit.framework.TestCase; import java.io.IOException; /** * @author Kohsuke Kawaguchi */ public class MemoryMonitorTest extends TestCase { public void test1() throws IOException { MemoryUsage data = MemoryMonitor.get().monitor(); System.out.println(data); } public void test2() throws IOException { MemoryUsage data = new Top().monitor(); System.out.println(data); } }