diff --git a/src/zutil/net/ThroughputCalculator.java b/src/zutil/net/ThroughputCalculator.java new file mode 100644 index 0000000..f883524 --- /dev/null +++ b/src/zutil/net/ThroughputCalculator.java @@ -0,0 +1,51 @@ +package zutil.net; + +/** + * Created by Ziver Koc + */ +public class ThroughputCalculator { + public static final float UPDATES_PER_SEC = 1; + public static final double NANOSEC_PER_SECOND = 1000000000.0; + + private boolean updated; + private double throughput; + private long previousTimeStamp; + private long data_amount; + private long total_data_amount; + private float frequency = UPDATES_PER_SEC; + + public void setTotalHandledData(long bytes){ + setHandledData(bytes - total_data_amount); + total_data_amount = bytes; + } + public void setHandledData(long bytes){ + long currentTimeStamp = System.nanoTime(); + data_amount += bytes; + if(currentTimeStamp - (NANOSEC_PER_SECOND/frequency) > previousTimeStamp) { + throughput = data_amount / ((currentTimeStamp - previousTimeStamp) / NANOSEC_PER_SECOND); + previousTimeStamp = currentTimeStamp; + data_amount = 0; + updated = true; + } + } + + public double getByteThroughput(){ + setHandledData(0); // Update throughput + updated = false; + return throughput; + } + public double getBitThroughput(){ + return getByteThroughput()*8; + } + + public boolean isUpdated(){ + return updated; + } + + public void setFrequency(float frequency) { + if(frequency < 0) + this.frequency = UPDATES_PER_SEC; + else + this.frequency = frequency; + } +} diff --git a/src/zutil/osal/app/linux/AptGet.java b/src/zutil/osal/app/linux/AptGet.java new file mode 100644 index 0000000..dcdd0a0 --- /dev/null +++ b/src/zutil/osal/app/linux/AptGet.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014 Ziver + * + * 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 zutil.osal.app.linux; + +import zutil.log.LogUtil; +import zutil.osal.OSAbstractionLayer; + +import java.io.IOException; +import java.util.logging.Logger; + +/** + * Created by Ziver on 2014-11-09. + */ +public class AptGet { + public static final Logger log = LogUtil.getLogger(); + + private static long updateTimestamp; + + public static void install(String pkg) { + update(); + OSAbstractionLayer.runCommand("apt-get install " + pkg); + } + + public static void update(){ + // Only run every 5 min + if(updateTimestamp + 1000*60*5 >System.currentTimeMillis()){ + OSAbstractionLayer.runCommand("apt-get update"); + } + } + + public static void purge(String pkg) { + OSAbstractionLayer.runCommand("apt-get --purge remove " + pkg); + } +} diff --git a/src/zutil/osal/app/linux/ProcDiskstats.java b/src/zutil/osal/app/linux/ProcDiskstats.java new file mode 100644 index 0000000..de92104 --- /dev/null +++ b/src/zutil/osal/app/linux/ProcDiskstats.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2015 ezivkoc + * + * 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 zutil.osal.app.linux; + +import zutil.StringUtil; +import zutil.io.MultiPrintStream; +import zutil.log.LogUtil; +import zutil.net.ThroughputCalculator; + +import java.io.*; +import java.util.HashMap; +import java.util.Iterator; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Documentation from https://www.kernel.org/doc/Documentation/block/stat.txt + * + * Created by ezivkoc on 2015-05-19. + */ +public class ProcDiskstats { + private static final Logger log = LogUtil.getLogger(); + private static final String PROC_PATH = "/proc/diskstats"; + private static final int TTL = 500; // update stats every 0.5 second + + private static HashMap hdds = new HashMap(); + private static long updateTimestamp; + + + private synchronized static void update(){ + if(System.currentTimeMillis() - updateTimestamp < TTL) + return; + updateTimestamp = System.currentTimeMillis(); + try { + BufferedReader in = new BufferedReader(new FileReader(PROC_PATH)); + String line = null; + while((line=in.readLine()) != null){ + String[] str = line.trim().split("\\W+", 4); + if(str.length >= 4) { + String devName = str[2]; + if(!hdds.containsKey(devName)){ + HddStats hdd = new HddStats(devName); + hdds.put(hdd.getDevName(), hdd); + } + hdds.get(devName).update(str[3]); + } + } + in.close(); + } catch (IOException e) { + log.log(Level.SEVERE, null, e); + } + } + + public static HddStats getStats(String devName){ + update(); + return hdds.get(devName); + } + + + public static class HddStats { + private String devName; + //read I/Os requests number of read I/Os processed + private long readIO = -1; + //read merges requests number of read I/Os merged with in-queue I/O + private long readMerges = -1; + //read sectors sectors number of sectors read + private long readSectors = -1; + //read ticks milliseconds total wait time for read requests + private long readTicks = -1; + //write I/Os requests number of write I/Os processed + private long writeIO = -1; + //write merges requests number of write I/Os merged with in-queue I/O + private long writeMerges = -1; + //write sectors sectors number of sectors written + private long writeSectors = -1; + //write ticks milliseconds total wait time for write requests + private long writeTicks = -1; + //in_flight requests number of I/Os currently in flight + private long inFlight = -1; + //io_ticks milliseconds total time this block device has been active + private long ioTicks = -1; + //time_in_queue milliseconds total wait time for all requests + private long timeInQueue = -1; + + private ThroughputCalculator readThroughput; + private ThroughputCalculator writeThroughput; + + + protected HddStats(String devName) { + this.devName = devName; + readThroughput = new ThroughputCalculator(); + writeThroughput = new ThroughputCalculator(); + } + protected void update(String line){ + String[] stats = line.split("\\W+"); + if(stats.length >= 11){ + readIO = Long.parseLong(stats[0]); + readMerges = Long.parseLong(stats[1]); + readSectors = Long.parseLong(stats[2]); + readTicks = Long.parseLong(stats[3]); + writeIO = Long.parseLong(stats[4]); + writeMerges = Long.parseLong(stats[5]); + writeSectors = Long.parseLong(stats[6]); + writeTicks = Long.parseLong(stats[7]); + inFlight = Long.parseLong(stats[8]); + ioTicks = Long.parseLong(stats[9]); + timeInQueue = Long.parseLong(stats[10]); + + readThroughput.setTotalHandledData(readSectors * 512); + writeThroughput.setTotalHandledData(writeSectors * 512); + } + } + + + public String getDevName() { + return devName; + } + /** + * This values increment when an I/O request completes. + */ + public long getReadIO() { + return readIO; + } + /** + * This value increment when an I/O request is merged with an + * already-queued I/O request. + */ + public long getReadMerges() { + return readMerges; + } + /** + * This value count the number of sectors read from to this + * block device. The "sectors" in question are the standard UNIX 512-byte + * sectors, not any device- or filesystem-specific block size. The + * counter is incremented when the I/O completes. + */ + public long getReadSectors() { + return readSectors; + } + /** + * This value count the number of milliseconds that I/O requests have + * waited on this block device. If there are multiple I/O requests waiting, + * this value will increase at a rate greater than 1000/second; for + * example, if 60 read requests wait for an average of 30 ms, the read_ticks + * field will increase by 60*30 = 1800. + */ + public long getReadTicks() { + return readTicks; + } + /** + * This values increment when an I/O request completes. + */ + public long getWriteIO() { + return writeIO; + } + /** + * This value increment when an I/O request is merged with an + * already-queued I/O request. + */ + public long getWriteMerges() { + return writeMerges; + } + /** + * This value count the number of sectors written to this + * block device. The "sectors" in question are the standard UNIX 512-byte + * sectors, not any device- or filesystem-specific block size. The + * counter is incremented when the I/O completes. + */ + public long getWriteSectors() { + return writeSectors; + } + /** + * This value count the number of milliseconds that I/O requests have + * waited on this block device. If there are multiple I/O requests waiting, + * this value will increase at a rate greater than 1000/second; for + * example, if 60 write requests wait for an average of 30 ms, the write_ticks + * field will increase by 60*30 = 1800. + */ + public long getWriteTicks() { + return writeTicks; + } + /** + * This value counts the number of I/O requests that have been issued to + * the device driver but have not yet completed. It does not include I/O + * requests that are in the queue but not yet issued to the device driver. + */ + public long getInFlight() { + return inFlight; + } + /** + * This value counts the number of milliseconds during which the device has + * had I/O requests queued. + */ + public long getIoTicks() { + return ioTicks; + } + /** + * This value counts the number of milliseconds that I/O requests have waited + * on this block device. If there are multiple I/O requests waiting, this + * value will increase as the product of the number of milliseconds times the + * number of requests waiting (see "read ticks" above for an example). + */ + public long getTimeInQueue() { + return timeInQueue; + } + + /** + * @return the average byte/second read throughput from the disk + */ + public double getReadThroughput(){ + return readThroughput.getByteThroughput(); + } + /** + * @return the average byte/second write throughput to the disk + */ + public double getWriteThroughput(){ + return writeThroughput.getByteThroughput(); + } + } + + + public static void main(String[] args){ + while(true){ + HddStats hdd = ProcDiskstats.getStats("sda"); + System.out.println("sda= " + + "read: " + StringUtil.formatByteSizeToString((long)hdd.getReadThroughput()) + "/s "+ + "write: " + StringUtil.formatByteSizeToString((long)hdd.getWriteThroughput()) + "/s"); + try{Thread.sleep(1000);}catch (Exception e){} + } + } +} diff --git a/src/zutil/osal/app/linux/ProcStat.java b/src/zutil/osal/app/linux/ProcStat.java new file mode 100644 index 0000000..1d48f04 --- /dev/null +++ b/src/zutil/osal/app/linux/ProcStat.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2015 ezivkoc + * + * 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 zutil.osal.app.linux; + +import zutil.log.LogUtil; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Documentation from https://www.kernel.org/doc/Documentation/block/stat.txt + * + * Created by ezivkoc on 2015-05-19. + */ +public class ProcStat { + private static final Logger log = LogUtil.getLogger(); + private static final String PROC_PATH = "/proc/stat"; + private static final int TTL = 500; // update stats every 0.5 second + + private static CpuStats cpuTotal = new CpuStats(); + private static ArrayList cpus = new ArrayList(); + private static long uptime; + private static long processes; + private static long updateTimestamp; + + + private synchronized static void update(){ + if(System.currentTimeMillis() - updateTimestamp < TTL) + return; + updateTimestamp = System.currentTimeMillis(); + try { + BufferedReader in = new BufferedReader(new FileReader(PROC_PATH)); + String line = null; + while((line=in.readLine()) != null){ + String[] str = line.split("\\W+"); + if(str[0].equals("cpu")) { + cpuTotal.update(str); + } + else if(str[0].startsWith("cpu")){ + int cpuId = Integer.parseInt(str[0].substring(3)); + if(cpus.size() <= cpuId) + cpus.add(new CpuStats()); + cpus.get(cpuId).update(str); + } + else if(str[0].startsWith("btime")){ + uptime = Long.parseLong(str[1]); + } + else if(str[0].startsWith("processes")){ + processes = Long.parseLong(str[1]); + } + } + in.close(); + } catch (IOException e) { + log.log(Level.SEVERE, null, e); + } + } + + public static CpuStats getTotalCpuStats(){ + update(); + return cpuTotal; + } + public static Iterator getCpuStats(){ + update(); + return cpus.iterator(); + } + /** + * @return the time at which the system booted, in seconds since the Unix epoch. + */ + public static long getUptime(){ + update(); + return uptime; + } + /** + * @return the number of processes and threads created, which includes (but is not limited to) those created by calls to the fork() and clone() system calls. + */ + public static long getProcesses(){ + update(); + return processes; + } + + + + public static class CpuStats { + // normal processes executing in user mode + private long user; + // processes executing in kernel mode + private long system; + // twiddling thumbs + private long idle; + // waiting for I/O to complete + private long iowait; + private long steal; + // virtual processes + private long guest; + private long total; + + // Percentage + private float load_total; + private float load_user; + private float load_system; + private float load_iowait; + private float load_virtual; + + protected CpuStats(){} + protected void update(String[] stats){ + long newUser=0, newNice=0, newSystem=0, newIdle=0, newIowait=0, newIrq=0, newSoftirq=0, newSteal=0, newGuest=0, newGuestNice=0; + if(stats.length >= 1+8){ + newUser = Long.parseLong(stats[1]); + newNice = Long.parseLong(stats[2]); + newSystem = Long.parseLong(stats[3]); + newIdle = Long.parseLong(stats[4]); + newIowait = Long.parseLong(stats[5]); + newIrq = Long.parseLong(stats[6]); + newSoftirq = Long.parseLong(stats[7]); + if(stats.length >= 1+8+3){ + newSteal = Long.parseLong(stats[8]); + newGuest = Long.parseLong(stats[9]); + newGuestNice = Long.parseLong(stats[10]); + } + + // Summarize + newUser = newUser + newNice - newGuest - newGuestNice; + newSystem = newSystem + newIrq + newSoftirq; + newGuest = newGuest + newGuestNice; + + // Calculate the diffs + long userDiff = newUser - user; + long idleDiff = (newIdle + newIowait) - (idle + iowait); + long systemDiff = newSystem - system; + long stealDiff = newSteal - steal; + long virtualDiff = newGuest - guest; + long newTotal = userDiff + systemDiff + idleDiff + stealDiff + virtualDiff; + // Calculate load + load_total = (float)(newTotal-idleDiff)/newTotal; + load_user = (float)userDiff/newTotal; + load_system = (float)systemDiff/newTotal; + load_iowait = (float)(newIowait - iowait)/newTotal; + load_virtual = (float)virtualDiff/newTotal; + + // update old values + user = newUser; + system = newSystem; + idle = newIdle; + iowait = newIowait; + steal = newSteal; + guest = newGuest; + total = newTotal; + } + } + + public float getTotalLoad() { + return load_total; + } + public float getUserLoad() { + return load_user; + } + public float getSystemLoad() { + return load_system; + } + public float getIOWaitLoad() { + return load_iowait; + } + public float getVirtualLoad() { + return load_virtual; + } + + } + + public static void main(String[] args){ + while(true){ + Iterator it = ProcStat.getCpuStats(); + for(int i=0; it.hasNext(); ++i){ + CpuStats cpu = it.next(); + System.out.print("CPU"+i+": " + cpu.getTotalLoad()+ " "); + } + System.out.println("Total Load: " + ProcStat.getTotalCpuStats().getTotalLoad()); + try{Thread.sleep(1000);}catch (Exception e){} + } + } +} diff --git a/src/zutil/osal/app/linux/Ps.java b/src/zutil/osal/app/linux/Ps.java new file mode 100644 index 0000000..eb715d9 --- /dev/null +++ b/src/zutil/osal/app/linux/Ps.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 Ziver + * + * 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 zutil.osal.app.linux; + +import zutil.osal.OSAbstractionLayer; + +/** + * Created by Ziver on 2014-12-23. + */ +public class Ps { + private static OSAbstractionLayer os = OSAbstractionLayer.getInstance(); + + public static boolean isRunning(int pid){ + String[] output = os.runCommand("ps -p "+pid); + return output.length > 1; + } +}