/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2006-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.tools.rrd; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.LinkedList; import java.util.List; import org.opennms.netmgt.rrd.RrdDataSource; import org.opennms.netmgt.rrd.RrdStrategy; import org.opennms.netmgt.rrd.RrdUtils; public class RrdStresser { static int currFileNum = 0; static int[] dataPosition = null; static final String FACTORY_NAME = System.getProperty("stresstest.factory", "FILE"); static final int FILE_COUNT = Integer.getInteger("stresstest.filecount", 10000).intValue(); static final int ZERO_FILES = Integer.getInteger("stresstest.zerofiles", (FILE_COUNT / 2)).intValue(); static final int FILES_PER_DIR = Integer.getInteger("stresstest.filesperdir", 0).intValue(); static Date firstUpdateComplete = null; static final String[] RRA_LIST = System.getProperty("rras.list", "RRA:AVERAGE:0.5:1:8928,RRA:AVERAGE:0.5:12:8784,RRA:MIN:0.5:12:8784,RRA:MAX:0.5:12:8784").split(","); //This is the number of updates that will be performed during a run of this tool static final int MAX_UPDATES = Integer.getInteger("stresstest.maxupdates", 1000).intValue(); //Output interim statistics every 'stresstest.modulus' updates static final int MODULUS = Integer.getInteger("stresstest.modulus", 1000).intValue(); //Unused, but will be used to simulate store-by-group (multiple values per file) static final int RRD_DATASOURCE_COUNT = Integer.getInteger("stresstest.datasourcecount", 1).intValue(); static final String RRD_DATASOURCE_NAME = "T"; static final String RRD_PATH = System.getProperty("stresstest.file", "/var/opennms/rrd/stressTest/stress"); static final long RRD_START = 946710000L; static final long RRD_STEP = Integer.getInteger("stresstest.rrdstep", 300).intValue(); static final int THREAD_COUNT = Integer.getInteger("stresstest.threadcount", 1).intValue(); static final long TIME_END = 1080013472L; static final long TIME_START = 1060142010L; private static final String UPDATE_FILE = System.getProperty("stresstest.updatefile", "/stress-test-simple.txt"); static int updateCount = 0; static String[] updateData = null; static final int UPDATES_PER_OPEN = Integer.getInteger("stresstest.updatesperopen", 1).intValue(); static Date updateStart = null; static final boolean USE_QUEUE = "true".equals(System.getProperty("stresstest.usequeue", "true")); static final boolean QUEUE_CREATES = "true".equals(System.getProperty("stresstest.queuecreates", "true")); //Effectively this is the total runtime static final int UPDATE_TIME = Integer.getInteger("stresstest.updatetime", 300).intValue(); static final String EXTENSION = ".jrb"; static long filesPerZero = FILE_COUNT / ZERO_FILES; static RrdStrategy<Object,Object> rrd = null; /** * */ private static synchronized void countUpdate() { if (updateCount == FILE_COUNT) { firstUpdateComplete = new Date(); } if (++updateCount % MODULUS == 0) { printStats(); } } /** * */ private static void printStats() { Date now = new Date(); long avgSpeed = (long) (updateCount * 1000.0 / (now.getTime() - updateStart.getTime())); long updateSpeed = (long) ((updateCount - FILE_COUNT) * 1000.0 / (now.getTime() - firstUpdateComplete.getTime())); print(updateCount + " samples stored, " + updateSpeed + " updates/sec avg since first update " + avgSpeed + " updates/sec avg for all time: " + rrdGetStats()); } static String getFileName(int fileNum) { if (FILES_PER_DIR == 0) { return RRD_PATH + fileNum + EXTENSION; } else { int dirNum = fileNum / FILES_PER_DIR; return RRD_PATH + File.separator + dirNum + File.separator + fileNum + EXTENSION; } } private static synchronized String getNextLine(int fileNum) { int pos = dataPosition[fileNum]; if (pos >= updateData.length) { dataPosition[fileNum] = 0; } else { dataPosition[fileNum]++; } String update = updateData[pos]; if (ZERO_FILES > 0) { if (fileNum % filesPerZero == 0) { update = makeZeroUpdate(fileNum, update); } } return update; } private static String makeZeroUpdate(int fileNum, String update) { try { int colon = update.indexOf(':'); if (colon >= 0) { long initialTimeStamp = Long.parseLong(update.substring(0, colon)); if (initialTimeStamp == 0) print("ZERO ERROR: created a zero update with ts=0 for file: " + getFileName(fileNum) + " data: " + update); update = initialTimeStamp + ":0"; } } catch (NumberFormatException e) { } return update; } public static void main(final String[] args) throws Exception { String strategy = System.getProperty("org.opennms.rrd.strategyClass"); if (strategy == null) { System.setProperty("org.opennms.rrd.strategyClass", "org.opennms.netmgt.rrd.jrobin.JRobinRrdStrategy"); } printHeader(); print("Starting demo at " + new Date() + " using " + System.getProperty("org.opennms.rrd.strategyClass")); rrdInitialize(); print("Loading update file"); InputStream resourceStream = RrdStresser.class.getResourceAsStream(UPDATE_FILE); BufferedReader rdr = new BufferedReader(new InputStreamReader(resourceStream)); List<String> dataList = new LinkedList<String>(); String line; while ((line = rdr.readLine()) != null) { dataList.add(line); } updateData = dataList.toArray(new String[dataList.size()]); print("Finished loading update file. Initializing data positions"); dataPosition = new int[FILE_COUNT]; Date createStart = new Date(); print("Creating " + FILE_COUNT + " RRD files"); for (int i = 0; i < FILE_COUNT; i++) { dataPosition[i] = 0; File f = new File(getFileName(i)); if (!f.exists()) { // create RRD database Object rrdDef = rrdCreateDefinition(i); rrdCreateFile(rrdDef); } } Date now = new Date(); long speed = (long) (FILE_COUNT * 1000.0 / (now.getTime() - createStart.getTime())); print(FILE_COUNT + " files created, " + speed + " creates/sec"); updateStart = new Date(); firstUpdateComplete = new Date(); for (int i = 0; i < THREAD_COUNT; i++) { final int threadid = i; Runnable r = new Runnable() { public void run() { try { RrdStresser test = new RrdStresser(); test.execute(args,threadid); } catch (Throwable e) { e.printStackTrace(); } } }; Thread t = new Thread(r); t.start(); } } private static synchronized boolean moreUpdates() { return updateCount < MAX_UPDATES; } static synchronized int nextFileNum() { currFileNum = (currFileNum + 1) % FILE_COUNT; return currFileNum; } /** * */ private static void printHeader() { System.out.println("********************************************************************"); System.out.println("* OpenNMS Collection StressTest *"); System.out.println("* *"); System.out.println("* This demo creates single RRD file and tries to update it *"); System.out.println("* more than 600.000 times. Real data (> 20Mb) is obtained from the *"); System.out.println("* stress-test.txt file provided by Vadim Tkachenko *"); System.out.println("* (http://diy-zoning.sourceforge.net). *"); System.out.println("* *"); System.out.println("* Finally, a single PNG graph will be created from the RRD file. *"); System.out.println("* The stress test takes about one hour to complete on a 1.6GHz *"); System.out.println("* computer with 256MB of RAM. *"); System.out.println("********************************************************************"); System.out.println("modulus = " + MODULUS); System.out.println("fileCount = " + FILE_COUNT); System.out.println("zeroFiles = " + ZERO_FILES); System.out.println("threadCount = " + THREAD_COUNT); System.out.println("useQueuing = " + USE_QUEUE); System.out.println("queueCreates = " + QUEUE_CREATES); System.out.println("rraList = " + Arrays.asList(RRA_LIST)); System.out.println(); } static void print(String message) { System.out.println(message); } private static void rrdCloseFile(Object rrdFile) throws Exception { rrd.closeFile(rrdFile); } private static Object rrdCreateDefinition(int fileNum) throws Exception { String fileName = getFileName(fileNum); File file = new File(fileName); String dir = file.getParent(); String dsName = file.getName(); if (dsName.endsWith(EXTENSION)) { dsName = dsName.substring(0, dsName.length() - EXTENSION.length()); } RrdDataSource rrdDataSource = new RrdDataSource(dsName, "GAUGE", 600, "U", "U"); return rrd.createDefinition("stressTest", dir, dsName, 300, Collections.singletonList(rrdDataSource), Arrays.asList(RRA_LIST)); } private static void rrdCreateFile(Object rrdDef) throws Exception { rrd.createFile(rrdDef); } private static void rrdInitialize() throws Exception { rrd = RrdUtils.getStrategy(); } private static Object rrdOpenFile(String fileName) throws Exception { return rrd.openFile(fileName); } private static String rrdGetStats() { return rrd.getStats(); } private static void rrdUpdateFile(Object rrdFile, String data) throws Exception { rrd.updateFile(rrdFile, "stressTest", data); } public void execute(String[] args, int threadid) throws Exception { double millisPerUpdate = ((double) UPDATE_TIME * 1000) / ((double) (MAX_UPDATES)); System.out.println("Will perform one update every " +millisPerUpdate + "ms"); while (moreUpdates()) { // System.out.println(threadid+":More updates to do"); int fileNum = nextFileNum(); Object rrd = rrdOpenFile(getFileName(fileNum)); for (int i = 0; i < UPDATES_PER_OPEN; i++) { Date now = new Date(); long elapsedTime = now.getTime() - updateStart.getTime(); // System.out.println(threadid+":It's been "+elapsedTime+"ms since we started, and we've updated "+updateCount +" so far"); long expectedTime = (long) (millisPerUpdate * (double) updateCount); // System.out.println(threadid+":And I want it to be "+expectedTime); if (expectedTime > elapsedTime) { try { // System.out.println(threadid+":Sleeping for "+(expectedTime-elapsedTime)); Thread.sleep(expectedTime - elapsedTime); } catch (InterruptedException e) { } } String line = getNextLine(fileNum); try { rrdUpdateFile(rrd, line); countUpdate(); } catch (Throwable e) { print(threadid+":RRD ERROR: " + line + " : " + e.getMessage()); } } rrdCloseFile(rrd); } } }