sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.memory/src/com/nokia/carbide/cpp/pi/memory/MemTrace.java
author Jussi Ryoma <ext-jussi.s.ryoma@nokia.com>
Tue, 24 Aug 2010 14:01:48 +0300
changeset 16 72f198be1c1d
parent 5 844b047e260d
permissions -rw-r--r--
Crash Analyser Carbide Extension 1.4.0

/*
 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
 * All rights reserved.
 * This component and the accompanying materials are made available
 * under the terms of the License "Eclipse Public License v1.0"
 * which accompanies this distribution, and is available
 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
 *
 * Initial Contributors:
 * Nokia Corporation - initial contribution.
 *
 * Contributors:
 *
 * Description: 
 *
 */

package com.nokia.carbide.cpp.pi.memory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.SortedMap;
import java.util.TreeMap;

import com.nokia.carbide.cpp.internal.pi.analyser.NpiInstanceRepository;
import com.nokia.carbide.cpp.internal.pi.model.GenericSampledTrace;
import com.nokia.carbide.cpp.internal.pi.model.GenericThread;
import com.nokia.carbide.cpp.internal.pi.model.TraceWithThreads;
import com.nokia.carbide.cpp.internal.pi.visual.GenericTraceGraph;
import com.nokia.carbide.cpp.pi.editors.PIPageEditor;

public class MemTrace extends GenericSampledTrace implements TraceWithThreads {
	private static final long serialVersionUID = -2073732380166861141L;

	// Symbian OS memory models
	transient public static final long MEMORY_DIRECT = 0;
	transient public static final long MEMORY_MOVING = 1;
	transient public static final long MEMORY_MULTIPLE = 2;
	transient public static final long MEMORY_UNKNOWN = -1;

	transient private long memoryModel;

	private transient MemTraceGraph[] graphs;

	private Hashtable<Integer, Integer> firstSynchTimes;
	private Hashtable<Integer, Integer> lastSynchTimes;
	private MemThread[] threads;

	// maximums for the entire trace
	transient private int traceMaxChunks = 0;
	transient private int traceMaxStackHeap = 0;
	transient private int traceMaxTotal = 0;

	// maximums found the last time setMaxMemDataByInterval was called
	transient private int intervalMaxChunks = 0;
	transient private int intervalMaxStackHeap = 0;
	transient private int intervalMaxTotal = 0;

	transient private Hashtable<String, TreeMap<Long, MemSample>> drawDataByMemThread = null;
	transient private ArrayList<MemSampleByTime> drawDataByTime;
	transient private HashSet<MemThread> noDuplicateMemThreads;
	
	transient private Hashtable<String, ProfiledLibraryEvent> drawDataByLibraryEvent = null;
	transient private TreeMap<Long, ArrayList<MemSample>> drawLibraryEventDataByTime = null;
	
    transient private LibraryEventColorPalette libraryEventColorPalette = null;
	transient private long intervalStart = -1;
	transient private long intervalEnd = -1;
	
	

	private int version;

	public MemTrace() {
		firstSynchTimes = new Hashtable<Integer, Integer>();
		lastSynchTimes = new Hashtable<Integer, Integer>();
	}

	public MemSample getMemSample(int number) {
		return (MemSample) this.samples.elementAt(number);
	}

	public GenericThread[] getThreads() {
		return threads;
	}

	public void setThreads(MemThread[] threads) {
		this.threads = threads;
	}

	public int getTraceMaxChunks() {
		return traceMaxChunks;
	}

	public int getTraceMaxStackHeap() {
		return traceMaxStackHeap;
	}

	public int getTraceMaxTotal() {
		return traceMaxTotal;
	}

	public void setTraceMaxStackHeap(int traceMaxStackHeap) {
		this.traceMaxStackHeap = traceMaxStackHeap;
	}

	public void setTraceMaxTotal(int traceMaxTotal) {
		this.traceMaxTotal = traceMaxTotal;
	}

	public void setTraceMaxChunks(int traceMaxChunks) {
		this.traceMaxChunks = traceMaxChunks;
	}

	public int getIntervalMaxChunks() {
		return intervalMaxChunks;
	}

	public int getIntervalMaxStackHeap() {
		return intervalMaxStackHeap;
	}

	public int getIntervalMaxTotal() {
		return intervalMaxTotal;
	}

	public int getVersion() {
		return this.version;
	}

	public void setVersion(int version) {
		this.version = version;
	}

	public void addFirstSynchTime(Integer id, Integer firstSynchTime) {
		firstSynchTimes.put(id, firstSynchTime);
	}

	public void addLastSynchTime(Integer id, Integer lastSynchTime) {
		lastSynchTimes.put(id, lastSynchTime);
	}

	public GenericTraceGraph getTraceGraph(int graphIndex) {
		if (graphs == null) {
			graphs = new MemTraceGraph[3];
		}

		// note that graphIndex need not match the index sent to MemTraceGraph
		if ((graphIndex == PIPageEditor.THREADS_PAGE)
				|| (graphIndex == PIPageEditor.BINARIES_PAGE)
				|| (graphIndex == PIPageEditor.FUNCTIONS_PAGE)) {
			if (graphs[graphIndex] == null) {
				int uid = NpiInstanceRepository.getInstance().activeUid();
				graphs[graphIndex] = new MemTraceGraph(graphIndex, this, uid);
			}
			return graphs[graphIndex];
		}
		return null;
	}

	public void gatherDrawData() {
		if (version < 202) {
			gatherSamplingBasedDrawData();
		} else {
			gatherEventBasedDrawData();
		}
	}

	public void gatherSamplingBasedDrawData() {
		if (drawDataByMemThread != null)
			return; // already initialised

		drawDataByMemThread = new Hashtable<String, TreeMap<Long, MemSample>>();
		memoryModel = MemTrace.MEMORY_UNKNOWN;
		getThreadsFromTrace();

		if (drawDataByTime == null)
			drawDataByTime = new ArrayList<MemSampleByTime>();

		long lastTime = Integer.MIN_VALUE;
		ArrayList<MemSample> memSamples = null;

		traceMaxChunks = 0;
		traceMaxStackHeap = 0;
		traceMaxTotal = 0;

		int currentChunks = 0;
		int currentStackHeap = 0;
		int currentTotal = 0;

		long usedMemory = 0;
		long freeMemory = 0;

		// index each sample by thread/process name and by sample time
		MemSample memSample;
		for (Enumeration e = this.getSamples(); e.hasMoreElements();) {
			memSample = (MemSample) e.nextElement();

			if (lastTime != memSample.sampleSynchTime) {
				// the first sample in each time period contains system-wide
				// info
				if (memSample.thread.threadId == 0xffffffffbabbeaaaL) {
					usedMemory = memSample.heapSize;
					freeMemory = memSample.stackSize;
					if(e.hasMoreElements()){
						memSample = (MemSample) e.nextElement();
					}
					else{
						break;
					}
				}

				// the 2nd sample in each time period has memory model and
				// CodeSeg data
				if (memSample.thread.threadId == 0xffffffffbabbea20L) {
					usedMemory = memSample.heapSize;
					freeMemory = memSample.stackSize;
					if(e.hasMoreElements()){
						memSample = (MemSample) e.nextElement();
					}
					else{
						break;
					}
					
				}

				// Create MemSampleByTime object based on sample
				MemSampleByTime memSampleByTime = new MemSampleByTime(
						memSample.sampleSynchTime, usedMemory + freeMemory,
						usedMemory);

				// add sample to drawn samples
				drawDataByTime.add(memSampleByTime);

				// add sample to array that contains all samples
				memSamples = memSampleByTime.getSamples();

				// save time
				lastTime = memSample.sampleSynchTime;

				// find the maximums for the entire graph
				if (currentChunks > traceMaxChunks)
					traceMaxChunks = currentChunks;
				if (currentStackHeap > traceMaxStackHeap)
					traceMaxStackHeap = currentStackHeap;
				if (currentTotal > traceMaxTotal)
					traceMaxTotal = currentTotal;

				currentChunks = 0;
				currentStackHeap = 0;
				currentTotal = 0;
			}

			// Add sample to its thread's data hashtable
			// drawDataByMemThread.get(memSample.thread.fullName).add(memSample);
			drawDataByMemThread.get(memSample.thread.fullName).put(
					memSample.sampleSynchTime, memSample);

			// add sample sample array that contains all samples
			memSamples.add(memSample);

			currentChunks += memSample.heapSize;
			currentStackHeap += memSample.stackSize;
			currentTotal += memSample.heapSize + memSample.stackSize;
		}

		// find the maximums for the entire graph
		if (currentChunks > traceMaxChunks)
			traceMaxChunks = currentChunks;
		if (currentStackHeap > traceMaxStackHeap)
			traceMaxStackHeap = currentStackHeap;
		if (currentTotal > traceMaxTotal)
			traceMaxTotal = currentTotal;
	}

	public void gatherEventBasedDrawData() {
		if (drawDataByMemThread != null)
			return; // already initialised
		drawDataByMemThread = new Hashtable<String, TreeMap<Long, MemSample>>();
		if(version >= 203){
			drawDataByLibraryEvent = new Hashtable<String, ProfiledLibraryEvent>();
		}

		memoryModel = MemTrace.MEMORY_UNKNOWN;
		getThreadsFromTrace();

		if (drawDataByTime == null)
			drawDataByTime = new ArrayList<MemSampleByTime>();

		long lastTime = Integer.MIN_VALUE;
		ArrayList<MemSample> memSamples = null;

		long usedMemory = 0;
		long freeMemory = 0;

		// index each sample by thread/process name and by sample time
		MemSample memSample;
		for (Enumeration e = this.getSamples(); e.hasMoreElements();) {
			memSample = (MemSample) e.nextElement();

			if (lastTime != memSample.sampleSynchTime) {
				// the first sample in each time period contains system-wide
				// info
				if (memSample.thread.threadId == 0xffffffffbabbeaaaL) {
					usedMemory = memSample.heapSize;
					freeMemory = memSample.stackSize;
					addSampleToThread(memSample);
					if(e.hasMoreElements()){
						memSample = (MemSample) e.nextElement();
					}
					else{
						break;
					}

				}

				// Create MemSampleByTime object based on sample
				// MemSampleByTime memSampleByTime = new
				// MemSampleByTime(memSample.sampleSynchTime, usedMemory +
				// freeMemory, usedMemory);

				// add sample to drawn samples
				// drawDataByTime.add(memSampleByTime);

				// add sample to array that contains all samples
				// memSamples = memSampleByTime.getSamples();

				// save time
				lastTime = memSample.sampleSynchTime;

			}

			// Add sample to its thread's data hashtable
			addSampleToThread(memSample);

			// add sample sample array that contains all samples
			// memSamples.add(memSample);
		}

	}

	private void addSampleToThread(MemSample sample) {

		if (version >= 203) {
			String library = getLibraryNameString(sample.thread.fullName);
			if (library != null) {
				ProfiledLibraryEvent ple = drawDataByLibraryEvent.get(library);
				if (ple != null) {
					// Add initial sample to library event
					ple.addMemSample(sample);
					return;
				}
			}

		}
		// get sample array from thread
		TreeMap<Long, MemSample> samples = drawDataByMemThread
				.get(sample.thread.fullName);

		if (sample.type == MemTraceParser.SAMPLE_CODE_DELETE_CHUNK) {
			// event is delete event, set stack and heap size to zero
			sample.stackSize = 0;
			sample.heapSize = 0;
		}

		if (samples != null) {
			// Add initial sample to thread
			samples.put(sample.sampleSynchTime, sample);
			return;
		}

		System.out.println("PI ERROR: Thread not found"); //$NON-NLS-1$

	}

	private void getThreadsFromTrace() {

		noDuplicateMemThreads = new HashSet<MemThread>(131, 0.75f);

		// the parser creates multiple copies of the same MemThread item,
		// so we have to use the full name of the MemThread to access sample
		// data
		for (MemThread memThread : threads) {
			String processedThreadName = memThread.threadName;
			boolean libraryEvent = false;
			// Add Thread ID into processedThreadName
			// looking for _T and _C suffixes and remove them for thread
			if (processedThreadName.endsWith("_T")) //$NON-NLS-1$
			{
				processedThreadName = processedThreadName.substring(0,
						processedThreadName.length() - 2)
						+ "_" + memThread.threadId; //$NON-NLS-1$
			} else if (processedThreadName.endsWith("_C")) { //$NON-NLS-1$
				processedThreadName = processedThreadName.substring(0,
						processedThreadName.length() - 2)
						+ " [0x" + Integer.toHexString(memThread.threadId) + "]"; //$NON-NLS-1$ //$NON-NLS-2$
			} else if (processedThreadName.endsWith("_L")) { //$NON-NLS-1$
				processedThreadName = processedThreadName.substring(0,
						processedThreadName.length() - 2)
						+ " [0x" + Integer.toHexString(memThread.threadId) + "]"; //$NON-NLS-1$ //$NON-NLS-2$
				libraryEvent = true;
			}else {
				processedThreadName += "_" + memThread.threadId; //$NON-NLS-1$
			}

			// Full name contains process name, thread name and thread id
			memThread.fullName = memThread.processName
					+ "::" + processedThreadName; //$NON-NLS-1$

			memThread.enabled = new boolean[3];
			memThread.enabled[0] = true;
			memThread.enabled[1] = true;
			memThread.enabled[2] = true;

			memThread.maxMemoryItem = new MaxMemoryItem();
			memThread.maxMemoryItem.maxChunks = 0;
			memThread.maxMemoryItem.maxStackHeap = 0;
			memThread.maxMemoryItem.maxTotal = 0;

			if (libraryEvent) {
				String name = getLibraryNameString(memThread.fullName);
				if (drawDataByLibraryEvent.get(name) == null) {
					ProfiledLibraryEvent ple = new ProfiledLibraryEvent(name);
					ple.setColor(getLibraryEventColorPalette().getColor(name));
					drawDataByLibraryEvent.put(name, ple);
				}
			} else {
				if (drawDataByMemThread.get(memThread.fullName) == null) {
					drawDataByMemThread.put(memThread.fullName,
							new TreeMap<Long, MemSample>());
					noDuplicateMemThreads.add(memThread);
				}
			}
		}

	}

	public TreeMap<Long, MemSample> getDrawDataByMemThread(MemThread id) {
		return this.drawDataByMemThread.get(id.fullName);
	}
	
	public Hashtable<String, TreeMap<Long, MemSample>> getDrawDataByMemThread() {
		return this.drawDataByMemThread;
	}

	public ArrayList<MemSampleByTime> getDrawDataByTime() {
		if (drawDataByTime.isEmpty() && getVersion() >= 202) {
			TreeMap<Long, MemSample> events = drawDataByMemThread
					.get("TOTAL_MEMORY::TOTAL_MEMORY_-1162089814"); //$NON-NLS-1$

			Iterator<MemSample> iterator = events.values().iterator();
			while (iterator.hasNext()) {
				MemSample memSample = iterator.next();
				drawDataByTime.add(new MemSampleByTime(
						memSample.sampleSynchTime, memSample.stackSize
								+ memSample.heapSize, memSample.heapSize));
			}
		}
		return this.drawDataByTime;
	}

	public HashSet<MemThread> getNoDuplicateMemThreads() {
		return this.noDuplicateMemThreads;
	}

	public ArrayList<MemSample> getMemSampleDataByTime(long time) {
		if ((this.drawDataByTime == null)
				|| (time < this.drawDataByTime.get(0).getTime()))
			return null;

		int i = 0;
		for (; i < this.drawDataByTime.size(); i++) {
			MemSampleByTime sample = this.drawDataByTime.get(i);
			if (sample.getTime() > time)
				break;
		}

		return this.drawDataByTime.get(i - 1).getSamples();
	}

	public MemThread[] getMemThreads() {
		return threads;
	}

	public MaxMemoryItem getSystemUseByInterval(long startTime, long endTime) {
		MaxMemoryItem item = new MaxMemoryItem();

		if ((this.drawDataByTime == null)
				|| ((startTime == intervalStart) && (endTime == intervalEnd)))
			return item;

		if (this.getVersion() >= 202) {
			TreeMap<Long, MemSample> events = drawDataByMemThread
					.get("TOTAL_MEMORY::TOTAL_MEMORY_-1162089814"); //$NON-NLS-1$

			Iterator<MemSample> values = events.values().iterator();

			while (values.hasNext()) {
				MemSample memSample = values.next();
				// store system used memory as chunks and total memory as total
				if (item.maxChunks < memSample.heapSize)
					item.maxChunks = memSample.heapSize;

				if (item.maxTotal < memSample.stackSize + memSample.heapSize)
					item.maxTotal = memSample.stackSize + memSample.heapSize;

				if (memSample.sampleSynchTime > endTime)
					break;

			}

		} else {
			long firstTime = this.drawDataByTime.get(0).getTime();
			if ((startTime < firstTime) && (endTime < firstTime))
				return item;

			MemSampleByTime memSampleByTime;

			int i = 0;

			// find least sampling time greater than or equal to the start index
			for (; i < this.drawDataByTime.size(); i++) {
				if (((MemSampleByTime) this.drawDataByTime.get(i)).getTime() > startTime)
					break;
			}

			if (i != 0)
				i--;

			for (; i < this.drawDataByTime.size(); i++) {
				memSampleByTime = this.drawDataByTime.get(i);

				// store system used memory as chunks and total memory as total
				if (item.maxChunks < memSampleByTime.getUsedMemory())
					item.maxChunks = memSampleByTime.getUsedMemory();

				if (item.maxTotal < memSampleByTime.getTotalMemory())
					item.maxTotal = memSampleByTime.getTotalMemory();

				if (memSampleByTime.getTime() > endTime)
					break;
			}

		}

		return item;
	}

	public void setMaxMemDataByInterval(long startTime, long endTime) {

		// Set all values to zero
		for (int i = 0; i < threads.length; i++) {
			MaxMemoryItem item = threads[i].maxMemoryItem;
			item.maxChunks = 0;
			item.maxStackHeap = 0;
			item.maxTotal = 0;
		}

		// if no data is found between start and end time or start and end
		// times are same with previous.
		if ((this.drawDataByTime == null)
				|| ((startTime == intervalStart) && (endTime == intervalEnd)))
			return;

		if (this.version >= 202) {

			for (Enumeration e = drawDataByMemThread.elements(); e
					.hasMoreElements();) {
				TreeMap<Long, MemSample> memSamples = (TreeMap<Long, MemSample>) e
						.nextElement();

				if (memSamples.size() == 0) {
					continue;
				}

				MemSample firstSample = (MemSample) memSamples.get(memSamples
						.lastKey());

				MemThread thread = firstSample.thread;

				MaxMemoryItem maxMemoryItem = thread.maxMemoryItem;

				SortedMap<Long, MemSample> subMap = memSamples.subMap(
						startTime, endTime);

				ArrayList<MemSample> samples = new ArrayList<MemSample>(subMap
						.values());

				MemSample floorSample = (MemSample) MemTrace
						.getFloorEntryFromMap(startTime, memSamples);

				if (floorSample != null) {

					// TODO check these!
					// MemSample firstSample = floorEntry.getValue();

					if (firstSample != null) {
						samples.add(firstSample);
					}
				}

				for (MemSample item : samples) {
					if (maxMemoryItem.maxChunks < item.heapSize) {
						maxMemoryItem.maxChunks = item.heapSize;
					}
					if (maxMemoryItem.maxStackHeap < item.stackSize) {
						maxMemoryItem.maxStackHeap = item.stackSize;
					}
					if (maxMemoryItem.maxTotal < item.heapSize + item.stackSize) {
						maxMemoryItem.maxTotal = item.heapSize + item.stackSize;
					}

				}

			}

		} else {

			// check that start time is not before first sample's time or end
			// time is not before first sample time
			long firstTime = this.drawDataByTime.get(0).getTime();
			if ((startTime < firstTime) && (endTime < firstTime))
				return;

			MemSampleByTime memSampleByTime;

			int i = 0;

			// find first sample which is greater than start time
			for (; i < this.drawDataByTime.size(); i++) {
				memSampleByTime = this.drawDataByTime.get(i);
				if (memSampleByTime.getTime() > startTime)
					break;
			}

			if (i != 0)
				--i;
			memSampleByTime = this.drawDataByTime.get(i);

			// 
			int size = this.drawDataByTime.size();

			// go thru samples and find max values for chunks and heapsandstacks
			do {
				ArrayList<MemSample> memSamples = memSampleByTime.getSamples();

				for (int j = 0; j < memSamples.size(); j++) {
					MemSample memSample = memSamples.get(j);
					MemThread memThread = memSample.thread;
					MaxMemoryItem maxMemoryItem = memThread.maxMemoryItem;

					if (maxMemoryItem == null)
						continue;

					if (maxMemoryItem.maxChunks < memSample.heapSize)
						maxMemoryItem.maxChunks = memSample.heapSize;
					if (maxMemoryItem.maxStackHeap < memSample.stackSize)
						maxMemoryItem.maxStackHeap = memSample.stackSize;
					if (maxMemoryItem.maxTotal < memSample.heapSize
							+ memSample.stackSize)
						maxMemoryItem.maxTotal = memSample.heapSize
								+ memSample.stackSize;

					// find the maximums for all threads/processes in the
					// interval
					if (memSample.heapSize > traceMaxChunks)
						intervalMaxChunks = memSample.heapSize;
					if (memSample.stackSize > traceMaxStackHeap)
						intervalMaxStackHeap = memSample.stackSize;
					if (memSample.heapSize + memSample.stackSize > traceMaxTotal)
						intervalMaxTotal = memSample.heapSize
								+ memSample.stackSize;
				}
				i++;
				if (i < size)
					memSampleByTime = this.drawDataByTime.get(i);
				else
					break;
			} while (memSampleByTime.getTime() <= endTime);

		}

		return;
	}
		
	public void setMaxMemLibraryEventDataByInterval(long startTime, long endTime) {
		// update memory usage for each library event that are used during the time slot
		for (Enumeration<ProfiledLibraryEvent> e = drawDataByLibraryEvent
				.elements(); e.hasMoreElements();) {
			ProfiledLibraryEvent ple = (ProfiledLibraryEvent) e
					.nextElement();
			ple.updateSelection(startTime, endTime);
		}
	}

	public long getMemoryModel() {
		return this.memoryModel;
	}

	public void setMemoryModel(long memoryModel) {
		if (memoryModel == MemTrace.MEMORY_DIRECT
				|| memoryModel == MemTrace.MEMORY_MOVING
				|| memoryModel == MemTrace.MEMORY_MULTIPLE)
			this.memoryModel = memoryModel;
		else
			this.memoryModel = MemTrace.MEMORY_UNKNOWN;
	}

	public static Object getFloorEntryFromMap(long key, TreeMap map) {
		// TODO if JDK 6 is in use this should be used:
		// return map.floorEntry(key).getValue();

		// when JDK 5 in use use this:
		try {
			SortedMap headMap = map.headMap(key);
			return headMap.get(headMap.lastKey());
		} catch (Exception e) {
			return null;
		}

	}
	
	public Hashtable<String, ProfiledLibraryEvent> getLibraryEvents(){
		return drawDataByLibraryEvent;
	}
	
	public LibraryEventColorPalette getLibraryEventColorPalette(){
		if(libraryEventColorPalette == null){
			libraryEventColorPalette = new LibraryEventColorPalette();
		}
		return libraryEventColorPalette;
	}
	
	
	public ArrayList<MemSample> getLibraryEventDataByTime(int graphIndex, long time, long scale) {
		if(drawLibraryEventDataByTime == null){
			// find library events by time
			drawLibraryEventDataByTime = new TreeMap<Long, ArrayList<MemSample>>();
			Iterator<ProfiledLibraryEvent> iterator = drawDataByLibraryEvent.values().iterator();
			while(iterator.hasNext()){	
				ProfiledLibraryEvent ple = iterator.next();	
				Iterator<MemSample> iteratorMem = ple.getMemSamples().values().iterator();
				while(iteratorMem.hasNext()){
					MemSample memSample = iteratorMem.next();
					ArrayList<MemSample> memSamples = drawLibraryEventDataByTime.get(memSample.sampleSynchTime);
					if(memSamples == null){
						memSamples = new ArrayList<MemSample>();
					}
					memSamples.add(memSample);					
					drawLibraryEventDataByTime.put(memSample.sampleSynchTime, memSamples);
				}		
			}
		}		
		
		ArrayList<MemSample> retMemSamples = new ArrayList<MemSample>();
		ArrayList<MemSample> bestChoice = null;
		scale = (long)scale * 5;
		
		if(scale == 0){
			bestChoice = drawLibraryEventDataByTime.get(time);
		} else {	
			SortedMap<Long, ArrayList<MemSample>> sortedMap = drawLibraryEventDataByTime
					.subMap(time - scale, time + scale);
			long min = Long.MAX_VALUE;
			long closest = time;
			for (Long key : sortedMap.keySet()) {
				final long diff = Math.abs(key - time);
				if (diff < min) {
					Iterator<MemSample> iterator = sortedMap.get(key).iterator();
					while(iterator.hasNext()){
						MemSample memSample = iterator.next();
						if(memSample.thread.isEnabled(graphIndex)){
							min = diff;
							closest = key;
						}
					}					
				}
			}
			bestChoice = sortedMap.get(closest);			
		}
		if(bestChoice != null){
			Iterator<MemSample> iterator = bestChoice.iterator();
			while(iterator.hasNext()){
				MemSample memSample = iterator.next();
				if(memSample.thread.isEnabled(graphIndex)){
					retMemSamples.add(memSample);
				}
			}
		}
		return retMemSamples;
	}	
	
	public String getLibraryNameString(String fullName){
		int startIndex = fullName.indexOf("::") + 2; //$NON-NLS-1$
		int lastIndex = fullName.indexOf(" ["); //$NON-NLS-1$
		if(startIndex != -1 && lastIndex != -1){
			return fullName.substring(startIndex, lastIndex);
		}
		return null;
	}
	
	public String getProcessFromLibraryNameString(String fullName){
		int lastIndex = fullName.indexOf("::"); //$NON-NLS-1$
		if(lastIndex != -1){
			return fullName.substring(0, lastIndex);
		}
		return null;
	}

}