/******************************************************************************* * Copyright (c) 2014 EURA NOVA. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v2.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * Aldemar Reynaga - initial API and implementation * Salim Jouili - initial API and implementation ******************************************************************************/ package com.steffi.testing; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.StringTokenizer; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.infinispan.Cache; import com.steffi.common.BigTextFile; import com.steffi.model.Cell; import com.steffi.model.EdgeType; import com.steffi.model.SteffiEdge; import com.steffi.model.SteffiGraph; import com.steffi.model.SteffiVertex; import com.steffi.storage.CacheContainer; import com.steffi.storage.CellTransaction.TransactionConclusion; import com.steffi.traversal.DistributedTraversal; import com.steffi.traversal.EdgeTraversalConf; import com.steffi.traversal.Evaluation; import com.steffi.traversal.MatchEvaluatorConf; import com.steffi.traversal.Path; import com.steffi.traversal.TraversalResults; /** * @author Aldemar Reynaga * Functions to execute read, write and traversal tests */ public class TestTools { public enum TestFileType{ RANDOM, ALL_PATHS, NO_PATHS } public static long nextLong(Random rng, long n) { // error checking and 2^x checking removed for simplicity. long bits, val; do { bits = (rng.nextLong() << 1) >>> 1; val = bits % n; } while (bits-val+(n-1) < 0L); return val; } private static Long genPathTest(Random randomGen, Cache<Long, Cell> cache, SteffiVertex startVertex, int hops, EdgeType edgeType) throws Exception { int index; SteffiVertex vertex = startVertex; for (int i=0; i<hops; i++) { List<SteffiEdge> edges = vertex.getEdgesByType(edgeType); if (edges.isEmpty()) { return null; } index = randomGen.nextInt(edges.size()); vertex = (SteffiVertex) cache.get(edges.get(index).getDestCellId()); } if (vertex.getId() == startVertex.getId()) return null; return vertex.getId(); } public static void genPathTestFile(long minId, long maxId, int numTests, String outFile, int hops, EdgeType edgeType) throws Exception { BufferedWriter writer = null; Cache<Long, Cell> cache = CacheContainer.getCellCache(); long startId=0; Long endId = null; Cell startCell=null; Random randomGen = new Random(); try { writer = new BufferedWriter(new FileWriter(new File( outFile), false)); writer.write("#START_ID, END_ID"); for (int i=0; i<numTests; i++) { do { do { startId = nextLong(randomGen, maxId - minId) + minId; startCell = cache.get(startId); } while (startCell == null); endId = genPathTest(randomGen, cache, (SteffiVertex) startCell, hops, edgeType); } while (endId == null); writer.newLine(); writer.write(startId + "," + endId); } } finally { if (writer != null) { writer.flush(); writer.close(); } } } public static void genTestFile(long minId, long maxId, int numTests, String outFile) throws Exception { BufferedWriter writer = null; Cache<Long, Cell> cache = CacheContainer.getCellCache(); long startId=0, endId=0; Cell startCell=null, endCell=null; Random randomGen = new Random(); try { writer = new BufferedWriter(new FileWriter(new File( outFile), false)); writer.write("#START_ID, END_ID"); for (int i=0; i<numTests; i++) { while (startCell == null) { startId = nextLong(randomGen, maxId - minId) + minId; startCell = cache.get(startId); } while (endCell == null || startCell.getId() == endCell.getId()) { endId = nextLong(randomGen, maxId - minId) + minId; endCell = cache.get(endId); } writer.newLine(); writer.write(startId + "," + endId); startCell = null; endCell = null; } } finally { if (writer != null) { writer.flush(); writer.close(); } } } private static void runTraversal(DistributedTraversal traversal, long startVertexId, long endVertexId, SteffiGraph graph, List<Long> traversalTimes, BufferedWriter writer) throws Exception{ TraversalResults results = traversal.traverse((SteffiVertex) graph.retrieveCell(startVertexId)); traversalTimes.add(results.getTime()); if (writer != null) { List<Path> paths = results.getPaths(); writer.write(startVertexId + "," + endVertexId + "," + results.getTime()); if (paths.isEmpty()) { writer.write(",N,"); } else { String resPaths = ""; for (Path path : paths) resPaths += path.toString() + "||"; resPaths = resPaths.substring(0, resPaths.length()-2); writer.write(",Y," + resPaths); } writer.newLine(); //writer.flush(); } } private static Map<StatisticalIndicators, Double> calculateIndicators(List<Long> traversalTimes) { Map<StatisticalIndicators, Double> indicators = new HashMap<StatisticalIndicators, Double>(); Collections.sort(traversalTimes); if (traversalTimes.size() % 2 == 0) indicators.put(StatisticalIndicators.MEDIAN, (traversalTimes.get((traversalTimes.size()/2) - 1) + traversalTimes.get((traversalTimes.size()/2) + 1))/2D); else indicators.put(StatisticalIndicators.MEDIAN, traversalTimes.get(traversalTimes.size()/2)/2D); indicators.put(StatisticalIndicators.MIN, (double)traversalTimes.get(0)); indicators.put(StatisticalIndicators.MAX, (double)traversalTimes.get(traversalTimes.size()-1)); double sum = 0, mean; for (long time : traversalTimes) sum += (double)time; mean = sum / traversalTimes.size(); indicators.put(StatisticalIndicators.MEAN, mean); indicators.put(StatisticalIndicators.TOTAL, sum); sum = 0; for (long time : traversalTimes) sum += Math.pow(time-mean, 2); indicators.put(StatisticalIndicators.DEV_STD, Math.sqrt(sum/(traversalTimes.size()-1))); return indicators; } public static Map<StatisticalIndicators, Double> testTraversalFromFile(SteffiGraph graph, EdgeTraversalConf edgeTraversalConf, Evaluation evaluation, String fileName, int maxDepth, String outLogFile, long delay) throws Exception{ return testTraversalFromFile(graph, edgeTraversalConf, evaluation, fileName, maxDepth, outLogFile, delay, false); } public static Map<StatisticalIndicators, Double> testTraversalFromFile(SteffiGraph graph, EdgeTraversalConf edgeTraversalConf, Evaluation evaluation, String fileName, int maxDepth, String outLogFile, long delay, boolean runConcurrentTest) throws Exception{ BigTextFile file = null; DistributedTraversal traversal = new DistributedTraversal(); BufferedWriter writer = null; List<Long> traversalTimes = new ArrayList<Long>(); int counter = 0; long startVertexId, endVertexId; try { file = new BigTextFile(fileName); traversal.setHops(maxDepth); traversal.addEdgeTraversalConfs(edgeTraversalConf); MatchEvaluatorConf matchConf = new MatchEvaluatorConf(); matchConf.setEvaluation(evaluation); traversal.setMatchEvaluatorConf(matchConf); if (outLogFile != null) writer = new BufferedWriter(new FileWriter(new File( outLogFile), false)); for (String line : file) { if (!line.startsWith("#")) { StringTokenizer tokenizer = new StringTokenizer(line, ","); startVertexId = Long.parseLong(tokenizer.nextToken()); endVertexId = Long.parseLong(tokenizer.nextToken()); matchConf.setCellId(endVertexId); runTraversal(traversal, startVertexId, endVertexId, graph, traversalTimes, writer); counter++; if (!runConcurrentTest) System.out.println("Traversal # " + counter + " executed"); Thread.sleep(delay); } } if (runConcurrentTest) return null; return calculateIndicators(traversalTimes); } finally { if (file!=null) file.Close(); if (writer != null) { writer.flush(); writer.close(); } } } public static Map<StatisticalIndicators, Double> testReads(String testFile, String outLogFile) throws Exception { return testReads(testFile, outLogFile, false); } public static Map<StatisticalIndicators, Double> testReads(String testFile, String outLogFile, boolean runConcurTest) throws Exception { BigTextFile file = null; BufferedWriter writer = null; try { file = new BigTextFile(testFile); List<Long> cellIds = new ArrayList<Long>(); List<Long> times = new ArrayList<Long>(); SteffiGraph graph = SteffiGraph.getInstance(); long startTime, endTime; if (outLogFile != null) { writer = new BufferedWriter(new FileWriter(new File( outLogFile), false)); writer.write("CELL_ID, TIME(nanoseconds)"); } for (String line : file) { if (!line.startsWith("#")) { StringTokenizer tokenizer = new StringTokenizer(line, ","); cellIds.add(Long.parseLong(tokenizer.nextToken())); cellIds.add(Long.parseLong(tokenizer.nextToken())); } } for (long cellId : cellIds) { startTime = System.nanoTime(); graph.retrieveCell(cellId); endTime = System.nanoTime(); times.add(endTime-startTime); if (writer != null) { writer.newLine(); writer.write(cellId + "," + (endTime-startTime)); } } if (runConcurTest) return null; return calculateIndicators(times); } finally { if (file!=null) file.Close(); if (writer!=null) writer.close(); } } public static Map<StatisticalIndicators, Double> testWrites(String testFile, String outLogFile) throws Exception { return testWrites(testFile, outLogFile, false); } public static Map<StatisticalIndicators, Double> testWrites(String testFile, String outLogFile, boolean runConcurTest) throws Exception { BigTextFile file = null; BufferedWriter writer = null; try { Random random = new Random(); file = new BigTextFile(testFile); List<Long[]> cellIds = new ArrayList<Long[]>(); List<Long> times = new ArrayList<Long>(); SteffiGraph graph = SteffiGraph.getInstance(); long startTime, endTime; Set<Long> newCellIds = new HashSet<Long>(); long cellId; if (outLogFile != null) writer = new BufferedWriter(new FileWriter(new File( outLogFile), false)); int transactionCounter=0; for (String line : file) { if (!line.startsWith("#")) { StringTokenizer tokenizer = new StringTokenizer(line, ","); boolean isNewId = false; do { cellId = nextLong(random, 50000) + 9999999999L; if (!newCellIds.contains(cellId)) { newCellIds.add(cellId); isNewId = true; } } while (!isNewId); cellIds.add(new Long[]{cellId, Long.parseLong(tokenizer.nextToken()), Long.parseLong(tokenizer.nextToken())}); } } if (writer != null) writer.write("NEW CELL ID, TIME(nanoseconds)"); for (Long[] destCellIds : cellIds) { try { graph.startTransaction(); SteffiVertex vertexA = (SteffiVertex) graph.retrieveCell(destCellIds[1]); SteffiVertex vertexB = (SteffiVertex) graph.retrieveCell(destCellIds[2]); //startTime = new Date().getTime(); startTime = System.nanoTime(); SteffiVertex vertex = graph.addVertex(destCellIds[0], null); vertex.addEdge(vertexA, true, null); vertex.addEdge(vertexB, true, null); graph.stopTransaction(TransactionConclusion.COMMIT); transactionCounter++; } catch (Exception x) { System.out.println("Error on transaction " + (transactionCounter+1) + ", " + destCellIds[0] + "-" + destCellIds[1]); throw new Exception(x); } endTime = System.nanoTime(); //endTime = new Date().getTime(); if (writer != null) { writer.newLine(); writer.write(String.valueOf(destCellIds[0]) + "," + (endTime-startTime)); } times.add(endTime-startTime); } if (runConcurTest) return null; return calculateIndicators(times); } finally { if (file!=null) file.Close(); if (writer != null) { writer.flush(); writer.close(); } } } public static void runWriteClients (int numberOfClients, String fileName) { long startTime, endTime; startTime = new Date().getTime(); ExecutorService executorService = Executors.newFixedThreadPool(numberOfClients); for (int i = 0; i < numberOfClients; i++) { Runnable client = new WriteClient(fileName); executorService.execute(client); } executorService.shutdown(); while (!executorService.isTerminated()) { } endTime = new Date().getTime(); System.out.println("Total time (ms): " + (endTime - startTime)); System.out.println("Writes per second: " + ((numberOfClients*200*1000)/(endTime - startTime))); } public static void runReadClients (int numberOfClients, String fileName) { long startTime, endTime; startTime = new Date().getTime(); ExecutorService executorService = Executors.newFixedThreadPool(numberOfClients); for (int i = 0; i < numberOfClients; i++) { Runnable client = new ReadClient(fileName); executorService.execute(client); } executorService.shutdown(); while (!executorService.isTerminated()) { } endTime = new Date().getTime(); System.out.println("Total time (ms): " + (endTime - startTime)); System.out.println("Reads per second: " + ((numberOfClients*200*1000)/(endTime - startTime))); } private static List<NodePair> readQueries(String queryFileName) throws Exception { List<NodePair> queries = new ArrayList<NodePair>(); BigTextFile file = null; try { file = new BigTextFile(queryFileName); for (String line : file) { if (!(line.trim().equals("") || line.startsWith("#"))) { StringTokenizer tokenizer = new StringTokenizer(line, ","); queries.add(new NodePair(Long.parseLong(tokenizer.nextToken()), Long.parseLong(tokenizer.nextToken()))); } } } finally { if (file != null) file.Close(); } return queries; } public static void runTraversalClients(int numberOfClients, String queryFileName, int hops, EdgeType edgeType, long testDuration) throws Exception { long numberOfTraversals; ExecutorService executorService = Executors.newFixedThreadPool(numberOfClients); List<TraversalClient> clients = new ArrayList<TraversalClient>(); List<NodePair> queries = readQueries(queryFileName); EdgeTraversalConf edgeTraversalConf = new EdgeTraversalConf("", edgeType); SteffiGraph graph =SteffiGraph.getInstance(); for (int i = 0; i < numberOfClients; i++) clients.add(new TraversalClient(hops, edgeTraversalConf, queries, graph)); //Launch client threads for (Runnable client : clients) executorService.execute(client); Thread.sleep(testDuration); numberOfTraversals = 0; for (TraversalClient client : clients) { client.stop(); numberOfTraversals += client.getCounter(); } executorService.shutdown(); while (!executorService.isTerminated()) { } System.out.println("Traversals per second: " + ((1000*numberOfTraversals)/testDuration)); } }