2015-05-27 12:21:36 +00:00
|
|
|
/*
|
|
|
|
|
* 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.log.LogUtil;
|
|
|
|
|
import zutil.net.ThroughputCalculator;
|
|
|
|
|
|
2015-06-02 15:47:44 +00:00
|
|
|
import java.io.BufferedReader;
|
|
|
|
|
import java.io.FileReader;
|
|
|
|
|
import java.io.IOException;
|
2015-05-27 12:21:36 +00:00
|
|
|
import java.util.HashMap;
|
|
|
|
|
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<String, HddStats> hdds = new HashMap<String, HddStats>();
|
|
|
|
|
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){
|
2015-05-27 13:33:00 +00:00
|
|
|
String[] str = line.trim().split("\\s+", 4);
|
2015-05-27 12:21:36 +00:00
|
|
|
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){
|
2015-05-27 13:33:00 +00:00
|
|
|
String[] stats = line.split("\\s+");
|
2015-05-27 12:21:36 +00:00
|
|
|
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){}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|