/* This code is part of Freenet. It is distributed under the GNU General * Public License, version 2 (or at your option any later version). See * http://www.gnu.org/ for further details of the GPL. */ package freenet.io.comm; import java.net.InetAddress; import java.util.Arrays; import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; import freenet.support.Logger; import freenet.support.Logger.LogLevel; public class IOStatisticCollector { public static final int STATISTICS_ENTRIES = 10; public static final int STATISTICS_DURATION_S = 30; public static final int STATISTICS_DURATION = 1000*STATISTICS_DURATION_S; private long lastrotate; private static boolean logDEBUG; private long totalbytesin; private long totalbytesout; private final LinkedHashMap<String, StatisticEntry> targets; static boolean ENABLE_PER_ADDRESS_TRACKING = false; public IOStatisticCollector() { targets = new LinkedHashMap<String, StatisticEntry>(); // TODO: only for testing!!!! // This should only happen once //SNMPAgent.create(); //SNMPStarter.initialize(); logDEBUG = Logger.shouldLog(LogLevel.DEBUG, this); } public void addInfo(InetAddress addr, int port, int inbytes, int outbytes, boolean isLocal) { try { synchronized (this) { _addInfo(addr, port, inbytes, outbytes, isLocal); } } catch (Throwable t) { t.printStackTrace(); } } private void _addInfo(InetAddress addr, int port, int inbytes, int outbytes, boolean isLocal) { rotate(); if(ENABLE_PER_ADDRESS_TRACKING) { String key = addr + ":" + port; StatisticEntry entry = targets.get(key); if (entry == null) { entry = new StatisticEntry(); targets.put(key, entry); } entry.addData((inbytes>0)?inbytes:0, (outbytes>0)?outbytes:0); } if(!isLocal) { synchronized(this) { totalbytesout += (outbytes>0)?outbytes:0; totalbytesin += (inbytes>0)?inbytes:0; if(logDEBUG) Logger.debug(IOStatisticCollector.class, "Add("+addr+":"+port+ ',' +inbytes+ ',' +outbytes+" -> "+totalbytesin+" : "+totalbytesout); } } } public void dumpInfo() { synchronized (this) { _dumpInfo(); } } public long[] getTotalIO() { synchronized (this) { return _getTotalIO(); } } private long[] _getTotalIO() { long ret[] = new long[2]; synchronized(this) { ret[0] = totalbytesout; ret[1] = totalbytesin; } return ret; } public int[][] getTotalStatistics() { synchronized (this) { return _getTotalStatistics(); } } private int[][] _getTotalStatistics() { //String[] keys = (String[])targets.keySet().toArray(); int ret[][] = new int[STATISTICS_ENTRIES][2]; for (int i = 0 ; i < STATISTICS_ENTRIES ; i++) { ret[i][0] = ret[i][1] = 0; } for (Map.Entry<String,StatisticEntry> entry : targets.entrySet()) { int inres[] = entry.getValue().getRecieved(); int outres[] = entry.getValue().getSent(); for (int i = 0 ; i < STATISTICS_ENTRIES ; i++) { ret[i][1] += inres[i]; ret[i][0] += outres[i]; } } return ret; } private void _dumpInfo() { rotate(); //DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE); //System.err.println(DateFormat.getDateInstance().format(new Date())); System.err.println(new Date()); final double divby = STATISTICS_DURATION_S*1024; for (Map.Entry<String,StatisticEntry> entry : targets.entrySet()) { String key = entry.getKey(); int inres[] = entry.getValue().getRecieved(); int outres[] = entry.getValue().getSent(); System.err.print((key + " ").substring(0,22) + ": "); int tin = 0; int tout = 0; for (int i = 0 ; i < inres.length ; i++) { // in/out in 102.4 bytes (hecto-bytes) tin += inres[i]; tout += outres[i]; int in = (int) ((tin*10.0) / (divby*(i+1))); int out =(int) ((tout*10.0) /(divby*(i+1))); System.err.print("i:" + (in/10) + '.' + (in%10)); System.err.print(" o:" + (out/10) + '.' + (out%10)); System.err.print(" \t"); } System.err.println(); } System.err.println(); } private void rotate() { long now = System.currentTimeMillis(); if ((now - lastrotate) >= STATISTICS_DURATION) { lastrotate = now; Object[] keys = targets.keySet().toArray(); if(keys == null) return; // Why aren't we iterating there ? for(int i = 0 ; i < keys.length ; i++) { Object key = keys[i]; if (targets.get(key).rotate() == false) targets.remove(key); } // FIXME: debugging //_dumpInfo(); } } /* * to thead each update.... heavy stuff private class StatisticUpdater implements Runnable { private IOStatisticCollector sc; private String key; private int inbytes; private int outbytes; public StatisticUpdater(IOStatisticCollector sc, String key, int inbytes, int outbytes) { this.sc = sc; this.key = key; this.inbytes = inbytes; this.outbytes = outbytes; new Thread(this, "IOStatisticCollector$StatisticUpdater").run(); } public void run() { } } */ private static class StatisticEntry { private int recieved[]; private int sent[]; public StatisticEntry() { // Create a new array and clear it recieved = new int[IOStatisticCollector.STATISTICS_ENTRIES+1]; sent = new int[IOStatisticCollector.STATISTICS_ENTRIES+1]; for (int i = 0 ; i < recieved.length ; i++) { recieved[i] = sent[i] = 0; } } public void addData(int inbytes, int outbytes) { recieved[0] += inbytes; sent[0] += outbytes; } public boolean rotate() { boolean hasdata = false; for (int i = recieved.length - 1 ; i > 0 ; i--) { recieved[i] = recieved[i-1]; sent[i] = sent[i-1]; hasdata |= (recieved[i] > 0) || (sent[i] > 0); } recieved[0] = sent[0] = 0; return hasdata; } public int[] getRecieved() { return Arrays.copyOfRange(recieved, 1, 1 + IOStatisticCollector.STATISTICS_ENTRIES); } public int[] getSent() { return Arrays.copyOfRange(sent, 1, 1 + IOStatisticCollector.STATISTICS_ENTRIES); } } }