sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.memory/src/com/nokia/carbide/cpp/pi/memory/MemTrace.java
changeset 2 b9ab3b238396
child 5 844b047e260d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi.memory/src/com/nokia/carbide/cpp/pi/memory/MemTrace.java	Thu Feb 11 15:32:31 2010 +0200
@@ -0,0 +1,656 @@
+/*
+ * 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.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.Map.Entry;
+
+import org.eclipse.draw2d.IFigure;
+
+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 long intervalStart = -1;
+	transient private long intervalEnd = -1;
+
+	private int version;
+
+	public MemTrace() {
+		firstSynchTimes = new Hashtable<Integer, Integer>();
+		lastSynchTimes = new Hashtable<Integer, Integer>();
+	}
+
+	public void addSample(MemSample sample) {
+		this.samples.add(sample);
+	}
+
+	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;
+					memSample = (MemSample) e.nextElement();
+				}
+
+				// the 2nd sample in each time period has memory model and
+				// CodeSeg data
+				if (memSample.thread.threadId == 0xffffffffbabbea20L) {
+					usedMemory = memSample.heapSize;
+					freeMemory = memSample.stackSize;
+					memSample = (MemSample) e.nextElement();
+				}
+
+				// 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>>();
+		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);
+					memSample = (MemSample) e.nextElement();
+
+				}
+
+				// 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) {
+
+		// 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");
+
+	}
+
+	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;
+
+			// 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 {
+				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 (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 ArrayList<MemSampleByTime> getDrawDataByTime() {
+		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");
+
+			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 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;
+		}
+
+	}
+
+}