/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; If not, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.io.raw; import xxl.core.math.statistics.nonparametric.histograms.LogScaleHistogram; import xxl.core.util.timers.Timer; import xxl.core.util.timers.TimerUtils; /** * Counts the calls to a (decorated) raw access and calculates * a statistic of seeks. * <p> * Two LogscaleHistograms are computed: <br> * <ol> * <li>seek distance histogram: average seek time for a certain seek distance</li> * <li>seek time histogram: number of accesses that needed a certain amount of time</li> * </ol> * To get the statistics, call the toString() method. */ public class StatisticsRawAccess implements RawAccess { /** * Decorated RawAccess */ private RawAccess r; /** * A counter for calls to the <tt>open</tt> method. */ private int openCalls; /** * A counter for calls to the <tt>close</tt> method. */ private int closeCalls; /** * A counter for calls to the <tt>close</tt> method. */ private int readCalls; /** * A counter for calls to the <tt>write</tt> method. */ private int writeCalls; /** * A counter for the number of resets. */ private int resetCount; /** * A counter for the number of sequential access operations. */ private int sequentialAccessCount; /** * A counter for the number of sequential access operations. */ private int sameSectorCount; /** * A counter for the number of random access operations. */ private int randomAccessCount; /** * The sector that is accessed at last. */ private long lastSector; /** * A histogram storing informations about the distance between consecutive * accessed sectors. */ private LogScaleHistogram histSectorDistance; /** * A histogram storing informations about the access-time of sectors. */ private LogScaleHistogram histTime; /** * A timer that is used for time measurement. */ private Timer timer; /** * The time the last access operation is performed. */ private long t; // current time messured /** * The time that is needed to do the timer calls without performing * operations. */ private long tzero; /** * The frequence of the timer. */ private long tfreq; /** * Constructs a RawAccessStatistic. * * @param r Decorated RawAccess * @param partitions Number of partition for both LogScaleHistograms * @param sdHistFactor Partition growth factor for the seek distance histogram * @param tHistFactor Partition growth factor for the seek time histogram * @exception RawAccessException a specialized RuntimeException */ public StatisticsRawAccess(RawAccess r,int partitions, double sdHistFactor, double tHistFactor) throws RawAccessException { this.r = r; resetCounter(); resetCount = 0; lastSector = -2; // -1 ==> 0 would be a sequential access as first operation! histSectorDistance = new LogScaleHistogram(0.0, r.getNumSectors(),partitions,sdHistFactor); histTime = new LogScaleHistogram(0.0, 0.05, partitions, tHistFactor); timer = (Timer) TimerUtils.FACTORY_METHOD.invoke(); TimerUtils.warmup(timer); tzero = TimerUtils.getZeroTime(timer); tfreq = timer.getTicksPerSecond(); } /** * Constructs a RawAccessStatistic. * * @param r Decorated RawAccess * @exception RawAccessException a specialized RuntimeException */ public StatisticsRawAccess(RawAccess r) throws RawAccessException { this(r,50,1.3,1.1); } /** * Resets the counters to zero */ public void resetCounter() { openCalls = 0; closeCalls = 0; readCalls = 0; writeCalls = 0; sequentialAccessCount = 0; sameSectorCount = 0; randomAccessCount = 0; resetCount++; } /** * Opens a device or file * See super class for detailed description * * @param filename name of device or file * @exception RawAccessException a specialized RuntimeException */ public void open(String filename) throws RawAccessException { openCalls++; r.open(filename); } /** * Closes device or file * See super class for detailed description * * @exception RawAccessException a specialized RuntimeException */ public void close() throws RawAccessException { closeCalls++; r.close(); } /** * Calculates if the access is sequential or random. * * @param sector the sector that is accessed. * @param t the time the given sector is accessed. */ private void calcAccess(long sector, long t) { /* System.out.print(sector+" "); try { throw new RuntimeException(); } catch (Exception e) { StackTraceElement st[] = e.getStackTrace(); for (int i=2; i<st.length; i++) System.out.print(st[i].getClassName()+"."+st[i].getMethodName()+"("+st[i].getLineNumber()+") "); System.out.println(); }*/ if (lastSector==sector) sameSectorCount++; else if (lastSector==sector-1) sequentialAccessCount++; else randomAccessCount++; double time = ((double) (t-tzero))/tfreq; histSectorDistance.process(Math.abs(lastSector-sector),time); histTime.process(time,0.0); lastSector = sector; } /** * Writes block to file/device * See super class for detailed description * * @param block array to be written * @param sector number of the sector * @exception RawAccessException a specialized RuntimeException */ public void write(byte[] block, long sector) throws RawAccessException { writeCalls++; timer.start(); r.write(block,sector); t = timer.getDuration(); calcAccess(sector,t); } /** * Reads block from file/device * See super class for detailed description * * @param block byte array of 512 which will be written to the sector * @param sector number of the sector */ public void read(byte[] block, long sector) { readCalls++; timer.start(); r.read(block,sector); t = timer.getDuration(); calcAccess(sector,t); } /** * Returns the amount of sectors in the file/device. * * @return amount of sectors */ public long getNumSectors() { return r.getNumSectors(); } /** * Returns the size of a sector of the file/device. * * @return size of sectors */ public int getSectorSize() { return r.getSectorSize(); } /** * Returns the number of sequential accesses. * @return the number of sequential accesses. */ public int getSequentialAccessCount() { return sequentialAccessCount; } /** * Returns the number of same sector accesses. * @return the number of same sector accesses. */ public int getSameSectorAccessCount() { return sameSectorCount; } /** * Returns the number of random accesses. * @return the number of random accesses. */ public int getRandomAccessCount() { return randomAccessCount; } /** * Outputs the statistics which were gathered. * * @return the statistics as a string. */ public String toString() { return r + "\nopen: "+openCalls+" close: "+closeCalls+" read: "+readCalls+" write: "+writeCalls+ " number of counterresets: "+resetCount+ " sequentialAccess: "+sequentialAccessCount+" randomAccess: "+randomAccessCount+" sameAccess: "+sameSectorCount+ "\n"+ "Sector distance histogram:\n"+histSectorDistance+ "Time histogram:\n"+histTime; } }