TraceDataByRank.java

Go to the documentation of this file.
00001 package edu.rice.cs.hpc.traceviewer.data.db;
00002 
00003 import java.util.Arrays;
00004 import java.util.Vector;
00005 
00006 import edu.rice.cs.hpc.data.experiment.extdata.AbstractBaseData;
00007 import edu.rice.cs.hpc.data.util.Constants;
00008 import edu.rice.cs.hpc.traceviewer.data.util.Debugger;
00009 
00010 public class TraceDataByRank {
00011 
00012     //  tallent: safe to assume version 1.01 and greater here
00013     public final static int HeaderSzMin = Header.MagicLen + Header.VersionLen + Header.EndianLen + Header.FlagsLen;
00014     public final static int RecordSzMin = Constants.SIZEOF_LONG // time stamp
00015                                         + Constants.SIZEOF_INT; // call path id
00016     
00017     //These must be initialized in local mode. They should be considered final unless the data is remote.
00019     public Header header;
00020     private AbstractBaseData data;
00021     private int numPixelH;
00022     int rank;
00023     
00024     protected Vector<DataRecord> listcpid;
00025     
00026     /***
00027      * Create a new instance of trace data for a given rank of process or thread 
00028      * Used only for local
00029      * @param _data
00030      * @param _rank
00031      * @param _numPixelH
00032      */
00033     public TraceDataByRank(AbstractBaseData _data, int _rank, int _numPixelH)
00034     {
00035 
00036     
00037         //:'( This is a safe cast because this constructor is only
00038         //called in local mode but it's so ugly....
00039         data = _data;
00040         rank = _rank;
00041         numPixelH = _numPixelH;
00042 
00043         final long offsets[] = data.getOffsets();
00044         final long begHeader = offsets[rank];
00045         header = getHeader(begHeader);
00046         
00047         listcpid = new Vector<DataRecord>(numPixelH);
00048     }
00049     
00050     public boolean isEmpty() {
00051         return listcpid == null || listcpid.size()==0;
00052     }
00053     
00054     public TraceDataByRank(DataRecord[] data) {
00055         listcpid = new Vector<DataRecord>(Arrays.asList(data));
00056     }
00057     
00058     /***
00059      * reading data from file
00060      * 
00061      * @param timeStart
00062      * @param timeRange
00063      * @param pixelLength : number of records
00064      */
00065     public void getData(long timeStart, long timeRange, double pixelLength)
00066     {
00067             
00068         long minloc = data.getMinLoc(rank);
00069         long maxloc = data.getMaxLoc(rank, header.RecordSz);
00070         
00071         Debugger.printDebug(4, "getData loc [" + minloc+","+ maxloc + "]");
00072         
00073         // get the start location
00074         final long startLoc = this.findTimeInInterval(timeStart, minloc, maxloc);
00075         
00076         // get the end location
00077         final long endTime = timeStart + timeRange;
00078         final long endLoc = Math.min(this.findTimeInInterval(endTime, minloc, maxloc) + header.RecordSz, maxloc );
00079 
00080         // get the number of records data to display
00081         final long numRec = 1+this.getNumberOfRecords(startLoc, endLoc);
00082         
00083         // --------------------------------------------------------------------------------------------------
00084         // if the data-to-display is fit in the display zone, we don't need to use recursive binary search
00085         //  we just simply display everything from the file
00086         // --------------------------------------------------------------------------------------------------
00087         if (numRec<=numPixelH) {
00088             
00089             // display all the records
00090             for(long i=startLoc;i<=endLoc; ) {
00091                 listcpid.add(getData(i));
00092                 // one record of data contains of an integer (cpid) and a long (time)
00093                 i =  i + header.RecordSz;
00094             }
00095             
00096         } else {
00097             
00098             // the data is too big: try to fit the "big" data into the display
00099             
00100             //fills in the rest of the data for this process timeline
00101             this.sampleTimeLine(startLoc, endLoc, 0, numPixelH, 0, pixelLength, timeStart);
00102             
00103         }
00104         
00105         // --------------------------------------------------------------------------------------------------
00106         // get the last data if necessary: the rightmost time is still less then the upper limit
00107         //  I think we can add the rightmost data into the list of samples
00108         // --------------------------------------------------------------------------------------------------
00109         if (endLoc < maxloc) {
00110             final DataRecord dataLast = this.getData(endLoc);
00111             this.addSample(listcpid.size(), dataLast);
00112         }
00113         
00114         // --------------------------------------------------------------------------------------------------
00115         // get the first data if necessary: the leftmost time is still bigger than the lower limit
00116         //  similarly, we add to the list 
00117         // --------------------------------------------------------------------------------------------------
00118         if ( startLoc > minloc ) {
00119             final DataRecord dataFirst = this.getData(startLoc - header.RecordSz);
00120             this.addSample(0, dataFirst);
00121         }
00122 
00123         
00124         postProcess();
00125         
00126     }
00127     
00128     
00130     public long getTime(int sample)
00131     {
00132         if(sample<0)
00133             return 0;
00134 
00135         final int last_index = listcpid.size();
00136         if(sample>=last_index) {
00137             return listcpid.get(last_index-1).timestamp;
00138         }
00139         return listcpid.get(sample).timestamp;
00140     }
00141     
00143     public int getCpid(int sample)
00144     {
00145         return listcpid.get(sample).cpId;
00146     }
00147     
00148     public int getMetricId(int sample)
00149     {
00150         return listcpid.get(sample).metricId;
00151     }
00152 
00153     
00155     public void shiftTimeBy(long lowestStartingTime)
00156     {
00157         for(int i = 0; i<listcpid.size(); i++)
00158         {
00159             DataRecord timecpid = listcpid.get(i);
00160             timecpid.timestamp = timecpid.timestamp - lowestStartingTime;
00161             listcpid.set(i,timecpid);
00162         }
00163     }
00164 
00165     
00166     
00168     public int size()
00169     {
00170         return listcpid.size();
00171     }
00172 
00173     
00179     public int findMidpointBefore(long time, boolean usingMidpoint)
00180     {
00181         if (listcpid.size()==0)
00182             return 0;
00183 
00184         int low = 0;
00185         int high = listcpid.size() - 1;
00186         
00187         long timeMin = listcpid.get(low).timestamp;
00188         long timeMax = listcpid.get(high).timestamp;
00189         
00190         // do not search the sample if the time is out of range
00191         if (time<timeMin  || time>timeMax) 
00192             return -1;
00193         
00194         int mid = ( low + high ) / 2;
00195         
00196         while( low != mid )
00197         {
00198             final long time_current = (usingMidpoint ? getTimeMidPoint(mid,mid+1) : listcpid.get(mid).timestamp);
00199             
00200             if (time > time_current)
00201                 low = mid;
00202             else
00203                 high = mid;
00204             mid = ( low + high ) / 2;
00205             
00206         }
00207         if (usingMidpoint)
00208         {
00209             if (time >= getTimeMidPoint(low,low+1))
00210                 return low+1;
00211             else
00212                 return low;
00213         } else 
00214         {
00215             // without using midpoint, we adopt the leftmost sample approach.
00216             // this means whoever on the left side, it will be the painted
00217             return low;
00218         }
00219     }
00220 
00221     
00222     
00223     private long getTimeMidPoint(int left, int right) {
00224         return (listcpid.get(left).timestamp + listcpid.get(right).timestamp) / 2;
00225     }
00226     
00227     /*******************************************************************************************
00228      * Recursive method that fills in times and timeLine with the correct data from the file.
00229      * Takes in two pixel locations as endpoints and finds the timestamp that owns the pixel
00230      * in between these two. It then recursively calls itself twice - once with the beginning 
00231      * location and the newfound location as endpoints and once with the newfound location 
00232      * and the end location as endpoints. Effectively updates times and timeLine by calculating 
00233      * the index in which to insert the next data. This way, it keeps times and timeLine sorted.
00234      * @author Reed Landrum and Michael Franco
00235      * @param minLoc The beginning location in the file to bound the search.
00236      * @param maxLoc The end location in the file to bound the search.
00237      * @param startPixel The beginning pixel in the image that corresponds to minLoc.
00238      * @param endPixel The end pixel in the image that corresponds to maxLoc.
00239      * @param minIndex An index used for calculating the index in which the data is to be inserted.
00240      * @return Returns the index that shows the size of the recursive subtree that has been read.
00241      * Used for calculating the index in which the data is to be inserted.
00242      ******************************************************************************************/
00243     private int sampleTimeLine(long minLoc, long maxLoc, int startPixel, int endPixel, int minIndex, 
00244             double pixelLength, long startingTime)
00245     {
00246         int midPixel = (startPixel+endPixel)/2;
00247         if (midPixel == startPixel)
00248             return 0;
00249         
00250         long loc = findTimeInInterval((long)(midPixel*pixelLength)+startingTime, minLoc, maxLoc);
00251         
00252         final DataRecord nextData = this.getData(loc);
00253         
00254         addSample(minIndex, nextData);
00255         
00256         int addedLeft = sampleTimeLine(minLoc, loc, startPixel, midPixel, minIndex, pixelLength, startingTime);
00257         int addedRight = sampleTimeLine(loc, maxLoc, midPixel, endPixel, minIndex+addedLeft+1, pixelLength, startingTime);
00258         
00259         return (addedLeft+addedRight+1);
00260     }
00261     
00262     /*********************************************************************************
00263      *  Returns the location in the traceFile of the trace data (time stamp and cpid)
00264      *  Precondition: the location of the trace data is between minLoc and maxLoc.
00265      * @param time: the time to be found
00266      * @param left_boundary_offset: the start location. 0 means the beginning of the data in a process
00267      * @param right_boundary_offset: the end location.
00268      ********************************************************************************/
00269     private long findTimeInInterval(long time, long left_boundary_offset, long right_boundary_offset)
00270     {
00271         if (left_boundary_offset == right_boundary_offset) return left_boundary_offset;
00272 
00273         long left_index = getRelativeLocation(left_boundary_offset);
00274         long right_index = getRelativeLocation(right_boundary_offset);
00275         
00276         long left_time = data.getLong(left_boundary_offset);
00277         long right_time = data.getLong(right_boundary_offset);
00278         
00279         // apply "Newton's method" to find target time
00280         while (right_index - left_index > 1) {
00281             long predicted_index;
00282             double rate = (right_time - left_time) / (right_index - left_index);
00283             long mtime = (right_time - left_time) / 2;
00284             if (time <= mtime) {
00285                 predicted_index = Math.max((long) ((time - left_time) / rate) + left_index, left_index);
00286             } else {
00287                 predicted_index = Math.min((right_index - (long) ((right_time - time) / rate)), right_index); 
00288 /*              if (tmp_index<0) {
00289                     predicted_index = Math.max(tmp_index, left_index);
00290                 } else {
00291                     // original code: predicted_index = Math.min((right_index - (long) ((right_time - time) / rate)), right_index);
00292                     predicted_index = Math.min(tmp_index, right_index);
00293                 }*/
00294                 
00295             }
00296             
00297             // adjust so that the predicted index differs from both ends
00298             // except in the case where the interval is of length only 1
00299             // this helps us achieve the convergence condition
00300             if (predicted_index <= left_index) 
00301                 predicted_index = left_index + 1;
00302             if (predicted_index >= right_index)
00303                 predicted_index = right_index - 1;
00304 
00305             long temp = data.getLong(getAbsoluteLocation(predicted_index));
00306             if (time >= temp) {
00307                 left_index = predicted_index;
00308                 left_time = temp;
00309             } else {
00310                 right_index = predicted_index;
00311                 right_time = temp;
00312             }
00313         }
00314         long left_offset = getAbsoluteLocation(left_index);
00315         long right_offset = getAbsoluteLocation(right_index);
00316 
00317         left_time = data.getLong(left_offset);
00318         right_time = data.getLong(right_offset);
00319 
00320         // return the closer sample or the maximum sample if the 
00321         // time is at or beyond the right boundary of the interval
00322         final boolean is_left_closer = Math.abs(time - left_time) < Math.abs(right_time - time);
00323         long maxloc = data.getMaxLoc(rank, header.RecordSz);
00324         
00325         if ( is_left_closer ) return left_offset;
00326         else if (right_offset < maxloc) return right_offset;
00327         else return maxloc;
00328     }
00329     
00330     private long getAbsoluteLocation(long relativePosition)
00331     {
00332         return data.getMinLoc(rank) + (relativePosition * header.RecordSz);
00333     }
00334     
00335     private long getRelativeLocation(long absolutePosition)
00336     {
00337         return (absolutePosition-data.getMinLoc(rank)) / header.RecordSz;
00338     }
00339     
00340     
00342     public void addSample( int index, DataRecord datacpid)
00343     {       
00344         if (index == listcpid.size())
00345         {
00346             this.listcpid.add(datacpid);
00347         }
00348         else
00349         {
00350             this.listcpid.add(index, datacpid);
00351         }
00352     }
00353 
00354     
00355     public Vector<DataRecord> getListOfData()
00356     {
00357         return this.listcpid;
00358     }
00359     
00360     
00361     public void setListOfData(Vector<DataRecord> anotherList)
00362     {
00363         this.listcpid = anotherList;
00364     }
00365     
00366     
00367     private Header getHeader(long begHeader)
00368     {
00369         int headerSz = 0;
00370         final String filename = ""; // FIXME
00371         
00372         final long begMagic   = begHeader;
00373         final long begVersion = begMagic   + Header.MagicLen;
00374         final long begEndian  = begVersion + Header.VersionLen;
00375         final long begFlags   = begEndian  + Header.EndianLen;
00376 
00377         final String magicStr = data.getString(begMagic, Header.MagicLen);
00378         headerSz += Header.MagicLen;
00379         if (!magicStr.contentEquals(Header.Magic)) {
00380             System.err.println("Error: trace file has bad header: " + filename);
00381         }
00382         
00383         final String versionStr = data.getString(begVersion, Header.VersionLen);
00384         headerSz += Header.VersionLen;
00385         final double version = new Double(versionStr);
00386         if ( !(version >= 1.0) ) {
00387             System.err.println("Error: trace file has bad version: " + filename);
00388         }
00389         
00390         final String endianStr = data.getString(begEndian, Header.EndianLen);
00391         headerSz += Header.EndianLen;
00392         if (!endianStr.contentEquals(Header.Endian)) {
00393             System.err.println("Error: trace file has bad endianness: " + filename);
00394         }
00395 
00396         long flags = 0;
00397         if (version > 1.00) {
00398             flags = data.getLong(begFlags);
00399             headerSz += Header.FlagsLen;
00400         }
00401 
00402         if (data.getHeaderSize() != headerSz) {
00403             System.err.println("Error: trace file has unknown header: " + filename);
00404         }
00405             
00406         return new Header(version, flags);
00407     }
00408 
00409     
00410     private DataRecord getData(long location)
00411     {
00412         final long time = data.getLong(location);
00413         final int cpId = data.getInt(location + Constants.SIZEOF_LONG);
00414         int metricId = edu.rice.cs.hpc.traceviewer.data.util.Constants.dataIdxNULL;
00415         if (header.isDataCentric) {
00416             metricId = data.getInt(location + Constants.SIZEOF_LONG + Constants.SIZEOF_INT);
00417         }
00418         
00419         return new DataRecord(time, cpId, metricId);
00420     }
00421     
00422     private long getNumberOfRecords(long start, long end)
00423     {
00424         return (end-start) / (header.RecordSz);
00425     }
00426 
00427     /*********************************************************************************************
00428      * Removes unnecessary samples:
00429      * i.e. if timeLine had three of the same cpid's in a row, the middle one would be superfluous,
00430      * as we would know when painting that it should be the same color all the way through.
00431      ********************************************************************************************/
00432     private void postProcess()
00433     {
00434         int len = listcpid.size();
00435         for(int i = 0; i < len-2; i++)
00436         {
00437             while(i < len-1 && listcpid.get(i).timestamp==(listcpid.get(i+1).timestamp))
00438             {
00439                 listcpid.remove(i+1);
00440                 len--;
00441             }
00442         }
00443     }
00444         
00445     public int getRank()
00446     {
00447         return rank;
00448     }   
00449 }

Generated on 5 May 2015 for HPCVIEWER by  doxygen 1.6.1