/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package se.sics.gvod.ls.interas.snapshot; import java.text.DecimalFormat; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import se.sics.gvod.common.Self; import se.sics.gvod.ls.interas.InterAs; import se.sics.gvod.net.VodAddress; import se.sics.gvod.net.VodAddress.NatType; /** * * @author Jim Dowling<jdowling@sics.se> */ public final class InterAsStats { private static Logger logger = LoggerFactory.getLogger(InterAsStats.class); // (overlayId -> (nodeId, stats)) private static final ConcurrentHashMap<Integer, ConcurrentHashMap<Integer, Stats>> snapshotMap = new ConcurrentHashMap<Integer, ConcurrentHashMap<Integer, Stats>>(); private static final ConcurrentHashMap<VodAddress, Stats> nodeMap = new ConcurrentHashMap<VodAddress, Stats>(); private static AtomicInteger counter = new AtomicInteger(0); private static final ConcurrentHashMap<Integer, Integer> sentRequests = new ConcurrentHashMap<Integer, Integer>(); private static final ConcurrentHashMap<Integer, Integer> receivedResponses = new ConcurrentHashMap<Integer, Integer>(); private static final ConcurrentHashMap<Integer, Integer> gossipTimedout = new ConcurrentHashMap<Integer, Integer>(); private static final ConcurrentHashMap<Integer, Integer> sentResponses = new ConcurrentHashMap<Integer, Integer>(); private InterAsStats() { // hidden } public static Stats instance(Self self) { return addNode(self.getAddress()); } public static Stats addNode(VodAddress peer) { // int overlayId = peer.getOverlayId(); int overlayId = InterAs.SYSTEM_INTER_AS_OVERLAY_ID; int nodeId = peer.getId(); ConcurrentHashMap<Integer, Stats> overlayStats; if (!snapshotMap.containsKey(overlayId)) { overlayStats = new ConcurrentHashMap<Integer, Stats>(); snapshotMap.put(overlayId, overlayStats); } else { overlayStats = snapshotMap.get(overlayId); } Stats stats; if (!overlayStats.containsKey(nodeId)) { stats = new Stats(nodeId, overlayId); overlayStats.put(nodeId, stats); nodeMap.put(peer, stats); } else { stats = overlayStats.get(nodeId); } stats.setNatType(peer.getNatType()); return stats; } public static boolean removeNode(int nodeId, int overlayId) { ConcurrentHashMap<Integer, Stats> overlayStats = snapshotMap.get(overlayId); if (overlayStats != null) { return (overlayStats.remove(nodeId) == null) ? false : true; } else { return false; } } private static Set<Stats> getNodes(int overlayId) { Set<Stats> nodes = new HashSet<Stats>(); nodes.addAll(snapshotMap.get(overlayId).values()); return nodes; } private static int numNodes(int overlayId) { return getNodes(overlayId).size(); } //------------------------------------------------------------------- public static void startCollectData() { logger.debug("\nStart collecting data ...\n"); } //------------------------------------------------------------------- public static void stopCollectData() { logger.debug("\nStop collecting data ...\n"); for (int overlayId : snapshotMap.keySet()) { report(overlayId); } } /** * Returns all nodes with the same overlayId * * @param overlayId * @return */ private static Set<Stats> getOverlayStats(int overlayId) { Set<Stats> nodes = new HashSet<Stats>(); nodes.addAll(snapshotMap.get(overlayId).values()); return nodes; } private static void incTotal(Map<Integer, Integer> map, int overlayId, int count) { Integer total = map.get(overlayId); if (total == null) { total = 0; map.put(overlayId, total); } total += count; } private static int getNumRequestsSent(int overlayId) { int count = 0; Set<Stats> nodes = getOverlayStats(overlayId); for (Stats s : nodes) { count += s.getSentRequests(); } incTotal(sentRequests, overlayId, count); return count; } private static int getNumShufflesTimeouts(int overlayId) { int count = 0; Set<Stats> nodes = getOverlayStats(overlayId); for (Stats s : nodes) { count += s.getShuffleTimeout(); } incTotal(gossipTimedout, overlayId, count); return count; } private static int getNumResponsesSent(int overlayId) { int count = 0; Set<Stats> nodes = getOverlayStats(overlayId); for (Stats s : nodes) { count += s.getSentResponses(); } incTotal(sentResponses, overlayId, count); return count; } private static int getNumReceivedResponses(int overlayId) { int count = 0; Set<Stats> nodes = getOverlayStats(overlayId); for (Stats s : nodes) { count += s.getReceivedResponses(); } incTotal(receivedResponses, overlayId, count); return count; } private static int stdReceivedRequests(int overlayId, int avg) { int std = 0; Set<Stats> nodes = getOverlayStats(overlayId); for (Stats s : nodes) { if (s.getNatType() == NatType.OPEN) { std += Math.abs(avg - s.getReceivedRequests()); } } return std; } private static int maxShufflesRecvd(int overlayId) { int count = -1; Set<Stats> nodes = getOverlayStats(overlayId); for (Stats s : nodes) { count = (s.getReceivedRequests() > count) ? s.getReceivedRequests() : count; } return count; } private static int minShufflesRecvd(int overlayId) { int count = Integer.MAX_VALUE; Set<Stats> nodes = getOverlayStats(overlayId); for (Stats s : nodes) { if (s.getNatType() == NatType.OPEN) { count = (s.getReceivedRequests() < count) ? s.getReceivedRequests() : count; } } return count; } private static double avgAsHops(int overlayId) { double sumOfPeersAvgAsHops = 0; Set<Stats> nodes = getOverlayStats(overlayId); for (Stats s : nodes) { sumOfPeersAvgAsHops += s.getAvgAsHops(); } return (sumOfPeersAvgAsHops / nodes.size()); } private static int sentRequestsFromNat(int overlayId) { int count = 0; Set<Stats> nodes = getOverlayStats(overlayId); for(Stats s : nodes) { if(s.getNatType().equals(NatType.NAT)) { count += s.getSentRequests(); } } return count; } private static int sentRequestsFromOpen(int overlayId) { int count = 0; Set<Stats> nodes = getOverlayStats(overlayId); for(Stats s : nodes) { if(s.getNatType().equals(NatType.OPEN)) { count += s.getSentRequests(); } } return count; } private static int successfulExchangesNat(int overlayId) { int count = 0; Set<Stats> nodes = getOverlayStats(overlayId); for(Stats s : nodes) { if(s.getNatType().equals(NatType.NAT)) { count += s.getReceivedResponses(); } } return count; } private static int successfulExchangesOpen(int overlayId) { int count = 0; Set<Stats> nodes = getOverlayStats(overlayId); for(Stats s : nodes) { if(s.getNatType().equals(NatType.OPEN)) { count += s.getReceivedResponses(); } } return count; } //------------------------------------------------------------------- public static void report(int overlayId) { StringBuilder sb = new StringBuilder("\n"); sb.append("InterAs current step: ").append(counter.getAndIncrement()). append(", current time: ").append(System.currentTimeMillis()). append(", number of nodes: ").append(numNodes(overlayId)); sb.append(reportShuffles(overlayId)); logger.info(sb.toString()); } private static String reportShuffles(int overlayId) { StringBuilder sb = new StringBuilder(); int t = getNumShufflesTimeouts(overlayId); int sentRequests = getNumRequestsSent(overlayId); int sentResponses = getNumResponsesSent(overlayId); int recvd = getNumReceivedResponses(overlayId); int sz = numNodes(overlayId); int max = maxShufflesRecvd(overlayId); int min = minShufflesRecvd(overlayId); double avgAsHops = avgAsHops(overlayId); DecimalFormat format = new DecimalFormat("#.##"); String timedoutPercent = sentRequests == 0 ? "0" : format.format(100 * (double) ((double) t / (double) sentRequests)); String receivedPercent = sentRequests == 0 ? "0" : format.format(100 * (double) ((double) recvd / (double) sentRequests)); String averageAsHops = format.format(avgAsHops); int sentRequestsFromNat = sentRequestsFromNat(overlayId); int sentRequestsFromOpen = sentRequestsFromOpen(overlayId); int receivedResponsesNat = successfulExchangesNat(overlayId); int receivedResponsesOpen = successfulExchangesOpen(overlayId); if (sz != 0) { sb.append("---\n"); sb.append("Msg Stats: "); sb.append("avg recvd(").append((recvd / sz)). // append("), max(").append(max). // append("), min(").append(min). append("), sReq(").append(sentRequests). append("), t(").append(t).append(":").append(timedoutPercent).append("%"). append("), rResp(").append(recvd).append(":").append(receivedPercent).append("%"). append(")\n"); sb.append("NAT Stats (recvd/sent): "); sb.append("NAT(").append(receivedResponsesNat).append("/").append(sentRequestsFromNat). append("), Open(").append(receivedResponsesOpen).append("/").append(sentRequestsFromOpen). append(")\n"); sb.append("Topology Stats: "); sb.append("avgAsHops(").append(averageAsHops). append(")\n"); } return sb.toString(); } }