From: Bernd Hufmann Date: Tue, 24 Jan 2012 16:27:45 +0000 (-0500) Subject: Added latency analysis feature (bug 331467) X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=fbd124ddfe08ba05a96e6fee1faeceb82e08a479;hp=e8689c0fff4fc9d025a2d94d5364ad7ea89189e7;p=deliverable%2Ftracecompass.git Added latency analysis feature (bug 331467) --- diff --git a/org.eclipse.linuxtools.lttng.core/META-INF/MANIFEST.MF b/org.eclipse.linuxtools.lttng.core/META-INF/MANIFEST.MF index a8275a04e2..1ac8175feb 100644 --- a/org.eclipse.linuxtools.lttng.core/META-INF/MANIFEST.MF +++ b/org.eclipse.linuxtools.lttng.core/META-INF/MANIFEST.MF @@ -17,6 +17,7 @@ Export-Package: org.eclipse.linuxtools.lttng.core, org.eclipse.linuxtools.lttng.core.control, org.eclipse.linuxtools.lttng.core.event, org.eclipse.linuxtools.lttng.core.exceptions, + org.eclipse.linuxtools.lttng.core.latency.analyzer, org.eclipse.linuxtools.lttng.core.model, org.eclipse.linuxtools.lttng.core.request, org.eclipse.linuxtools.lttng.core.signal, @@ -28,7 +29,9 @@ Export-Package: org.eclipse.linuxtools.lttng.core, org.eclipse.linuxtools.lttng.core.state.resource, org.eclipse.linuxtools.lttng.core.state.trace, org.eclipse.linuxtools.lttng.core.trace, + org.eclipse.linuxtools.lttng.core.tracecontrol, org.eclipse.linuxtools.lttng.core.tracecontrol.model, org.eclipse.linuxtools.lttng.core.tracecontrol.model.config, - org.eclipse.linuxtools.lttng.core.tracecontrol.service + org.eclipse.linuxtools.lttng.core.tracecontrol.service, + org.eclipse.linuxtools.lttng.core.util Bundle-Localization: plugin diff --git a/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/latency/analyzer/EventMatcher.java b/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/latency/analyzer/EventMatcher.java new file mode 100644 index 0000000000..721efadfe7 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/latency/analyzer/EventMatcher.java @@ -0,0 +1,505 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse + * Public License v1.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.core.latency.analyzer; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Set; +import java.util.Stack; +import java.util.Vector; + +import org.eclipse.linuxtools.lttng.core.event.LttngEvent; +import org.eclipse.linuxtools.lttng.core.util.EventsPair; + +/** + * EventMatcher + *

+ * Event matching class. Saves events in a list and returns the previously saved event if the currently processed one is + * its response, so that the latency can be computed by subtracting their respective timestamps. + * + * @author Philippe Sawicki + */ +public class EventMatcher { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * Class instance (Singleton pattern). + */ + private static EventMatcher fInstance = null; + + /** + * Stack abstraction, used to save the events in a list. + */ + private StackWrapper fStack; + + /** + * Match table, associates a request class to a response class. + */ + private HashMap fMatch; + /** + * Inverse match table, associates a response class to a request class. + */ + private HashMap fInverseMatch; + + /** + * The number of events processed. + */ + private int fProcessedEvents; + /** + * The number of events matched. + */ + private int fMatchedEvents; + + /** + * Event types identification Strings. + */ + @SuppressWarnings("nls") + public static String + ADD_TO_PAGE_CACHE = "add_to_page_cache", + BIO_BACKMERGE = "bio_backmerge", + BIO_FRONTMERGE = "bio_frontmerge", + BIO_QUEUE = "bio_queue", + BUFFER_WAIT_END = "buffer_wait_end", + BUFFER_WAIT_START = "buffer_wait_start", + CALL = "call", + CLOSE = "close", + CORE_MARKER_FORMAT = "core_marker_format", + CORE_MARKER_ID = "core_marker_id", + DEV_RECEIVE = "dev_receive", + DEV_XMIT = "dev_xmit", + END_COMMIT = "end_commit", + EXEC = "exec", + FILE_DESCRIPTOR = "file_descriptor", + GETRQ = "getrq", + GETRQ_BIO = "getrq_bio", + IDT_TABLE = "idt_table", + INTERRUPT = "interrupt", + IOCTL = "ioctl", + IRQ_ENTRY = "irq_entry", + IRQ_EXIT = "irq_exit", + LIST_MODULE = "list_module", + LLSEEK = "llseek", + LSEEK = "lseek", + NAPI_COMPLETE = "napi_complete", + NAPI_POLL = "napi_poll", + NAPI_SCHEDULE = "napi_schedule", + NETWORK_IPV4_INTERFACE = "network_ipv4_interface", + NETWORK_IP_INTERFACE = "network_ip_interface", + OPEN = "open", + PAGE_FAULT_ENTRY = "page_fault_entry", + PAGE_FAULT_EXIT = "page_fault_exit", + PAGE_FAULT_GET_USER_ENTRY = "page_fault_get_user_entry", + PAGE_FAULT_GET_USER_EXIT = "page_fault_get_user_exit", + PAGE_FREE = "page_free", + PLUG = "plug", + POLLFD = "pollfd", + PREAD64 = "pread64", + PRINTF = "printf", + PRINTK = "printk", + PROCESS_EXIT = "process_exit", + PROCESS_FORK = "process_fork", + PROCESS_FREE = "process_free", + PROCESS_STATE = "process_state", + PROCESS_WAIT = "process_wait", + READ = "read", + REMAP = "remap", + REMOVE_FROM_PAGE_CACHE = "remove_from_page_cache", + RQ_COMPLETE_FS = "rq_complete_fs", + RQ_COMPLETE_PC = "rq_complete_pc", + RQ_INSERT_FS = "rq_insert_fs", + RQ_INSERT_PC = "rq_insert_pc", + RQ_ISSUE_FS = "rq_issue_fs", + RQ_ISSUE_PC = "rq_issue_pc", + RQ_REQUEUE_PC = "rq_requeue_pc", + SCHED_MIGRATE_TASK = "sched_migrate_task", + SCHED_SCHEDULE = "sched_schedule", + SCHED_TRY_WAKEUP = "sched_try_wakeup", + SCHED_WAKEUP_NEW_TASK = "sched_wakeup_new_task", + SELECT = "select", + SEM_CREATE = "sem_create", + SEND_SIGNAL = "send_signal", + SHM_CREATE = "shm_create", + SLEEPRQ_BIO = "sleeprq_bio", + SOCKET_ACCEPT = "socket_accept", + SOCKET_BIND = "socket_bind", + SOCKET_CALL = "socket_call", + SOCKET_CONNECT = "socket_connect", + SOCKET_CREATE = "socket_create", + SOCKET_GETPEERNAME = "socket_getpeername", + SOCKET_GETSOCKNAME = "socket_getsockname", + SOCKET_GETSOCKOPT = "socket_getsockopt", + SOCKET_LISTEN = "socket_listen", + SOCKET_SETSOCKOPT = "socket_setsockopt", + SOCKET_SHUTDOWN = "socket_shutdown", + SOCKET_SOCKETPAIR = "socket_socketpair", + SOFTIRQ_ENTRY = "softirq_entry", + SOFTIRQ_EXIT = "softirq_exit", + SOFTIRQ_RAISE = "softirq_raise", + SOFTIRQ_VEC = "softirq_vec", + START_COMMIT = "start_commit", + STATEDUMP_END = "statedump_end", + SYS_CALL_TABLE = "sys_call_table", + SYSCALL_ENTRY = "syscall_entry", + SYSCALL_EXIT = "syscall_exit", + TASKLET_LOW_ENTRY = "tasklet_low_entry", + TASKLET_LOW_EXIT = "tasklet_low_exit", + TCPV4_RCV = "tcpv4_rcv", + TIMER_ITIMER_EXPIRED = "timer_itimer_expired", + TIMER_ITIMER_SET = "timer_itimer_set", + TIMER_SET = "timer_set", + TIMER_TIMEOUT = "timer_timeout", + TIMER_UPDATE_TIME = "timer_update_time", + UDPV4_RCV = "udpv4_rcv", + UNPLUG_IO = "unplug_io", + UNPLUG_TIMER = "unplug_timer", + VM_MAP = "vm_map", + VPRINTK = "vprintk", + WAIT_ON_PAGE_END = "wait_on_page_end", + WAIT_ON_PAGE_START = "wait_on_page_start", + WRITE = "write", + WRITEV = "writev"; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Private constructor to defeat instantiation (Singleton pattern). + */ + private EventMatcher() { + fStack = new StackWrapper(); + fMatch = new HashMap(); + fInverseMatch = new HashMap(); + + fProcessedEvents = 0; + fMatchedEvents = 0; + + createMatchTable(); + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + /** + * Returns an instance to the EventMatcher class (Singleton pattern). + * @return An instance to the EventMatcher class (Singleton pattern). + */ + public static EventMatcher getInstance() { + if (fInstance == null) + fInstance = new EventMatcher(); + return fInstance; + } + + /** + * Returns the number of events processed. + * @return The number of events processed. + */ + public int getNBProcessedEvents() { + return fProcessedEvents; + } + + /** + * Returns the number of events matched. + * @return The number of events matched. + */ + public int getNBMatchedEvents() { + return fMatchedEvents; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /** + * Releases the instance to the EventMatcher class. + */ + public static void releaseInstance() { + fInstance = null; + } + + /** + * Creates the event matching table, linking a response class to a request class. + */ + private void createMatchTable() { + // Build the default matches + fMatch.put(PAGE_FAULT_GET_USER_EXIT, PAGE_FAULT_GET_USER_ENTRY); + fMatch.put(TASKLET_LOW_EXIT, TASKLET_LOW_ENTRY); + fMatch.put(PAGE_FAULT_EXIT, PAGE_FAULT_ENTRY); + fMatch.put(SYSCALL_EXIT, SYSCALL_ENTRY); + fMatch.put(IRQ_EXIT, IRQ_ENTRY); + fMatch.put(WRITE, READ); + fMatch.put(CLOSE, OPEN); + fMatch.put(BUFFER_WAIT_END, BUFFER_WAIT_START); + fMatch.put(END_COMMIT, START_COMMIT); + fMatch.put(WAIT_ON_PAGE_END, WAIT_ON_PAGE_START); + + // Build the inverse matches based on the matches + Set> pairs = fMatch.entrySet(); + Iterator> it = pairs.iterator(); + while (it.hasNext()) { + Entry pair = it.next(); + fInverseMatch.put(pair.getValue(), pair.getKey()); + } + } + + /** + * Processes an event received: if it is identified as a response, try to get its request to remove it from the + * list. If no request was saved, dismiss the current response. If it is a request, save it to the list of requests + * waiting for a response. + * @param event + * The event to identify, and maybe process if it is a response. + * @return The request event associated with the current event (a response), or null if nothing was found (no + * request associated with this response, or the event to identify was a request that was added to the + * list). + */ + public LttngEvent process(LttngEvent event) { + fProcessedEvents++; + + String markerName = event.getMarkerName(); + if (fMatch.containsKey(markerName)) { + String startEventType = fMatch.get(markerName); + Stack events = fStack.getStackOf(startEventType); + + if (events != null) { + for (int i = events.size() - 1; i >= 0; i--) { + LttngEvent request = events.get(i); + + if (request.getCpuId() == event.getCpuId() && event.getTimestamp().getValue() > request.getTimestamp().getValue()) { + fStack.removeEvent(startEventType, request); + fMatchedEvents++; + return request; + } + } + } + return null; + } else { + // Add only if there can later be a match for this request + if (fMatch.containsValue(event.getMarkerName())) { + fStack.put(event.clone()); + } + return null; + } + } + + /** + * Clears the stack content. + */ + public void clearStack() { + fStack.clear(); + + // Reset the processed and matched events counter + fProcessedEvents = 0; + fMatchedEvents = 0; + } + + /** + * Resets all. + */ + public void resetMatches() { + fMatch.clear(); + fInverseMatch.clear(); + + fStack.clear(); + + // Reset the processed and matched events counter + fProcessedEvents = 0; + fMatchedEvents = 0; + } + + /** + * Returns the list of start events. + * @return The list of start events. + */ + public Collection getStartEvents() { + return fMatch.values(); + } + + /** + * Returns the list of end events. + * @return The list of end events. + */ + public Set getEndEvents() { + return fMatch.keySet(); + } + + /** + * Returns the alphabetically-sorted list of start/end events pairs. + * @return The alphabetically-sorted list of start/end events pairs. + */ + public EventsPair getEvents() { + Vector start = new Vector(getStartEvents()); + Vector end = new Vector(fMatch.size()); + + Collections.sort(start); + for (int i = 0; i < start.size(); i++) { + end.add(fInverseMatch.get(start.get(i))); + } + return new EventsPair(start, end); + } + + /** + * Adds a match to the list of events pairs. + * @param startType + * The start event type. + * @param endType + * The end event type. + */ + public void addMatch(String startType, String endType) { + fMatch.put(endType, startType); + fInverseMatch.put(startType, endType); + } + + /** + * Removes a matched pair based on the their type. + * + * Note : For now, only the pair's end type is used, since a type can only be either one start or one end. + * This function takes both types to account for the future, if a pairing process ever becomes more complex. + * + * @param startType + * The type of the pair's start type. + * @param endType + * The type of the pair's end type. + */ + public void removeMatch(String startType, String endType) { + fMatch.remove(endType); + fInverseMatch.remove(startType); + } + + /** + * Returns the list of all event possible types. + * @return The list of all event possible types. + */ + public Vector getTypeList() { + // Reserve some space for the 103 default event types. + Vector eventsList = new Vector(103); + + eventsList.add(ADD_TO_PAGE_CACHE); + eventsList.add(BIO_BACKMERGE); + eventsList.add(BIO_FRONTMERGE); + eventsList.add(BIO_QUEUE); + eventsList.add(BUFFER_WAIT_END); + eventsList.add(BUFFER_WAIT_START); + eventsList.add(CALL); + eventsList.add(CLOSE); + eventsList.add(CORE_MARKER_FORMAT); + eventsList.add(CORE_MARKER_ID); + eventsList.add(DEV_RECEIVE); + eventsList.add(DEV_XMIT); + eventsList.add(END_COMMIT); + eventsList.add(EXEC); + eventsList.add(FILE_DESCRIPTOR); + eventsList.add(GETRQ); + eventsList.add(GETRQ_BIO); + eventsList.add(IDT_TABLE); + eventsList.add(INTERRUPT); + eventsList.add(IOCTL); + eventsList.add(IRQ_ENTRY); + eventsList.add(IRQ_EXIT); + eventsList.add(LIST_MODULE); + eventsList.add(LLSEEK); + eventsList.add(LSEEK); + eventsList.add(NAPI_COMPLETE); + eventsList.add(NAPI_POLL); + eventsList.add(NAPI_SCHEDULE); + eventsList.add(NETWORK_IPV4_INTERFACE); + eventsList.add(NETWORK_IP_INTERFACE); + eventsList.add(OPEN); + eventsList.add(PAGE_FAULT_ENTRY); + eventsList.add(PAGE_FAULT_EXIT); + eventsList.add(PAGE_FAULT_GET_USER_ENTRY); + eventsList.add(PAGE_FAULT_GET_USER_EXIT); + eventsList.add(PAGE_FREE); + eventsList.add(PLUG); + eventsList.add(POLLFD); + eventsList.add(PREAD64); + eventsList.add(PRINTF); + eventsList.add(PRINTK); + eventsList.add(PROCESS_EXIT); + eventsList.add(PROCESS_FORK); + eventsList.add(PROCESS_FREE); + eventsList.add(PROCESS_STATE); + eventsList.add(PROCESS_WAIT); + eventsList.add(READ); + eventsList.add(REMAP); + eventsList.add(REMOVE_FROM_PAGE_CACHE); + eventsList.add(RQ_COMPLETE_FS); + eventsList.add(RQ_COMPLETE_PC); + eventsList.add(RQ_INSERT_FS); + eventsList.add(RQ_INSERT_PC); + eventsList.add(RQ_ISSUE_FS); + eventsList.add(RQ_ISSUE_PC); + eventsList.add(RQ_REQUEUE_PC); + eventsList.add(SCHED_MIGRATE_TASK); + eventsList.add(SCHED_SCHEDULE); + eventsList.add(SCHED_TRY_WAKEUP); + eventsList.add(SCHED_WAKEUP_NEW_TASK); + eventsList.add(SELECT); + eventsList.add(SEM_CREATE); + eventsList.add(SEND_SIGNAL); + eventsList.add(SHM_CREATE); + eventsList.add(SLEEPRQ_BIO); + eventsList.add(SOCKET_ACCEPT); + eventsList.add(SOCKET_BIND); + eventsList.add(SOCKET_CALL); + eventsList.add(SOCKET_CONNECT); + eventsList.add(SOCKET_CREATE); + eventsList.add(SOCKET_GETPEERNAME); + eventsList.add(SOCKET_GETSOCKNAME); + eventsList.add(SOCKET_GETSOCKOPT); + eventsList.add(SOCKET_LISTEN); + eventsList.add(SOCKET_SETSOCKOPT); + eventsList.add(SOCKET_SHUTDOWN); + eventsList.add(SOCKET_SOCKETPAIR); + eventsList.add(SOFTIRQ_ENTRY); + eventsList.add(SOFTIRQ_EXIT); + eventsList.add(SOFTIRQ_RAISE); + eventsList.add(SOFTIRQ_VEC); + eventsList.add(START_COMMIT); + eventsList.add(STATEDUMP_END); + eventsList.add(SYS_CALL_TABLE); + eventsList.add(SYSCALL_ENTRY); + eventsList.add(SYSCALL_EXIT); + eventsList.add(TASKLET_LOW_ENTRY); + eventsList.add(TASKLET_LOW_EXIT); + eventsList.add(TCPV4_RCV); + eventsList.add(TIMER_ITIMER_EXPIRED); + eventsList.add(TIMER_ITIMER_SET); + eventsList.add(TIMER_SET); + eventsList.add(TIMER_TIMEOUT); + eventsList.add(TIMER_UPDATE_TIME); + eventsList.add(UDPV4_RCV); + eventsList.add(UNPLUG_IO); + eventsList.add(UNPLUG_TIMER); + eventsList.add(VM_MAP); + eventsList.add(VPRINTK); + eventsList.add(WAIT_ON_PAGE_END); + eventsList.add(WAIT_ON_PAGE_START); + eventsList.add(WRITE); + eventsList.add(WRITEV); + + return eventsList; + } + + /** + * Prints the stack content to the console. + */ + public void print() { + fStack.printContent(); + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/latency/analyzer/StackWrapper.java b/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/latency/analyzer/StackWrapper.java new file mode 100644 index 0000000000..e64ccb2c04 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/latency/analyzer/StackWrapper.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.core.latency.analyzer; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; +import java.util.Stack; + +import org.eclipse.linuxtools.lttng.core.event.LttngEvent; + +/** + * StackWrapper + *

+ * Stack pile. + * + * TODO Change the types of the HashMaps from to , in order to take advantage of the + * compilation-time String.hashCode() speedup over execution-time String hash computation. + * + * @author Philippe Sawicki + */ +public class StackWrapper { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * Hash map of event stacks. + */ + private HashMap> fStacks = null; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. + */ + public StackWrapper() { + fStacks = new HashMap>(); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /** + * Adds an event to the list of events of the same type. + * @param event + * The event to add to the list. + */ + public void put(LttngEvent event) { + String key = event.getMarkerName(); + + if (fStacks.containsKey(key)) { + fStacks.get(key).add(event); + } else { + Stack newStack = new Stack(); + newStack.add(event); + fStacks.put(key, newStack); + } + } + + /** + * Checks if the stack contains a list of events of the given type. + * @param key + * The type of events to check for. + * @return "true" if the stack contains events of the given type, "false" otherwise. + */ + public boolean containsKey(String key) { + return fStacks.containsKey(key); + } + + /** + * Returns the list of events of the given type. + * @param key + * The type of events to return. + * @return The list of events of the given type, or null. + */ + public Stack getStackOf(String key) { + return fStacks.get(key); + } + + /** + * Removes the given event from the given stack list. + * @param key + * The given stack type. + * @param event + * The event to remove from the given stack type. + * @return "true" if the event was removed, "false" otherwise. + */ + public boolean removeEvent(String key, LttngEvent event) { + Stack stack = fStacks.get(key); + + boolean removed = false; + + try { + /** + * TODO Correct this... Here, no matter what CPU or other content field, we always remove the last event + * added to the stack. Should be something like : return stack.remove(event); + */ + stack.pop(); + removed = true; + } catch (Exception e) { + e.printStackTrace(); + } + + // Remove the stack from the stack list if it is empty + if (stack.isEmpty()) { + fStacks.remove(key); + } + + return removed; + } + + /** + * Clears the stack content. + */ + public void clear() { + fStacks.clear(); + } + + /** + * Prints the content of the stack to the console. + */ + @SuppressWarnings("nls") + public void printContent() { + Collection> values = fStacks.values(); + Iterator> valueIt = values.iterator(); + + Set keys = fStacks.keySet(); + Iterator keyIt = keys.iterator(); + + while (valueIt.hasNext() && keyIt.hasNext()) { + Stack stack = valueIt.next(); + + System.out.println(" " + keyIt.next() + " [" + stack.size() + "] : " + stack); + } + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/util/EventsPair.java b/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/util/EventsPair.java new file mode 100644 index 0000000000..3a13edd3b4 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/util/EventsPair.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse + * Public License v1.0 which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Mathieu Denis (mathieu.denis55@gmail.com) - Initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.core.util; + +import java.util.Vector; + + +/** + * Contains two lists of events name. The first list contains the events identified as starting request and the second list + * contains the events identified as ending request + */ +public class EventsPair extends Pair, Vector> { + + public EventsPair() { + super(); + } + + public EventsPair(Vector startingEvents, Vector endingEvents) { + super(startingEvents, endingEvents); + } +} diff --git a/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/util/Pair.java b/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/util/Pair.java new file mode 100644 index 0000000000..cebcf03da6 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/util/Pair.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.core.util; + +/** + * Pair utility class, encapsulates a pair of objects. + * + * @author Philippe Sawicki + * + * @param + * The type of the first object. + * @param + * The type of the second object. + */ +public abstract class Pair { + + /** + * A reference to the first object. + */ + protected A fFirst; + /** + * A reference to the second object. + */ + protected B fSecond; + + /** + * Constructor. + * @param first + * The pair's first object. + * @param second + * The pair's second object. + */ + public Pair(A first, B second) { + fFirst = first; + fSecond = second; + } + + /** + * Constructor. + */ + public Pair() { + this(null, null); + } + + /** + * Pair hash code. + */ + @Override + public int hashCode() { + int hashFirst = fFirst != null ? fFirst.hashCode() : 0; + int hashSecond = fSecond != null ? fSecond.hashCode() : 0; + + return (hashFirst + hashSecond) * hashSecond + hashFirst; + } + + /** + * Object comparison. + */ + @Override + @SuppressWarnings("unchecked") + public boolean equals(Object other) { + if (other instanceof Pair) { + Pair otherPair = (Pair) other; + return ((fFirst == otherPair.fFirst || (fFirst != null && otherPair.fFirst != null && fFirst.equals(otherPair.fFirst))) && (fSecond == otherPair.fSecond || (fSecond != null + && otherPair.fSecond != null && fSecond.equals(otherPair.fSecond)))); + } + return false; + } + + /** + * Object to string. + */ + @Override + public String toString() { + return "(" + fFirst + ", " + fSecond + ")"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + } + + /** + * Returns a reference to the pair's first object. + * @return A reference to the pair's first object. + */ + public A getFirst() { + return fFirst; + } + + /** + * Sets the pair's first object. + * @param first + * The pair's first object. + */ + public void setFirst(A first) { + fFirst = first; + } + + /** + * Returns a reference to the pair's second object. + * @return A reference to the pair's second object. + */ + public B getSecond() { + return fSecond; + } + + /** + * Sets the pair's second object. + * @param second + * The pair's second object. + */ + public void setSecond(B second) { + fSecond = second; + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/AllLTTngUITests.java b/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/AllLTTngUITests.java index dcc3c10f25..ab6fe78934 100644 --- a/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/AllLTTngUITests.java +++ b/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/AllLTTngUITests.java @@ -7,6 +7,7 @@ public class AllLTTngUITests { public static Test suite() { TestSuite suite = new TestSuite(AllLTTngUITests.class.getName()); //$JUnit-BEGIN$ + suite.addTest(org.eclipse.linuxtools.lttng.ui.tests.distribution.AllTests.suite()); suite.addTest(org.eclipse.linuxtools.lttng.ui.tests.histogram.AllTests.suite()); //$JUnit-END$ return suite; diff --git a/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/distribution/AllTests.java b/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/distribution/AllTests.java new file mode 100644 index 0000000000..b44a4debe7 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/distribution/AllTests.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.tests.distribution; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AllTests { + + public static Test suite() { + + TestSuite suite = new TestSuite(AllTests.class.getName()); + //$JUnit-BEGIN$ + suite.addTestSuite(LatencyGraphModelTest.class); + //$JUnit-END$ + return suite; + } +} diff --git a/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/distribution/LatencyGraphModelTest.java b/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/distribution/LatencyGraphModelTest.java new file mode 100644 index 0000000000..36c382d76b --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/distribution/LatencyGraphModelTest.java @@ -0,0 +1,582 @@ +package org.eclipse.linuxtools.lttng.ui.tests.distribution; + +import junit.framework.TestCase; + +import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.GraphScaledData; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyGraphModel; + +@SuppressWarnings("nls") +public class LatencyGraphModelTest extends TestCase { + + // ------------------------------------------------------------------------ + // Test data + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // Housekeeping + // ------------------------------------------------------------------------ + + @Override + public void setUp() throws Exception { + } + + @Override + public void tearDown() throws Exception { + } + + // ------------------------------------------------------------------------ + // Tests + // ------------------------------------------------------------------------ + + public void testLatencyGraphModel() { + LatencyGraphModel model = new LatencyGraphModel(); + assertEquals("nbBuckets", Config.DEFAULT_NUMBER_OF_BUCKETS, model.getNbBuckets()); + assertEquals("currentTime", Config.INVALID_EVENT_TIME, model.getCurrentEventTime()); + } + + public void testLatencyGraphModelInt() { + LatencyGraphModel model = new LatencyGraphModel(100); + assertEquals("nbBuckets", 100, model.getNbBuckets()); + assertEquals("currentTime", Config.INVALID_EVENT_TIME, model.getCurrentEventTime()); + } + + + public void testGraphModelListener() { + final int nbBuckets = 2000; + final int nbEvents = 10 * nbBuckets + 256; + final int[] count = new int[2]; + count [0] = 0; + count [1] = 0; + + // Test add listener and call of listener + IGraphModelListener listener = new IGraphModelListener() { + + @Override + public void graphModelUpdated() { + count[0]++; + + } + + @Override + public void currentEventUpdated(long currentEventTime) { + count[1]++; + } + }; + + // Test that the listener interface is called every 10000 events. + LatencyGraphModel model = new LatencyGraphModel(nbBuckets); + model.addGraphModelListener(listener); + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i+1, i, i); + } + + assertEquals("listener", 2, count[0]); + + // Test that the listener interface is called when complete is called. + model.complete(); + assertEquals("listener", 3, count[0]); + + // Test that clear triggers call of listener interface + model.clear(); + assertEquals("listener", 4, count[0]); + + // Test that clear triggers call of listener interface + model.setCurrentEventNotifyListeners(100); + assertEquals("listener", 1, count[1]); + + // Test remove listener + count[0] = 0; + count[1] = 0; + model.removeGraphModelListener(listener); + + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i, i, i); + } + model.complete(); + assertEquals("listener", 0, count[1]); + + // Test that clear triggers call of listener interface + model.setCurrentEventNotifyListeners(100); + assertEquals("listener", 0, count[1]); + } + + public void testConstructor() { + final int nbBuckets = 2000; + + LatencyGraphModel model = new LatencyGraphModel(nbBuckets); + GraphScaledData scaledData = model.scaleTo(100, 100, 1); + + // Verify model parameters + assertEquals("Horizontal bucket duration", 1, model.getHorBucketDuration()); + assertEquals("Vertical bucket duration", 1, model.getVerBucketDuration()); + + assertEquals("Horizontal first bucket time", 0, model.getHorFirstBucketTime()); + assertEquals("Vertical first bucket time", 0, model.getVerFirstBucketTime()); + + assertEquals("Horizontal last bucket ", 0, model.getHorLastBucket()); + assertEquals("Vertical last bucket ", 0, model.getVerLastBucket()); + + assertEquals("Horizontal first time", 0, model.getHorFirstEventTime()); + assertEquals("Vertical first time", 0, model.getVerFirstEventTime()); + + assertEquals("Horizontal last time", 0, model.getHorLastEventTime()); + assertEquals("Vertical last time", 0, model.getVerLastEventTime()); + + assertEquals("Horizontal time limit", 2000, model.getHorTimeLimit()); + assertEquals("Vertical time limit", 2000, model.getVerTimeLimit()); + + // Verify scaled data parameters + scaledData = model.scaleTo(101, 100, 1); + + assertEquals("barWidth", 1, scaledData.getBarWidth()); + assertEquals("height", 100, scaledData.getHeight()); + assertEquals("width", 101, scaledData.getWidth()); + + assertEquals(Config.INVALID_EVENT_TIME, scaledData.getCurrentEventTime()); + + assertEquals("Horizontal bucket duration", 1, scaledData.getHorBucketDuration()); + assertEquals("Vertical bucket duration", 1, scaledData.getVerBucketDuration()); + + assertEquals("Horizontal bucket end time", 1, scaledData.getHorBucketEndTime(0)); + assertEquals("Vertical bucket end time", 1, scaledData.getVerBucketEndTime(0)); + + assertEquals("Horizontal bucket start time", 0, scaledData.getHorBucketStartTime(0)); + assertEquals("Vertical bucket start time", 0, scaledData.getVerBucketStartTime(0)); + + assertEquals("Horizontal first time", 0, scaledData.getHorFirstEventTime()); + assertEquals("Vertical first time", 0, scaledData.getVerFirstEventTime()); + + assertEquals("Horizontal first bucket time", 0, scaledData.getHorFirstBucketTime()); + assertEquals("Vertical first bucket time", 0, scaledData.getVerFirstBucketTime()); + + assertEquals("Horizontal last bucket time", 0, scaledData.getHorLastBucketTime()); + assertEquals("Vertical last bucket time", 0, scaledData.getVerLastBucketTime()); + + assertEquals("Horizontal number of buckets", 101, scaledData.getHorNbBuckets()); + assertEquals("Vertical nubmer of buckets", 100, scaledData.getVerNbBuckets()); + + assertEquals("Horizontal getIndex", 100, scaledData.getHorBucketIndex(100)); + assertEquals("Vertical getIndex", 124, scaledData.getVerBucketIndex(124)); + + assertEquals("Horizontal last bucket", 0, scaledData.getHorLastBucket()); + assertEquals("Vertical last bucket", 0, scaledData.getVerLastBucket()); + + assertEquals("Horizontal last event time", 0, scaledData.getHorLastEventTime()); + assertEquals("Vertical last event time", 0, scaledData.getVerLastEventTime()); + } + + public void testClear() { + final int nbBuckets = 2000; + final int nbEvents = 10 * nbBuckets + 256; + + LatencyGraphModel model = new LatencyGraphModel(nbBuckets); + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i+1, i, i); + } + // make sure that we actually counted something. + GraphScaledData scaledData = model.scaleTo(100, 100, 1); + + assertTrue(scaledData.getHorLastBucket() > 0); + + model.clear(); + + // Verify model parameters + assertEquals("Horizontal bucket duration", 1, model.getHorBucketDuration()); + assertEquals("Vertical bucket duration", 1, model.getVerBucketDuration()); + + assertEquals("Horizontal first bucket time", 0, model.getHorFirstBucketTime()); + assertEquals("Vertical first bucket time", 0, model.getVerFirstBucketTime()); + + assertEquals("Horizontal last bucket ", 0, model.getHorLastBucket()); + assertEquals("Vertical last bucket ", 0, model.getVerLastBucket()); + + assertEquals("Horizontal first time", 0, model.getHorFirstEventTime()); + assertEquals("Vertical first time", 0, model.getVerFirstEventTime()); + + assertEquals("Horizontal last time", 0, model.getHorLastEventTime()); + assertEquals("Vertical last time", 0, model.getVerLastEventTime()); + + assertEquals("Horizontal time limit", 2000, model.getHorTimeLimit()); + assertEquals("Vertical time limit", 2000, model.getVerTimeLimit()); + + // Verify scaled data parameters + scaledData = model.scaleTo(101, 100, 1); + + assertEquals("barWidth", 1, scaledData.getBarWidth()); + assertEquals("height", 100, scaledData.getHeight()); + assertEquals("width", 101, scaledData.getWidth()); + + assertEquals(Config.INVALID_EVENT_TIME, scaledData.getCurrentEventTime()); + + assertEquals("Horizontal bucket duration", 1, scaledData.getHorBucketDuration()); + assertEquals("Vertical bucket duration", 1, scaledData.getVerBucketDuration()); + + assertEquals("Horizontal bucket end time", 1, scaledData.getHorBucketEndTime(0)); + assertEquals("Vertical bucket end time", 1, scaledData.getVerBucketEndTime(0)); + + assertEquals("Horizontal bucket start time", 0, scaledData.getHorBucketStartTime(0)); + assertEquals("Vertical bucket start time", 0, scaledData.getVerBucketStartTime(0)); + + assertEquals("Horizontal first time", 0, scaledData.getHorFirstEventTime()); + assertEquals("Vertical first time", 0, scaledData.getVerFirstEventTime()); + + assertEquals("Horizontal first bucket time", 0, scaledData.getHorFirstBucketTime()); + assertEquals("Vertical first bucket time", 0, scaledData.getVerFirstBucketTime()); + + assertEquals("Horizontal last bucket time", 0, scaledData.getHorLastBucketTime()); + assertEquals("Vertical last bucket time", 0, scaledData.getVerLastBucketTime()); + + assertEquals("Horizontal getIndex", 100, scaledData.getHorBucketIndex(100)); + assertEquals("Vertical getIndex", 124, scaledData.getVerBucketIndex(124)); + + assertEquals("Horizontal number of buckets", 101, scaledData.getHorNbBuckets()); + assertEquals("Vertical nubmer of buckets", 100, scaledData.getVerNbBuckets()); + + assertEquals("Horizontal last bucket", 0, scaledData.getHorLastBucket()); + assertEquals("Vertical last bucket", 0, scaledData.getVerLastBucket()); + + assertEquals("Horizontal last event time", 0, scaledData.getHorLastEventTime()); + assertEquals("Vertical last event time", 0, scaledData.getVerLastEventTime()); + } + + public void testCountEvent() { + final int nbBuckets = 2000; + final int nbEvents = 10 * nbBuckets + 256; + final long hOffset = 100; + final long vOffset = 55; + + LatencyGraphModel model = new LatencyGraphModel(nbBuckets); + + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i + 1, hOffset + i, vOffset + i); + } + + // Verify model parameters + assertEquals("Horizontal bucket duration", 16, model.getHorBucketDuration()); + assertEquals("Vertical bucket duration", 16, model.getVerBucketDuration()); + + assertEquals("Horizontal first bucket time", hOffset, model.getHorFirstBucketTime()); + assertEquals("Vertical first bucket time", vOffset, model.getVerFirstBucketTime()); + + assertEquals("Horizontal last bucket ", (nbEvents - 1)/16, model.getHorLastBucket()); + assertEquals("Vertical last bucket ", (nbEvents - 1)/16, model.getVerLastBucket()); + + assertEquals("Horizontal first time", hOffset, model.getHorFirstEventTime()); + assertEquals("Vertical first time", vOffset, model.getVerFirstEventTime()); + + assertEquals("Horizontal last time", nbEvents + hOffset - 1, model.getHorLastEventTime()); + assertEquals("Vertical last time", nbEvents + vOffset - 1, model.getVerLastEventTime()); + + assertEquals("Horizontal time limit", 16 * nbBuckets + hOffset, model.getHorTimeLimit()); + assertEquals("Vertical time limit", 16 * nbBuckets + vOffset, model.getVerTimeLimit()); + + // Verify scaled data parameters + GraphScaledData scaledData = model.scaleTo(50, 100, 1); + + assertEquals("barWidth", 1, scaledData.getBarWidth()); + assertEquals("height", 100, scaledData.getHeight()); + assertEquals("width", 50, scaledData.getWidth()); + + assertEquals(Config.INVALID_EVENT_TIME, scaledData.getCurrentEventTime()); + + // nbBars = width / barWidth + // bucketsPerBar = lastBucket/nbBars + 1 + // scaled bucket duration = bucketsPerBar * model.bucketDuration + // for nbBuckets=2000 and nbEvents=20256 (means 20256 ns + offset) -> model.bucketDuration = 16 + assertEquals("Horizontal bucket duration", 416, scaledData.getHorBucketDuration()); + assertEquals("Vertical bucket duration", 208, scaledData.getVerBucketDuration()); + + // startTime + scaledData.bucketDuration + assertEquals("Horizontal bucket end time", hOffset + 416, scaledData.getHorBucketEndTime(0)); + assertEquals("Vertical bucket end time", 55 + 208, scaledData.getVerBucketEndTime(0)); + + assertEquals("Horizontal bucket start time", 100, scaledData.getHorBucketStartTime(0)); + assertEquals("Vertical bucket start time", 55, scaledData.getVerBucketStartTime(0)); + + assertEquals("Horizontal first time", 100, scaledData.getHorFirstEventTime()); + assertEquals("Vertical first time", 55, scaledData.getVerFirstEventTime()); + + assertEquals("Horizontal first bucket time", hOffset, scaledData.getHorFirstBucketTime()); + assertEquals("Vertical first bucket time", 55, scaledData.getVerFirstBucketTime()); + + assertEquals("Horizontal last bucket time", hOffset + 48 * 416, scaledData.getHorLastBucketTime()); + assertEquals("Vertical last bucket time", vOffset + 97 * 208, scaledData.getVerLastBucketTime()); + + assertEquals("Horizontal getIndex", 47, scaledData.getHorBucketIndex(20000)); + assertEquals("Vertical getIndex", 47, scaledData.getVerBucketIndex(10000)); + + // nb Buckets = nbBars + assertEquals("Horizontal number of buckets", 50, scaledData.getHorNbBuckets()); + assertEquals("Vertical nubmer of buckets", 100, scaledData.getVerNbBuckets()); + + assertEquals("Horizontal last bucket", 48, scaledData.getHorLastBucket()); + assertEquals("Vertical last bucket", 97, scaledData.getVerLastBucket()); + + // start time of last bucket + assertEquals("Horizontal last event time", hOffset + nbEvents - 1, scaledData.getHorLastEventTime()); + assertEquals("Vertical last event time", vOffset + nbEvents - 1 , scaledData.getVerLastEventTime()); + } + + public void testCountEvent2() { + + final int nbBuckets = 2000; + final int nbEvents = 10 * nbBuckets + 256; + final long offset = 100; + final int height = 100; + final int width = 100; + final int barWidth = 1; + + int[][] expectedResults = new int[width/barWidth][height/barWidth]; + + int total = 0; + + // Horizontally and vertically the same data is used + + // for nbBuckets=2000 and nbEvents=20256 (means 20256 ns + offset) -> model.bucketDuration = 16 + // nbBars = width / barWidth = 100 + // bucketsPerBar = lastBucket/nbBars + 1 = 13 + // scaled bucket duration = bucketsPerBar * model.bucketDuration = 13 * 16 + boolean isFinished = false; + for (int i = 0; i < width/barWidth; i++) { + if (isFinished) { + break; + } + for (int j = 0; j < height/barWidth; j++) { + if (i == j) { + int value = 13 * 16; + if (total + value > nbEvents) { + expectedResults[i][j] = nbEvents - total; + isFinished = true; + break; + } + else { + expectedResults[i][j] = value; + total += value; + } + } + } + } + + LatencyGraphModel model = new LatencyGraphModel(nbBuckets); + + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i+1, offset + i, offset + i); + } + + GraphScaledData scaledData = model.scaleTo(height, width, barWidth); + + for (int i = 0; i < scaledData.getHorLastBucket(); i++) { + for (int j = 0; j < scaledData.getVerLastBucket(); j++) { + assertEquals(expectedResults[i][j], scaledData.getEventCount(i, j)); + } + } + } + + public void testCountEvent3() { + // Test with barWidth > 1 + final int nbBuckets = 2000; + final int nbEvents = 10 * nbBuckets + 256; + final long offset = 100; + final int height = 100; + final int width = 100; + final int barWidth = 4; + + int[][] expectedResults = new int[width/barWidth][height/barWidth]; + + int total = 0; + + // Horizontally and vertically the same data is used + + // for nbBuckets=2000 and nbEvents=20256 (means 20256 ns + offset) -> model.bucketDuration = 16 + // nbBars = width / barWidth = 25 + // bucketsPerBar = lastBucket/nbBars + 1 = 51 + // scaled bucket duration = bucketsPerBar * model.bucketDuration = 51 * 16 + boolean isFinished = false; + for (int i = 0; i < width/barWidth; i++) { + if (isFinished) { + break; + } + for (int j = 0; j < height/barWidth; j++) { + if (i == j) { + int value = 51 * 16; + if (total + value > nbEvents) { + expectedResults[i][j] = nbEvents - total; + isFinished = true; + break; + } + else { + expectedResults[i][j] = value; + total += value; + } + } + } + } + + LatencyGraphModel model = new LatencyGraphModel(nbBuckets); + + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i+1, offset + i, offset + i); + } + + GraphScaledData scaledData = model.scaleTo(height, width, barWidth); + + for (int i = 0; i < scaledData.getHorLastBucket(); i++) { + for (int j = 0; j < scaledData.getVerLastBucket(); j++) { + assertEquals(expectedResults[i][j], scaledData.getEventCount(i, j)); + } + } + } + + public void testCountEventReverse1() { + // Depending on the number of buckets and events the start buckets can be different + // between forward and reserve times. However, the content is correct. + final int nbBuckets = 100; + final int nbEvents = 256; + final long hOffset = 100; + final long vOffset = 55; + final int height = 100; + final int width = 50; + final int barWidth = 1; + + LatencyGraphModel model = new LatencyGraphModel(nbBuckets); + + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i + 1, hOffset + i, vOffset + i); + } + + GraphScaledData scaledData = model.scaleTo(width, height, barWidth); + + model.clear(); + + for (int i = nbEvents - 1; i >= 0; i--) { + model.countEvent(nbEvents - i, hOffset + i, vOffset + i); + } + + GraphScaledData scaledDataReverse = model.scaleTo(50, 100, 1); + + long count = 0; + for (int i = 0; i <= scaledData.getHorLastBucket(); i++) { + for (int j = 0; j <= scaledData.getVerLastBucket(); j++) { + count += scaledData.getEventCount(i, j); + } + } + + long revCount = 0; + for (int i = 0; i <= scaledDataReverse.getHorLastBucket(); i++) { + for (int j = 0; j <= scaledDataReverse.getVerLastBucket(); j++) { + revCount += scaledDataReverse.getEventCount(i, j); + } + } + + assertEquals(count, revCount); + + // Make sure that both scaledData have the same content + assertTrue("barWidth", scaledData.getBarWidth() == scaledDataReverse.getBarWidth()); + assertTrue("height", scaledData.getHeight() == scaledDataReverse.getHeight()); + assertTrue("width", scaledData.getWidth() == scaledDataReverse.getWidth()); + + assertTrue(scaledData.getCurrentEventTime() == scaledDataReverse.getCurrentEventTime()); + + assertTrue("Horizontal bucket duration", scaledData.getHorBucketDuration() == scaledDataReverse.getHorBucketDuration()); + assertTrue("Vertical bucket duration", scaledData.getVerBucketDuration() == scaledDataReverse.getVerBucketDuration()); + + // startTime + scaledData.bucketDuration + assertTrue("Horizontal bucket end time", scaledData.getHorBucketEndTime(0) == scaledDataReverse.getHorBucketEndTime(0)); + assertTrue("Vertical bucket end time", scaledData.getVerBucketEndTime(0) == scaledDataReverse.getVerBucketEndTime(0)); + + assertTrue("Horizontal bucket start time", scaledData.getHorBucketStartTime(0) == scaledDataReverse.getHorBucketStartTime(0)); + assertTrue("Vertical bucket start time", scaledData.getVerBucketStartTime(0) == scaledDataReverse.getVerBucketStartTime(0)); + + assertTrue("Horizontal first time", scaledData.getHorFirstEventTime() == scaledDataReverse.getHorFirstEventTime()); + assertTrue("Vertical first time", scaledData.getVerFirstEventTime() == scaledDataReverse.getVerFirstEventTime()); + + assertTrue("Horizontal getIndex", scaledData.getHorBucketIndex(200) == scaledDataReverse.getHorBucketIndex(200)); + assertTrue("Vertical getIndex", scaledData.getVerBucketIndex(100) == scaledDataReverse.getVerBucketIndex(100)); + + assertTrue("Horizontal last bucket", scaledData.getHorNbBuckets() == scaledDataReverse.getHorNbBuckets()); + assertTrue("Vertical last bucket", scaledData.getVerNbBuckets() == scaledDataReverse.getVerNbBuckets()); + + assertTrue("Horizontal nubmer of buckets", scaledData.getHorLastBucket() == scaledDataReverse.getHorLastBucket()); + assertTrue("Vertical nubmer of buckets", scaledData.getVerLastBucket() == scaledDataReverse.getVerLastBucket()); + + // start time of last bucket + assertTrue("Horizontal last event time", scaledData.getHorLastEventTime() == scaledDataReverse.getHorLastEventTime()); + assertTrue("Vertical last event time", scaledData.getVerLastEventTime() == scaledDataReverse.getVerLastEventTime()); + } + + public void testCountEventReverse2() { + // Depending on the number of buckets and events the start buckets can be different + // between forward and reserve times. However, the content is correct. + final int nbBuckets = 100; + final int nbEvents = 256; + final long hOffset = 100; + final long vOffset = 55; + final int height = 100; + final int width = 50; + final int barWidth = 1; + + LatencyGraphModel model = new LatencyGraphModel(nbBuckets); + + for (int i = nbEvents - 1; i >= 0; i--) { + model.countEvent(nbEvents - i, hOffset + i, vOffset + i); + } + + // Verify model parameters + int expectedBucketDuration = 4; + assertEquals("Horizontal bucket duration", expectedBucketDuration, model.getHorBucketDuration()); + assertEquals("Vertical bucket duration", expectedBucketDuration, model.getVerBucketDuration()); + + assertEquals("Horizontal first bucket time", hOffset, model.getHorFirstBucketTime()); + assertEquals("Vertical first bucket time", vOffset, model.getVerFirstBucketTime()); + + assertEquals("Horizontal last bucket", (nbEvents -1)/expectedBucketDuration, model.getHorLastBucket()); + assertEquals("Vertical last bucket", (nbEvents -1)/expectedBucketDuration, model.getVerLastBucket()); + + assertEquals("Horizontal first time", hOffset, model.getHorFirstEventTime()); + assertEquals("Vertical first time", vOffset, model.getVerFirstEventTime()); + + assertEquals("Horizontal last time", nbEvents + hOffset - 1, model.getHorLastEventTime()); + assertEquals("Vertical last time", nbEvents + vOffset - 1, model.getVerLastEventTime()); + + assertEquals("Horizontal time limit", expectedBucketDuration * nbBuckets + hOffset, model.getHorTimeLimit()); + assertEquals("Vertical time limit", expectedBucketDuration * nbBuckets + vOffset, model.getVerTimeLimit()); + + GraphScaledData scaledData = model.scaleTo(50, 100, 1); + + // Make sure that both scaledData have the same content + assertEquals("barWidth", barWidth, scaledData.getBarWidth()); + assertEquals("height", height, scaledData.getHeight()); + assertEquals("width", width, scaledData.getWidth()); + + assertEquals(-1, scaledData.getCurrentEventTime()); + + assertEquals("Horizontal bucket duration", 8, scaledData.getHorBucketDuration()); + assertEquals("Vertical bucket duration", 4, scaledData.getVerBucketDuration()); + + // startTime + scaledData.bucketDuration + assertEquals("Horizontal bucket end time", hOffset + 8, scaledData.getHorBucketEndTime(0)); + assertEquals("Vertical bucket end time", vOffset + 4, scaledData.getVerBucketEndTime(0)); + + assertEquals("Horizontal bucket start time", hOffset, scaledData.getHorBucketStartTime(0)); + assertEquals("Vertical bucket start time", vOffset, scaledData.getVerBucketStartTime(0)); + + assertEquals("Horizontal first time", hOffset, scaledData.getHorFirstEventTime()); + assertEquals("Vertical first time", vOffset, scaledData.getVerFirstEventTime()); + + assertEquals("Horizontal getIndex", 12, scaledData.getHorBucketIndex(200)); + assertEquals("Vertical getIndex", 11, scaledData.getVerBucketIndex(100)); + + // nb Buckets = nbBars + assertEquals("Horizontal number of buckets", 50, scaledData.getHorNbBuckets()); + assertEquals("Vertical number of buckets", 100, scaledData.getVerNbBuckets()); + + assertEquals("Horizontal last bucket", 31, scaledData.getHorLastBucket()); + assertEquals("Vertical last bucket", 63, scaledData.getVerLastBucket()); + + // start time of last bucket + assertEquals("Horizontal last event time", 355, scaledData.getHorLastEventTime()); + assertEquals("Vertical last event time", 310, scaledData.getVerLastEventTime()); + } +} diff --git a/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/histogram/HistogramDataModelTest.java b/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/histogram/HistogramDataModelTest.java index e0e0f3f9bd..249d34d2ef 100644 --- a/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/histogram/HistogramDataModelTest.java +++ b/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/histogram/HistogramDataModelTest.java @@ -17,6 +17,7 @@ import junit.framework.TestCase; import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramDataModel; import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramScaledData; +import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramModelListener; /** * HistogramDataModelTest @@ -55,6 +56,7 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbBuckets() == HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS); assertTrue(model.getNbEvents() == 0); assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getStartTime() == 0); assertTrue(model.getEndTime() == 0); assertTrue(model.getTimeLimit() == HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS); @@ -71,6 +73,7 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbEvents() == 0); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getStartTime() == 0); assertTrue(model.getEndTime() == 0); assertTrue(model.getTimeLimit() == nbBuckets); @@ -84,11 +87,12 @@ public class HistogramDataModelTest extends TestCase { public void testClear() { final int nbBuckets = 100; HistogramDataModel model = new HistogramDataModel(nbBuckets); - model.countEvent(-1); + model.countEvent(0, -1); assertTrue(model.getNbEvents() == 0); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getStartTime() == 0); assertTrue(model.getEndTime() == 0); assertTrue(model.getTimeLimit() == nbBuckets); @@ -102,11 +106,12 @@ public class HistogramDataModelTest extends TestCase { public void testCountEvent_0() { final int nbBuckets = 100; HistogramDataModel model = new HistogramDataModel(nbBuckets); - model.countEvent(-1); + model.countEvent(0, -1); assertTrue(model.getNbEvents() == 0); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getStartTime() == 0); assertTrue(model.getEndTime() == 0); assertTrue(model.getTimeLimit() == nbBuckets); @@ -118,7 +123,7 @@ public class HistogramDataModelTest extends TestCase { HistogramDataModel model = new HistogramDataModel(nbBuckets); - HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1); for (int i = 0; i < result.fData.length; i++) { assertTrue(result.fData[i] == 0); } @@ -126,6 +131,7 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbEvents() == 0); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getStartTime() == 0); assertTrue(model.getEndTime() == 0); assertTrue(model.getTimeLimit() == nbBuckets); @@ -136,9 +142,9 @@ public class HistogramDataModelTest extends TestCase { final int maxHeight = 10; HistogramDataModel model = new HistogramDataModel(nbBuckets); - model.countEvent(1); + model.countEvent(0, 1); - HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1); assertTrue(result.fData[0] == 1); for (int i = 1; i < result.fData.length; i++) { assertTrue(result.fData[i] == 0); @@ -147,6 +153,7 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbEvents() == 1); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getFirstBucketTime() == 1); assertTrue(model.getStartTime() == 1); assertTrue(model.getEndTime() == 1); assertTrue(model.getTimeLimit() == nbBuckets + 1); @@ -158,10 +165,10 @@ public class HistogramDataModelTest extends TestCase { HistogramDataModel model = new HistogramDataModel(nbBuckets); for (int i = 0; i < nbBuckets; i++) { - model.countEvent(i); + model.countEvent(i, i); } - HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1); for (int i = 0; i < result.fData.length; i++) { assertTrue(result.fData[i] == 1); } @@ -169,6 +176,7 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbEvents() == nbBuckets); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getStartTime() == 0); assertTrue(model.getEndTime() == nbBuckets - 1); assertTrue(model.getTimeLimit() == nbBuckets); @@ -180,11 +188,11 @@ public class HistogramDataModelTest extends TestCase { HistogramDataModel model = new HistogramDataModel(nbBuckets); for (int i = 0; i < nbBuckets; i++) { - model.countEvent(i); - model.countEvent(i); + model.countEvent(i, i); + model.countEvent(i+1, i); } - HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1); for (int i = 0; i < result.fData.length; i++) { assertTrue(result.fData[i] == 2); } @@ -192,6 +200,7 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbEvents() == 2 * nbBuckets); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getStartTime() == 0); assertTrue(model.getEndTime() == nbBuckets - 1); assertTrue(model.getTimeLimit() == nbBuckets); @@ -204,10 +213,10 @@ public class HistogramDataModelTest extends TestCase { HistogramDataModel model = new HistogramDataModel(nbBuckets); for (int i = startTime; i < startTime + nbBuckets; i++) { - model.countEvent(i); + model.countEvent(i, i); } - HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1); for (int i = 0; i < result.fData.length; i++) { assertTrue(result.fData[i] == 1); } @@ -215,6 +224,7 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbEvents() == nbBuckets); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getFirstBucketTime() == startTime); assertTrue(model.getStartTime() == startTime); assertTrue(model.getEndTime() == startTime + nbBuckets - 1); assertTrue(model.getTimeLimit() == startTime + nbBuckets); @@ -228,15 +238,15 @@ public class HistogramDataModelTest extends TestCase { public void testScaleTo_0() { HistogramDataModel model = new HistogramDataModel(10); try { - model.scaleTo(10, 0); + model.scaleTo(10, 0, 1); } catch (AssertionError e1) { try { - model.scaleTo(0, 10); + model.scaleTo(0, 10, 1); } catch (AssertionError e2) { try { - model.scaleTo(0, 0); + model.scaleTo(0, 0, 1); } catch (AssertionError e3) { return; @@ -255,10 +265,10 @@ public class HistogramDataModelTest extends TestCase { HistogramDataModel model = new HistogramDataModel(nbBuckets); for (int i = 0; i < nbEvents; i++) { - model.countEvent(i); + model.countEvent(i, i); } - HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1); for (int i = 0; i < result.fData.length; i++) { assertTrue(result.fData[i] == expectedResult[i]); } @@ -266,6 +276,7 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbEvents() == nbEvents); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getStartTime() == 0); assertTrue(model.getEndTime() == nbEvents - 1); assertTrue(model.getTimeLimit() == nbBuckets); @@ -279,10 +290,10 @@ public class HistogramDataModelTest extends TestCase { HistogramDataModel model = new HistogramDataModel(nbBuckets); for (int i = 0; i < nbEvents; i++) { - model.countEvent(i); + model.countEvent(i, i); } - HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1); for (int i = 0; i < result.fData.length; i++) { assertTrue(result.fData[i] == expectedResult[i]); } @@ -290,6 +301,7 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbEvents() == nbEvents); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getStartTime() == 0); assertTrue(model.getEndTime() == nbEvents - 1); assertTrue(model.getTimeLimit() == nbBuckets); @@ -303,10 +315,10 @@ public class HistogramDataModelTest extends TestCase { HistogramDataModel model = new HistogramDataModel(nbBuckets); for (int i = 0; i < nbEvents; i++) { - model.countEvent(i); + model.countEvent(i, i); } - HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1); for (int i = 0; i < result.fData.length; i++) { assertTrue(result.fData[i] == expectedResult[i]); } @@ -314,6 +326,7 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbEvents() == nbEvents); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 2); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getStartTime() == 0); assertTrue(model.getEndTime() == nbEvents - 1); assertTrue(model.getTimeLimit() == 2 * nbBuckets); @@ -327,10 +340,10 @@ public class HistogramDataModelTest extends TestCase { HistogramDataModel model = new HistogramDataModel(nbBuckets); for (int i = 0; i < nbEvents; i++) { - model.countEvent(i); + model.countEvent(i, i); } - HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1); for (int i = 0; i < result.fData.length; i++) { assertTrue(result.fData[i] == expectedResult[i]); } @@ -338,6 +351,7 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbEvents() == nbEvents); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 4); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getStartTime() == 0); assertTrue(model.getEndTime() == nbEvents - 1); assertTrue(model.getTimeLimit() == 4 * nbBuckets); @@ -351,10 +365,10 @@ public class HistogramDataModelTest extends TestCase { HistogramDataModel model = new HistogramDataModel(nbBuckets); for (int i = 0; i < nbEvents; i++) { - model.countEvent(i); + model.countEvent(i, i); } - HistogramScaledData result = model.scaleTo(10, maxHeight); + HistogramScaledData result = model.scaleTo(10, maxHeight, 1); for (int i = 0; i < result.fData.length; i++) { assertTrue(result.fData[i] == expectedResult[i]); } @@ -362,7 +376,7 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbEvents() == nbEvents); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 2); - assertTrue(model.getStartTime() == 0); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getEndTime() == nbEvents - 1); assertTrue(model.getTimeLimit() == 2 * nbBuckets); } @@ -375,10 +389,10 @@ public class HistogramDataModelTest extends TestCase { HistogramDataModel model = new HistogramDataModel(nbBuckets); for (int i = 0; i < nbEvents; i++) { - model.countEvent(i); + model.countEvent(i, i); } - HistogramScaledData result = model.scaleTo(10, maxHeight); + HistogramScaledData result = model.scaleTo(10, maxHeight, 1); for (int i = 0; i < result.fData.length; i++) { assertTrue(result.fData[i] == expectedResult[i]); } @@ -386,9 +400,195 @@ public class HistogramDataModelTest extends TestCase { assertTrue(model.getNbEvents() == nbEvents); assertTrue(model.getNbBuckets() == nbBuckets); assertTrue(model.getBucketDuration() == 4); + assertTrue(model.getFirstBucketTime() == 0); assertTrue(model.getStartTime() == 0); assertTrue(model.getEndTime() == nbEvents - 1); assertTrue(model.getTimeLimit() == 4 * nbBuckets); } + + public void testScaleTo_7() { + // verify scaleTo with barWidth > 1 + final int nbBuckets = 100; + final int maxHeight = 24; + final int width = 10; + final int barWidth = 4; + final int nbEvents = 2 * nbBuckets + 1; + + // (int)(width / barWith) = 2 + // -> 2 bars -> expected result needs two buckets (scaled data) + // + // buckets (in model) per bar = last bucket id / nbBars + 1 (plus 1 to cover all used buckets) + // -> buckets per bar = 50 / 2 + 1 = 26 + // -> first entry in expected result is 26 * 4 = 104 + // -> second entry in expected result is 22 * 4 + 9 = 97 + final int[] expectedResult = new int[] { 104, 97 }; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i, i); + } + + // verify scaled data + HistogramScaledData result = model.scaleTo(width, maxHeight, barWidth); + + assertEquals(4 * 26, result.fBucketDuration); + assertEquals(0, result.fCurrentBucket); + assertEquals(0, result.fFirstBucketTime); + assertEquals(0, result.fFirstEventTime); + assertEquals(1, result.fLastBucket); + assertEquals(104, result.fMaxValue); + assertEquals((double)maxHeight/104, result.fScalingFactor); + assertEquals(maxHeight, result.fHeight); + assertEquals(width, result.fWidth); + assertEquals(barWidth, result.fBarWidth); + + for (int i = 0; i < result.fData.length; i++) { + assertEquals(expectedResult[i], result.fData[i]); + } + + // verify model + assertEquals(nbEvents, model.getNbEvents()); + assertEquals(nbBuckets, model.getNbBuckets()); + assertEquals(4, model.getBucketDuration()); + assertEquals(0, model.getFirstBucketTime()); + assertEquals(0, model.getStartTime()); + assertEquals(nbEvents - 1, model.getEndTime()); + assertEquals(4 * nbBuckets, model.getTimeLimit()); + } + public void testScaleToReverse_1() { + final int nbBuckets = 100; + final int maxHeight = 24; + final int width = 10; + final int barWidth = 1; + final int nbEvents = 2 * nbBuckets + 1; + + // (int)(width / barWith) = 10 + // -> 10 bars -> expected result needs 10 buckets (scaled data) + // + // buckets in (model) per bar = last bucket id / nbBars + 1 (plus 1 to cover all used buckets) + // -> buckets per bar = 50 / 10 + 1 = 6 + final int[] expectedResult = new int[] { 21, 24, 24, 24, 24, 24, 24, 24, 12, 0 }; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + for (int i = nbEvents - 1; i >= 0; i--) { + model.countEvent(i, i); + } + + // verify scaled data + HistogramScaledData result = model.scaleTo(width, maxHeight, barWidth); + + assertEquals(4 * 6, result.fBucketDuration); + assertEquals(0, result.fCurrentBucket); + assertEquals(-3, result.fFirstBucketTime); // negative is correct, can happen when reverse + assertEquals(0, result.fFirstEventTime); + assertEquals(9, result.fLastBucket); + assertEquals(24, result.fMaxValue); + assertEquals((double)maxHeight/24, result.fScalingFactor); + assertEquals(maxHeight, result.fHeight); + assertEquals(width, result.fWidth); + assertEquals(barWidth, result.fBarWidth); + + for (int i = 0; i < result.fData.length; i++) { + assertEquals(expectedResult[i], result.fData[i]); + } + + // verify model + assertEquals(nbEvents, model.getNbEvents()); + assertEquals(nbBuckets, model.getNbBuckets()); + assertEquals(4, model.getBucketDuration()); + assertEquals(-3, model.getFirstBucketTime()); + assertEquals(0, model.getStartTime()); + assertEquals(nbEvents - 1, model.getEndTime()); + assertEquals(-3 + 4 * nbBuckets, model.getTimeLimit()); + } + + + public void testScaleToReverse_2() { + final int nbBuckets = 100; + final int maxHeight = 24; + final int width = 10; + final int barWidth = 1; + + final int nbEvents = 2 * nbBuckets; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i, i); + } + + HistogramScaledData result = model.scaleTo(width, maxHeight, barWidth); + + model.clear(); + + for (int i = nbEvents -1; i >= 0; i--) { + model.countEvent(i, i); + } + + HistogramScaledData revResult = model.scaleTo(width, maxHeight, barWidth); + + assertEquals(nbEvents, model.getNbEvents()); + assertEquals(nbBuckets, model.getNbBuckets()); + assertEquals(2, model.getBucketDuration()); + assertEquals(0, model.getFirstBucketTime()); + assertEquals(0, model.getStartTime()); + assertEquals(nbEvents - 1, model.getEndTime()); + assertEquals(2 * nbBuckets, model.getTimeLimit()); + + // For the above number of events, result and revResult are exactly the same. + assertEquals(result.fBucketDuration, revResult.fBucketDuration); + assertEquals(result.fCurrentBucket, revResult.fCurrentBucket); + assertEquals(result.fFirstBucketTime, revResult.fFirstBucketTime); + assertEquals(result.fMaxValue, revResult.fMaxValue); + assertEquals(result.fScalingFactor, revResult.fScalingFactor); + assertEquals(result.fLastBucket, revResult.fLastBucket); + assertEquals(result.getBucketEndTime(0), revResult.getBucketEndTime(0)); + assertEquals(result.getBucketStartTime(0), revResult.getBucketStartTime(0)); + + for (int i = 0; i < result.fData.length; i++) { + assertTrue(result.fData[i] == revResult.fData[i]); + } + } + + public void testModelListener() { + final int nbBuckets = 2000; + final int nbEvents = 10 * nbBuckets + 256; + final int[] count = new int[1]; + count [0] = 0; + + // Test add listener and call of listener + IHistogramModelListener listener = new IHistogramModelListener() { + @Override + public void modelUpdated() { + count[0]++; + } + }; + + // Test that the listener interface is called every 16000 events. + HistogramDataModel model = new HistogramDataModel(nbBuckets); + model.addHistogramListener(listener); + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i+1, i); + } + + assertTrue(count[0] == 1); + + // Test that the listener interface is called when complete is called. + model.complete(); + assertTrue(count[0] == 2); + + // Test that clear triggers call of listener interface + model.clear(); + assertTrue(count[0] == 3); + + // Test remove listener + count[0] = 0; + model.removeHistogramListener(listener); + + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i, i); + } + model.complete(); + assertTrue(count[0] == 0); + } } diff --git a/org.eclipse.linuxtools.lttng.ui/META-INF/MANIFEST.MF b/org.eclipse.linuxtools.lttng.ui/META-INF/MANIFEST.MF index e3fe166072..8cf889675b 100644 --- a/org.eclipse.linuxtools.lttng.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.linuxtools.lttng.ui/META-INF/MANIFEST.MF @@ -38,8 +38,13 @@ Export-Package: org.eclipse.linuxtools.lttng.ui;x-friends:="org.eclipse.linuxtoo org.eclipse.linuxtools.lttng.ui.views.controlflow;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", org.eclipse.linuxtools.lttng.ui.views.controlflow.evProcessor;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", org.eclipse.linuxtools.lttng.ui.views.controlflow.model;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.distribution.model, org.eclipse.linuxtools.lttng.ui.views.events;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", org.eclipse.linuxtools.lttng.ui.views.histogram;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.latency;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.latency.dialogs;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.latency.listeners;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.latency.model;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", org.eclipse.linuxtools.lttng.ui.views.project;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", org.eclipse.linuxtools.lttng.ui.views.project.dialogs;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", org.eclipse.linuxtools.lttng.ui.views.project.handlers;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", diff --git a/org.eclipse.linuxtools.lttng.ui/icons/elcl16/add_button.gif b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/add_button.gif new file mode 100644 index 0000000000..ae9543c6e7 Binary files /dev/null and b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/add_button.gif differ diff --git a/org.eclipse.linuxtools.lttng.ui/icons/elcl16/decreasebar_button.gif b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/decreasebar_button.gif new file mode 100644 index 0000000000..3d9202508c Binary files /dev/null and b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/decreasebar_button.gif differ diff --git a/org.eclipse.linuxtools.lttng.ui/icons/elcl16/delete_button.gif b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/delete_button.gif new file mode 100644 index 0000000000..6bc0689f13 Binary files /dev/null and b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/delete_button.gif differ diff --git a/org.eclipse.linuxtools.lttng.ui/icons/elcl16/increasebar_button.gif b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/increasebar_button.gif new file mode 100644 index 0000000000..aa58227d1a Binary files /dev/null and b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/increasebar_button.gif differ diff --git a/org.eclipse.linuxtools.lttng.ui/icons/elcl16/warning.gif b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/warning.gif new file mode 100644 index 0000000000..7285660618 Binary files /dev/null and b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/warning.gif differ diff --git a/org.eclipse.linuxtools.lttng.ui/icons/eview16/graph.gif b/org.eclipse.linuxtools.lttng.ui/icons/eview16/graph.gif new file mode 100644 index 0000000000..fc187dc2d0 Binary files /dev/null and b/org.eclipse.linuxtools.lttng.ui/icons/eview16/graph.gif differ diff --git a/org.eclipse.linuxtools.lttng.ui/plugin.properties b/org.eclipse.linuxtools.lttng.ui/plugin.properties index 5d6ea9dc3e..2211985c6d 100644 --- a/org.eclipse.linuxtools.lttng.ui/plugin.properties +++ b/org.eclipse.linuxtools.lttng.ui/plugin.properties @@ -14,6 +14,7 @@ controlflow.view.name = Control Flow resources.view.name = Resources statistics.view.name = Statistics histogram.view.name = Histogram +latency.view.name = Latency View wizard.category.name = LTTng project.new.wizard.name = LTTng Project diff --git a/org.eclipse.linuxtools.lttng.ui/plugin.xml b/org.eclipse.linuxtools.lttng.ui/plugin.xml index 15bd8f1294..988f3e8455 100644 --- a/org.eclipse.linuxtools.lttng.ui/plugin.xml +++ b/org.eclipse.linuxtools.lttng.ui/plugin.xml @@ -90,6 +90,15 @@ name="%histogram.view.name" restorable="true"> + + diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/BaseDistributionData.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/BaseDistributionData.java new file mode 100644 index 0000000000..ef3ee33f92 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/BaseDistributionData.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + ******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.distribution.model; + + +/** + * BaseDistributionData + *

+ */ +public class BaseDistributionData { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + public final static int OUT_OF_RANGE_BUCKET = -1; + + /** + * Number of buckets + */ + protected final int fNbBuckets; + + /** + * Duration of each bucket + */ + protected long fBucketDuration; + + /** + * Bucket index of last event time + */ + protected int fLastBucket; + + /** + * Timestamp of the first bucket. (could be negative when analyzing events with descending time!!!) + */ + protected long fFirstBucketTime; + + /** + * Timestamp of the first event + */ + protected long fFirstEventTime; + + /** + * Timestamp of the last event + */ + protected long fLastEventTime; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + public BaseDistributionData(int nbBuckets) { + fNbBuckets = nbBuckets; + clear(); + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + public int getNbBuckets() { + return fNbBuckets; + } + + public long getBucketDuration() { + return fBucketDuration; + } + + public void setBucketDuration(long bucketDuration) { + fBucketDuration = bucketDuration; + } + + public int getLastBucket() { + return fLastBucket; + } + + public void setLastBucket(int lastBucket) { + fLastBucket = lastBucket; + } + + public long getFirstBucketTime() { + return fFirstBucketTime; + } + + public void setFirstBucketTime(long firstBucketTime) { + fFirstBucketTime = firstBucketTime; + } + + public long getLastBucketTime() { + return getBucketStartTime(fLastBucket); + } + + public long getFirstEventTime() { + return fFirstEventTime; + } + + public void setFirstEventTime(long firstEventTime) { + fFirstEventTime = firstEventTime; + } + + public long getLastEventTime() { + return fLastEventTime; + } + + public void setLastEventTime(long lastEventTime) { + fLastEventTime = lastEventTime; + } + + public long getBucketStartTime(int index) { + return fFirstBucketTime + index * fBucketDuration; + } + + public long getBucketEndTime(int index) { + return getBucketStartTime(index) + fBucketDuration; + } + + public int getIndex(long time) { + return (int)((time - fFirstBucketTime) / fBucketDuration); + } + + public boolean isIndexValid(int index) { + return ((index >= 0) && (index <= fNbBuckets - 1)); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + public void clear() { + fFirstBucketTime = 0; + fFirstEventTime = 0; + fLastEventTime = 0; + fLastBucket = 0; + fBucketDuration = 1; // 1ns + } +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/DistributionData.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/DistributionData.java new file mode 100644 index 0000000000..75e3286bd0 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/DistributionData.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + ******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.distribution.model; + +import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config; + +/** + * DistributionData + *

+ * The algorithm is based on the algorithm for the Histogram. The difference is that + * it supports two dimensions. For more details about the model principle + * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramDataModel + *

+ */ +abstract public class DistributionData extends BaseDistributionData { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * Flag to indicate if given timestamp is the first one to count + */ + protected boolean fIsFirst; + + /** + * reference to fBuckets + */ + protected final int [][] fBuckets; + + /** + * Time limit (current available longest time) + */ + protected long fTimeLimit; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + public DistributionData(int[][] buckets) { + this(Config.DEFAULT_NUMBER_OF_BUCKETS, buckets); + } + + public DistributionData(int nbBuckets, int[][] buckets) { + super(nbBuckets); + fBuckets = buckets; + clear(); + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + public long getTimeLimit() { + return fTimeLimit; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.BaseDistributionData#clear() + */ + @Override + public void clear() { + super.clear(); + fIsFirst = true; + updateEndTime(); + } + + public boolean isFirst() { + return fIsFirst; + } + + public int countEvent(long timestamp) { + + // Set the start/end time if not already done + if (fIsFirst) { + fIsFirst = false; + fFirstBucketTime = timestamp; + fFirstEventTime = timestamp; + + updateEndTime(); + } + + // save first event time if necessary + if (timestamp < fFirstEventTime) { + fFirstEventTime = timestamp; + } + + // save last event time if necessary + if (fLastEventTime < timestamp) { + fLastEventTime = timestamp; + } + + + if (timestamp >= fFirstBucketTime) { + // Compact as needed + while (timestamp >= fTimeLimit) { + mergeBuckets(); + } + + } else { + + // Get offset for buckets adjustment + int offset = getOffset(timestamp); + + // Compact as needed + while (fLastBucket + offset >= fNbBuckets) { + mergeBuckets(); + offset = getOffset(timestamp); + } + + // Move buckets with offset (to right) + moveBuckets(offset); + + // Adjust start/end time and index + fLastBucket = fLastBucket + offset; + fFirstBucketTime = fFirstBucketTime - offset * fBucketDuration; + updateEndTime(); + } + + // Increment the right bucket + int index = (int) ((timestamp - fFirstBucketTime) / fBucketDuration); + + if (fLastBucket < index) { + fLastBucket = index; + } + + return index; + } + + // ------------------------------------------------------------------------ + // Abstract + // ------------------------------------------------------------------------ + + /** + * Moves content of buckets with the given offset in positive direction. + * It has to be implemented accordingly in the relevant sub-classes for + * horizontal and vertical direction. + * + * @param buckets - 2-dimensional array of buckets + * @param offset - offset to move + */ + abstract protected void moveBuckets(int offset); + + /** + * Merges buckets if end time is exceeded. It has to be implemented + * accordingly in the relevant sub-classes for horizontal and + * vertical direction. + * @param buckets + */ + abstract protected void mergeBuckets(); + + // ------------------------------------------------------------------------ + // Helper Functions + // ------------------------------------------------------------------------ + protected int getOffset(long timestamp) { + int offset = (int) ((fFirstBucketTime - timestamp) / fBucketDuration); + if ((fFirstBucketTime - timestamp) % fBucketDuration != 0) { + offset++; + } + return offset; + } + + protected void updateEndTime() { + fTimeLimit = fFirstBucketTime + fNbBuckets * fBucketDuration; + } +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/HorDistributionData.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/HorDistributionData.java new file mode 100644 index 0000000000..766384f69c --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/HorDistributionData.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + ******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.distribution.model; + +/** + * HorDistributionData + *

+ * Implementation of DistributionData for horizontal direction. + */ +public class HorDistributionData extends DistributionData { + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + public HorDistributionData(int nbBuckets, int[][] buckets) { + super(nbBuckets, buckets); + } + + // ------------------------------------------------------------------------ + // Abstract function implementation + // ------------------------------------------------------------------------ + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.DistributionData#moveBuckets(int) + */ + @Override + protected void moveBuckets(int offset) { + for (int j = 0; j < fNbBuckets; j++) { + + for(int i = fNbBuckets - 1; i >= offset; i--) { + fBuckets[i][j] = fBuckets[i-offset][j]; + } + + for (int i = 0; i < offset; i++) { + fBuckets[i][j] = 0; + } + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.DistributionData#mergeBuckets() + */ + @Override + protected void mergeBuckets() { + + for (int y = 0; y < fNbBuckets; y++) { + for (int i = 0; i < fNbBuckets / 2; i++) { + fBuckets[i][y] = fBuckets[2 * i][y] + fBuckets[2 * i + 1][y]; + } + + for (int i = fNbBuckets / 2; i < fNbBuckets; i++) { + fBuckets[i][y] = 0; + } + } + fBucketDuration = fBucketDuration * 2; + updateEndTime(); + fLastBucket = fNbBuckets / 2 - 1; + } +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/IBaseDistributionModel.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/IBaseDistributionModel.java new file mode 100644 index 0000000000..5c61a9eee2 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/IBaseDistributionModel.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.distribution.model; + +public interface IBaseDistributionModel { + /** + * Interface to complete the model + */ + public void complete(); + + /** + * Interface to clear the model + */ + public void clear(); +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/VerDistributionData.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/VerDistributionData.java new file mode 100644 index 0000000000..e44398c417 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/VerDistributionData.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + ******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.distribution.model; + +/** + * VerDistributionData + * + * Implementation of DistributionData for vertical direction. + *

+ */ +public class VerDistributionData extends DistributionData { + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + public VerDistributionData(int nbBuckets, int[][] buckets) { + super(nbBuckets, buckets); + } + + // ------------------------------------------------------------------------ + // Abstract function implementation + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.DistributionData#moveBuckets(int) + */ + @Override + protected void moveBuckets(int offset) { + for (int j = 0; j < fNbBuckets; j++) { + + for(int i = fNbBuckets - 1; i >= offset; i--) { + fBuckets[j][i] = fBuckets[j][i-offset]; + } + + for (int i = 0; i < offset; i++) { + fBuckets[j][i] = 0; + } + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.DistributionData#mergeBuckets() + */ + @Override + protected void mergeBuckets() { + for (int x = 0; x < fNbBuckets; x++) { + for (int i = 0; i < fNbBuckets / 2; i++) { + fBuckets[x][i] = fBuckets[x][2 * i] + fBuckets[x][2 * i + 1]; + } + for (int i = fNbBuckets / 2; i < fNbBuckets; i++) { + fBuckets[x][i] = 0; + } + } + fBucketDuration = fBucketDuration * 2; + updateEndTime(); + fLastBucket = fNbBuckets / 2 - 1; + } +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/FullTraceHistogram.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/FullTraceHistogram.java index d7e0345d4d..176cf8db6b 100644 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/FullTraceHistogram.java +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/FullTraceHistogram.java @@ -8,6 +8,7 @@ * * Contributors: * Francois Chouinard - Initial API and implementation + * Bernd Hufmann - Changed to updated histogram data model *******************************************************************************/ package org.eclipse.linuxtools.lttng.ui.views.histogram; @@ -75,7 +76,7 @@ public class FullTraceHistogram extends Histogram implements MouseMoveListener { fRangeStartTime = startTime; fRangeDuration = duration; fZoom.setNewRange(fRangeStartTime, fRangeDuration); - refresh(); + fDataModel.complete(); } @Override @@ -131,7 +132,7 @@ public class FullTraceHistogram extends Histogram implements MouseMoveListener { newStart = newEnd - fZoom.getDuration(); } fRangeStartTime = newStart; - refresh(); + fDataModel.complete(); } } @@ -166,7 +167,7 @@ public class FullTraceHistogram extends Histogram implements MouseMoveListener { long bucketSpan = fScaledData.fBucketDuration; int rangeWidth = (int) (fRangeDuration / bucketSpan); - int left = (int) ((fRangeStartTime - fDataModel.getStartTime()) / bucketSpan); + int left = (int) ((fRangeStartTime - fDataModel.getFirstBucketTime()) / bucketSpan); int right = left + rangeWidth; int center = (left + right) / 2; int height = fCanvas.getSize().y - 2; diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/Histogram.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/Histogram.java index b7632607e3..dc665aba11 100644 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/Histogram.java +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/Histogram.java @@ -8,6 +8,7 @@ * * Contributors: * Francois Chouinard - Initial API and implementation + * Bernd Hufmann - Changed to updated histogram data model *******************************************************************************/ package org.eclipse.linuxtools.lttng.ui.views.histogram; @@ -69,15 +70,12 @@ import org.eclipse.swt.widgets.Text; *

  • number of events in that time range * */ -public abstract class Histogram implements ControlListener, PaintListener, KeyListener, MouseListener, MouseTrackListener { +public abstract class Histogram implements ControlListener, PaintListener, KeyListener, MouseListener, MouseTrackListener, IHistogramModelListener { // ------------------------------------------------------------------------ // Constants // ------------------------------------------------------------------------ - // Histogram refresh frequency - private final static int REFRESH_FREQUENCY = HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS; - // Histogram colors private final Color fBackgroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE); private final Color fCurrentEventColor = Display.getCurrent().getSystemColor(SWT.COLOR_RED); @@ -86,6 +84,8 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi // Timestamp scale (nanosecond) public static final byte TIME_SCALE = -9; + + public static final int HISTOGRAM_BAR_WIDTH = 1; // ------------------------------------------------------------------------ // Attributes @@ -118,6 +118,7 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi createWidget(parent); fDataModel = new HistogramDataModel(); + fDataModel.addHistogramListener(this); clear(); fCanvas.addControlListener(this); @@ -129,6 +130,7 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi public void dispose() { fHistoBarColor.dispose(); + fDataModel.removeHistogramListener(this); } private void createWidget(Composite parent) { @@ -238,7 +240,7 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi // ------------------------------------------------------------------------ public long getStartTime() { - return fDataModel.getStartTime(); + return fDataModel.getFirstBucketTime(); } public long getEndTime() { @@ -248,6 +250,10 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi public long getTimeLimit() { return fDataModel.getTimeLimit(); } + + public HistogramDataModel getDataModel() { + return fDataModel; + } // ------------------------------------------------------------------------ // Operations @@ -261,7 +267,6 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi public void clear() { fDataModel.clear(); fScaledData = null; - refresh(); } /** @@ -269,12 +274,8 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi * * @param timestamp */ - public void countEvent(long timestamp) { - fDataModel.countEvent(timestamp); - if (fDataModel.getNbEvents() % REFRESH_FREQUENCY == 0) { - refresh(); - refresh(); // This is intentional. Exercise left to the reader :-) - } + public void countEvent(long eventCount, long timestamp) { + fDataModel.countEvent(eventCount, timestamp); } /** @@ -284,8 +285,7 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi */ public void setCurrentEvent(long timestamp) { fCurrentEventTime = (timestamp > 0) ? timestamp : 0; - fDataModel.setCurrentEvent(timestamp); - refresh(); + fDataModel.setCurrentEventNotifyListeners(timestamp); } /** @@ -297,7 +297,7 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi public synchronized long getTimestamp(int offset) { assert offset > 0 && offset < fScaledData.fWidth; try { - return fDataModel.getStartTime() + fScaledData.fBucketDuration * offset; + return fDataModel.getFirstBucketTime() + fScaledData.fBucketDuration * offset; } catch (Exception e) { return 0; // TODO: Fix that racing condition (NPE) } @@ -310,9 +310,9 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi * @return the offset of the corresponding bucket (-1 if invalid) */ public synchronized int getOffset(long timestamp) { - if (timestamp < fDataModel.getStartTime() || timestamp > fDataModel.getEndTime()) + if (timestamp < fDataModel.getFirstBucketTime() || timestamp > fDataModel.getEndTime()) return -1; - return (int) ((timestamp - fDataModel.getStartTime()) / fScaledData.fBucketDuration); + return (int) ((timestamp - fDataModel.getFirstBucketTime()) / fScaledData.fBucketDuration); } /** @@ -370,7 +370,8 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi /** * Refresh the histogram display */ - protected void refresh() { + @Override + public void modelUpdated() { if (!fCanvas.isDisposed() && fCanvas.getDisplay() != null) { fCanvas.getDisplay().asyncExec(new Runnable() { @Override @@ -382,10 +383,10 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi if (canvasWidth <= 0 || canvasHeight <= 0) return; fDataModel.setCurrentEvent(fCurrentEventTime); - fScaledData = fDataModel.scaleTo(canvasWidth, canvasHeight); + fScaledData = fDataModel.scaleTo(canvasWidth, canvasHeight, HISTOGRAM_BAR_WIDTH); fCanvas.redraw(); // Display histogram and update X-,Y-axis labels - fTimeRangeStartText.setText(HistogramUtils.nanosecondsToString(fDataModel.getStartTime())); + fTimeRangeStartText.setText(HistogramUtils.nanosecondsToString(fDataModel.getFirstBucketTime())); fTimeRangeEndText.setText(HistogramUtils.nanosecondsToString(fDataModel.getEndTime())); fMaxNbEventsText.setText(Long.toString(fScaledData.fMaxValue)); // The Y-axis area might need to be re-sized @@ -540,8 +541,12 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi } private String formatToolTipLabel(int index) { - long startTime = fDataModel.getStartTime() + fScaledData.fCurrentBucket * fScaledData.fBucketDuration; - long endTime = startTime + fScaledData.fBucketDuration; + long startTime = fScaledData.getBucketStartTime(fScaledData.fCurrentBucket); + // negative values are possible if time values came into the model in decreasing order + if (startTime < 0) { + startTime = 0; + } + long endTime = fScaledData.getBucketEndTime(fScaledData.fCurrentBucket); int nbEvents = (index >= 0) ? fScaledData.fData[index] : 0; StringBuffer buffer = new StringBuffer(); @@ -561,12 +566,11 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi @Override public void controlMoved(ControlEvent event) { - refresh(); + fDataModel.complete(); } @Override public void controlResized(ControlEvent event) { - refresh(); + fDataModel.complete(); } - } diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramDataModel.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramDataModel.java index 36c6fb748c..28b944ecca 100644 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramDataModel.java +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramDataModel.java @@ -8,12 +8,15 @@ * * Contributors: * Francois Chouinard - Initial API and implementation + * Bernd Hufmann - Implementation of new interfaces /listeners and support for + * time stamp in any order *******************************************************************************/ package org.eclipse.linuxtools.lttng.ui.views.histogram; import java.util.Arrays; +import org.eclipse.core.runtime.ListenerList; import org.eclipse.linuxtools.lttng.core.exceptions.EventOutOfSequenceException; import org.eclipse.linuxtools.lttng.ui.LTTngUILogger; @@ -41,6 +44,15 @@ import org.eclipse.linuxtools.lttng.ui.LTTngUILogger; * timespan (timespan' = n * d', where d' = * 2d). This compaction happens as needed as the trace is read. *

    + * The model allows for timestamps in not increasing order. The timestamps can + * be fed to the model in any order. If an event has a timestamp less than the + * basetime, the buckets will be moved to the right to account for the + * new smaller timestamp. The new basetime is a multiple of the bucket + * duration smaller then the previous basetime. Note that the basetime + * might not be anymore a timestamp of an event. If necessary, the buckets will + * be compacted before moving to the right. This might be necessary to not + * loose any event counts at the end of the buckets array. + *

    * The mapping from the model to the UI is performed by the scaleTo() * method. By keeping the number of buckets n relatively large with * respect to to the number of pixels in the actual histogram, we should achieve @@ -51,7 +63,7 @@ import org.eclipse.linuxtools.lttng.ui.LTTngUILogger; *

    * TODO: Cut-off eccentric values? TODO: Support for going back in time? */ -public class HistogramDataModel { +public class HistogramDataModel implements IHistogramDataModel { // ------------------------------------------------------------------------ // Constants @@ -60,6 +72,8 @@ public class HistogramDataModel { // The default number of buckets public static final int DEFAULT_NUMBER_OF_BUCKETS = 16 * 1000; + public static final int REFRESH_FREQUENCY = DEFAULT_NUMBER_OF_BUCKETS; + // // The ratio where an eccentric value will be truncated // private static final int MAX_TO_AVERAGE_CUTOFF_RATIO = 5; @@ -75,15 +89,15 @@ public class HistogramDataModel { private int fLastBucket; // Timestamps + private long fFirstBucketTime; // could be negative when analyzing events with descending order!!! private long fFirstEventTime; private long fLastEventTime; private long fCurrentEventTime; private long fTimeLimit; - - // ------------------------------------------------------------------------ - // Constructors - // ------------------------------------------------------------------------ - + + // private listener lists + private final ListenerList fModelListeners; + public HistogramDataModel() { this(DEFAULT_NUMBER_OF_BUCKETS); } @@ -91,6 +105,7 @@ public class HistogramDataModel { public HistogramDataModel(int nbBuckets) { fNbBuckets = nbBuckets; fBuckets = new long[nbBuckets]; + fModelListeners = new ListenerList(); clear(); } @@ -100,10 +115,16 @@ public class HistogramDataModel { fBucketDuration = other.fBucketDuration; fNbEvents = other.fNbEvents; fLastBucket = other.fLastBucket; + fFirstBucketTime = other.fFirstBucketTime; fFirstEventTime = other.fFirstEventTime; fLastEventTime = other.fLastEventTime; fCurrentEventTime = other.fCurrentEventTime; fTimeLimit = other.fTimeLimit; + fModelListeners = new ListenerList(); + Object[] listeners = other.fModelListeners.getListeners(); + for (Object listener : listeners) { + fModelListeners.add(listener); + } } // ------------------------------------------------------------------------ @@ -121,11 +142,15 @@ public class HistogramDataModel { public long getBucketDuration() { return fBucketDuration; } + + public long getFirstBucketTime() { + return fFirstBucketTime; + } public long getStartTime() { return fFirstEventTime; } - + public long getEndTime() { return fLastEventTime; } @@ -137,23 +162,55 @@ public class HistogramDataModel { public long getTimeLimit() { return fTimeLimit; } + + // ------------------------------------------------------------------------ + // Listener handling + // ------------------------------------------------------------------------ + + public void addHistogramListener(IHistogramModelListener listener) { + fModelListeners.add(listener); + } + + public void removeHistogramListener(IHistogramModelListener listener) { + fModelListeners.remove(listener); + } + private void fireModelUpdateNotification() { + fireModelUpdateNotification(0); + } + + private void fireModelUpdateNotification(long count) { + if (count % REFRESH_FREQUENCY == 0) { + Object[] listeners = fModelListeners.getListeners(); + for (int i = 0; i < listeners.length; i++) { + IHistogramModelListener listener = (IHistogramModelListener) listeners[i]; + listener.modelUpdated(); + } + } + } + // ------------------------------------------------------------------------ // Operations // ------------------------------------------------------------------------ + @Override + public void complete() { + fireModelUpdateNotification(); + } /** * Clear the histogram model. */ + @Override public void clear() { Arrays.fill(fBuckets, 0); fNbEvents = 0; - fFirstEventTime = 0; + fFirstBucketTime = 0; fLastEventTime = 0; fCurrentEventTime = 0; fLastBucket = 0; fBucketDuration = 1; // 1ns updateEndTime(); + fireModelUpdateNotification(); } /** @@ -165,63 +222,108 @@ public class HistogramDataModel { fCurrentEventTime = timestamp; } + /** + * Sets the current event time + * + * @param timestamp + */ + public void setCurrentEventNotifyListeners(long timestamp) { + fCurrentEventTime = timestamp; + fireModelUpdateNotification(); + } + /** * Add event to the correct bucket, compacting the if needed. * * @param timestamp the timestamp of the event to count */ - public void countEvent(long timestamp) { + @Override + public void countEvent(long eventCount, long timestamp) { + + // Validate + if (timestamp < 0) { + String message = "Negative time value"; //$NON-NLS-1$ + EventOutOfSequenceException exception = new EventOutOfSequenceException(message); + LTTngUILogger.logError(message, exception); + return; + } + // Set the start/end time if not already done if (fLastBucket == 0 && fBuckets[0] == 0 && timestamp > 0) { + fFirstBucketTime = timestamp; fFirstEventTime = timestamp; updateEndTime(); } + + if (timestamp < fFirstEventTime) { + fFirstEventTime = timestamp; + } + if (fLastEventTime < timestamp) { fLastEventTime = timestamp; } + + if (timestamp >= fFirstBucketTime) { - // Compact as needed - while (timestamp >= fTimeLimit) { - mergeBuckets(); - } + // Compact as needed + while (timestamp >= fTimeLimit) { + mergeBuckets(); + } - // Validate - if (timestamp < fFirstEventTime) { - String message = "Out of order timestamp. Going back in time?"; //$NON-NLS-1$ - EventOutOfSequenceException exception = new EventOutOfSequenceException(message); - LTTngUILogger.logError(message, exception); - return; - } + } else { + + // get offset for adjustment + int offset = getOffset(timestamp); + + // Compact as needed + while(fLastBucket + offset >= fNbBuckets) { + mergeBuckets(); + offset = getOffset(timestamp); + } + + moveBuckets(offset); + + fLastBucket = fLastBucket + offset; + fFirstBucketTime = fFirstBucketTime - offset*fBucketDuration; + updateEndTime(); + } + // Increment the right bucket - int index = (int) ((timestamp - fFirstEventTime) / fBucketDuration); + int index = (int) ((timestamp - fFirstBucketTime) / fBucketDuration); fBuckets[index]++; fNbEvents++; if (fLastBucket < index) fLastBucket = index; + + fireModelUpdateNotification(eventCount); } /** - * Scale the model data to the width and height requested. + * Scale the model data to the width, height and bar width requested. * * @param width * @param height + * @param bar width * @return the result array of size [width] and where the highest value * doesn't exceed [height] */ - public HistogramScaledData scaleTo(int width, int height) { + @Override + public HistogramScaledData scaleTo(int width, int height, int barWidth) { // Basic validation - if (width <= 0 || height <= 0) - throw new AssertionError("Invalid histogram dimensions (" + width + "x" + height + ")"); + if (width <= 0 || height <= 0 || barWidth <= 0) + throw new AssertionError("Invalid histogram dimensions (" + width + "x" + height + ", barWidth=" + barWidth + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ // The result structure - HistogramScaledData result = new HistogramScaledData(width, height); + HistogramScaledData result = new HistogramScaledData(width, height, barWidth); // Scale horizontally result.fMaxValue = 0; - int bucketsPerBar = fLastBucket / width + 1; + + int nbBars = width / barWidth; + int bucketsPerBar = fLastBucket / nbBars + 1; result.fBucketDuration = bucketsPerBar * fBucketDuration; - for (int i = 0; i < width; i++) { + for (int i = 0; i < nbBars; i++) { int count = 0; for (int j = i * bucketsPerBar; j < (i + 1) * bucketsPerBar; j++) { if (fNbBuckets <= j) @@ -240,11 +342,13 @@ public class HistogramDataModel { } // Set the current event index in the scaled histogram - if (fCurrentEventTime >= fFirstEventTime && fCurrentEventTime <= fLastEventTime) - result.fCurrentBucket = (int) ((fCurrentEventTime - fFirstEventTime) / fBucketDuration) / bucketsPerBar; + if (fCurrentEventTime >= fFirstBucketTime && fCurrentEventTime <= fLastEventTime) + result.fCurrentBucket = (int) ((fCurrentEventTime - fFirstBucketTime) / fBucketDuration) / bucketsPerBar; else result.fCurrentBucket = HistogramScaledData.OUT_OF_RANGE_BUCKET; + result.fFirstBucketTime = fFirstBucketTime; + result.fFirstEventTime = fFirstEventTime; return result; } @@ -253,7 +357,7 @@ public class HistogramDataModel { // ------------------------------------------------------------------------ private void updateEndTime() { - fTimeLimit = fFirstEventTime + fNbBuckets * fBucketDuration; + fTimeLimit = fFirstBucketTime + fNbBuckets * fBucketDuration; } private void mergeBuckets() { @@ -265,5 +369,23 @@ public class HistogramDataModel { updateEndTime(); fLastBucket = fNbBuckets / 2 - 1; } + + private void moveBuckets(int offset) { + for(int i = fNbBuckets - 1; i >= offset; i--) { + fBuckets[i] = fBuckets[i-offset]; + } + + for (int i = 0; i < offset; i++) { + fBuckets[i] = 0; + } + } + + private int getOffset(long timestamp) { + int offset = (int) ((fFirstBucketTime - timestamp) / fBucketDuration); + if ((fFirstBucketTime - timestamp) % fBucketDuration != 0) { + offset++; + } + return offset; + } } diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramRequest.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramRequest.java index 2b88329570..120d243298 100644 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramRequest.java +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramRequest.java @@ -30,22 +30,22 @@ public class HistogramRequest extends TmfEventRequest { // Attributes // ------------------------------------------------------------------------ - private final Histogram fHistogram; + protected final HistogramDataModel fHistogram; // ------------------------------------------------------------------------ // Constructor // ------------------------------------------------------------------------ - public HistogramRequest(Histogram histogram, TmfTimeRange range, int rank, int nbEvents, ITmfDataRequest.ExecutionType execType) { + public HistogramRequest(HistogramDataModel histogram, TmfTimeRange range, int rank, int nbEvents, ITmfDataRequest.ExecutionType execType) { super(LttngEvent.class, range, rank, nbEvents, LttngConstants.DEFAULT_BLOCK_SIZE, execType); fHistogram = histogram; } - public HistogramRequest(Histogram histogram, TmfTimeRange range, ITmfDataRequest.ExecutionType execType) { + public HistogramRequest(HistogramDataModel histogram, TmfTimeRange range, ITmfDataRequest.ExecutionType execType) { this(histogram, range, 0, ALL_DATA, execType); } - public HistogramRequest(Histogram histogram, TmfTimeRange range, int rank, ITmfDataRequest.ExecutionType execType) { + public HistogramRequest(HistogramDataModel histogram, TmfTimeRange range, int rank, ITmfDataRequest.ExecutionType execType) { this(histogram, range, rank, ALL_DATA, execType); } @@ -58,19 +58,19 @@ public class HistogramRequest extends TmfEventRequest { super.handleData(event); if (event != null) { long timestamp = event.getTimestamp().getValue(); - fHistogram.countEvent(timestamp); + fHistogram.countEvent(getNbRead(), timestamp); } } @Override public void handleCompleted() { - fHistogram.refresh(); + fHistogram.complete(); super.handleCompleted(); } @Override public void handleCancel() { - fHistogram.refresh(); + fHistogram.clear(); super.handleCancel(); } diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramScaledData.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramScaledData.java index 8260b4fb59..b1e6a1fe5e 100644 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramScaledData.java +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramScaledData.java @@ -8,6 +8,7 @@ * * Contributors: * Francois Chouinard - Initial API and implementation + * Bernd Hufmann - Added setter and getter *******************************************************************************/ package org.eclipse.linuxtools.lttng.ui.views.histogram; @@ -33,38 +34,67 @@ public class HistogramScaledData { public int fWidth; public int fHeight; + public int fBarWidth; public int[] fData; public long fBucketDuration; public long fMaxValue; public int fCurrentBucket; public int fLastBucket; public double fScalingFactor; + public long fFirstBucketTime; + public long fFirstEventTime; // ------------------------------------------------------------------------ // Constructor // ------------------------------------------------------------------------ - public HistogramScaledData(int width, int height) { + public HistogramScaledData(int width, int height, int barWidth) { fWidth = width; fHeight = height; - fData = new int[width]; + fBarWidth = barWidth; + fData = new int[width/fBarWidth]; Arrays.fill(fData, 0); fBucketDuration = 1; fMaxValue = 0; fCurrentBucket = 0; fLastBucket = 0; fScalingFactor = 1; + fFirstBucketTime = 0; } public HistogramScaledData(HistogramScaledData other) { fWidth = other.fWidth; fHeight = other.fHeight; + fBarWidth = other.fBarWidth; fData = Arrays.copyOf(other.fData, fWidth); fBucketDuration = other.fBucketDuration; fMaxValue = other.fMaxValue; fCurrentBucket = other.fCurrentBucket; fLastBucket = other.fLastBucket; fScalingFactor = other.fScalingFactor; + fFirstBucketTime = other.fFirstBucketTime; + } + + // ------------------------------------------------------------------------ + // Setter and Getter + // ------------------------------------------------------------------------ + public long getFirstBucketTime() { + return fFirstBucketTime; } + public void setFirstBucketTime(long firstEventTime) { + fFirstBucketTime = firstEventTime; + } + + public long getLastBucketTime() { + return getBucketStartTime(fLastBucket); + } + + public long getBucketStartTime(int index) { + return fFirstBucketTime + index * fBucketDuration; + } + + public long getBucketEndTime(int index) { + return getBucketStartTime(index) + fBucketDuration; + } } \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramView.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramView.java index 32f9dc11bf..62bc9573ef 100644 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramView.java +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramView.java @@ -265,8 +265,7 @@ public class HistogramView extends TmfView { public void updateCurrentEventTime(long newTime) { if (fCurrentExperiment != null) { TmfTimeRange timeRange = new TmfTimeRange(new TmfTimestamp(newTime, TIME_SCALE), TmfTimestamp.BigCrunch); - HistogramRequest request = new HistogramRequest(fTimeRangeHistogram, timeRange, 0, 1, - ExecutionType.FOREGROUND) { + HistogramRequest request = new HistogramRequest(fTimeRangeHistogram.getDataModel(), timeRange, 0, 1, ExecutionType.FOREGROUND) { @Override public void handleData(LttngEvent event) { if (event != null) { @@ -445,7 +444,7 @@ public class HistogramView extends TmfView { fTimeRangeHistogram.clear(); fTimeRangeHistogram.setTimeRange(startTime, endTime - startTime); - fTimeRangeRequest = new HistogramRequest(fTimeRangeHistogram, timeRange, ExecutionType.FOREGROUND); + fTimeRangeRequest = new HistogramRequest(fTimeRangeHistogram.getDataModel(), timeRange, ExecutionType.FOREGROUND); fCurrentExperiment.sendRequest(fTimeRangeRequest); } @@ -453,8 +452,8 @@ public class HistogramView extends TmfView { if (fFullTraceRequest != null && !fFullTraceRequest.isCompleted()) { fFullTraceRequest.cancel(); } - fFullTraceRequest = new HistogramRequest(fFullTraceHistogram, fullRange, - (int) fFullTraceHistogram.fDataModel.getNbEvents(), ExecutionType.BACKGROUND); + fFullTraceRequest = new HistogramRequest(fFullTraceHistogram.getDataModel(), fullRange, (int) fFullTraceHistogram.fDataModel.getNbEvents(), + ExecutionType.BACKGROUND); fCurrentExperiment.sendRequest(fFullTraceRequest); } diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/IHistogramDataModel.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/IHistogramDataModel.java new file mode 100644 index 0000000000..35606f3351 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/IHistogramDataModel.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.histogram; + +/** + * IHistogramDataModel + *

    + */ +import org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDistributionModel; + +public interface IHistogramDataModel extends IBaseDistributionModel { + /** + * Add event to the correct bucket, compacting the if needed. + * + * @param timestamp the timestamp of the event to count + */ + public void countEvent(long eventCount, long timestamp); + + /** + * Scale the model data to the width, height and bar width requested. + * + * @param width + * @param height + * @param bar width + * @return the result array of size [width] and where the highest value + * doesn't exceed [height] considering the bar width [barWidth] + */ + public HistogramScaledData scaleTo(int width, int height, int barWidth); +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/IHistogramModelListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/IHistogramModelListener.java new file mode 100644 index 0000000000..d980a17ccb --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/IHistogramModelListener.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.histogram; + +/** + * IHistogramModelListener + *

    + */ +public interface IHistogramModelListener { + /** + * Method to notify listeners about model updates + */ + public void modelUpdated(); +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/TimeRangeHistogram.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/TimeRangeHistogram.java index 1ed5f7ef5b..85a00612e4 100644 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/TimeRangeHistogram.java +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/TimeRangeHistogram.java @@ -1,6 +1,6 @@ /******************************************************************************* - * Copyright (c) 2011 Ericsson * + * Copyright (c) 2011 Ericsson * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at @@ -8,6 +8,7 @@ * * Contributors: * Francois Chouinard - Initial API and implementation + * Bernd Hufmann - Changed to updated histogram data model *******************************************************************************/ package org.eclipse.linuxtools.lttng.ui.views.histogram; diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/AbstractViewer.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/AbstractViewer.java new file mode 100644 index 0000000000..75597d693b --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/AbstractViewer.java @@ -0,0 +1,255 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Adapted to new model-view-controller design + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency; + +import org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDistributionModel; +import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseListener; +import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseTrackListener; +import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener; +import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.ZoomListener; +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; + +/** + * AbstractViewer + *

    + * Abstract viewer. + * + * @author Philippe Sawicki + */ +public abstract class AbstractViewer extends Canvas { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * Parent composite node. + */ + protected Composite fParent; + + /** + * Paint listener. + */ + protected AbstractPaintListener fPaintListener; + + /** + * Zoom listener, to zoom in and out of a graph using the scroll wheel. + */ + protected ZoomListener fZoomListener; + + /** + * Tool tip listener. + */ + protected AbstractMouseTrackListener fMouseTraceListener; + + /** + * Mouse listener + */ + protected AbstractMouseListener fMouseListener; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param parent + * The parent composite node. + * @param style + * The SWT style to use to render the view. + */ + public AbstractViewer(Composite parent, int style) { + super(parent, style); + + fParent = parent; + } + + // ------------------------------------------------------------------------ + // Abstract interface + // ------------------------------------------------------------------------ + + /** + * Clears the view. + */ + abstract public void clear(); + + /** + * Clears the background of the view but keeps min and max values. + */ + abstract public void clearBackground(); + + /** + * Method to increase bar width + */ + abstract public void increaseBarWidth(); + + /** + * Method to decrease bar width + */ + abstract public void decreaseBarWidth(); + + /** + * Return data model + */ + abstract public IBaseDistributionModel getModel(); + + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + /** + * Returns the zoom factor for the canvas. + * @return The zoom factor for the canvas. + */ + public int getZoomFactor() { + if (fZoomListener != null) { + return fZoomListener.getZoomFactor(); + } else { + return 1; + } + } + + /** + * Returns the zoom increment for the canvas. + * @return The zoom increment for the canvas. + */ + public int getZoomIncrement() { + if (fZoomListener != null) { + return fZoomListener.getZoomIncrement(); + } else { + return 1; + } + } + + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /** + * Draw horizontal label each "nbTicks" ticks. + * @param nbTicks + * The draw interval. + */ + public void setDrawLabelEachNTicks(int nbTicks) { + fPaintListener.setDrawLabelEachNTicks(nbTicks); + } + + /** + * Sets the title of the graph. + * @param graphTitle + * The title of the graph. + */ + public void setGraphTitle(String graphTitle) { + fPaintListener.setGraphTitle(graphTitle); + } + + /** + * Sets the horizontal axis label. + * @param xLabel + * The horizontal axis label. + * @param offset + * The horizontal axis draw offset (in pixels). + */ + public void setXAxisLabel(String xLabel, int offset) { + fPaintListener.setXAxisLabel(xLabel, offset); + } + + /** + * Sets the vertical axis label. + * @param yLabel + * The vertical axis label. + */ + public void setYAxisLabel(String yLabel) { + fPaintListener.setYAxisLabel(yLabel); + } + + /** + * Asks for the view to be redrawn, synchronously or asynchronously. + * @param asyncRedraw + * If "true", the view will be redrawn asynchronously, otherwise it will be redraw synchronously. + */ + public void askForRedraw(boolean asyncRedraw) { + if (asyncRedraw == true) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + try { + redraw(); + } catch (SWTException e) { + // ... + } + } + }); + } else { + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + try { + redraw(); + } catch (SWTException e) { + // ... + } + } + }); + } + } + + /** + * Asks for the view to be redrawn (asynchronously). + */ + public void askForRedraw() { + askForRedraw(true); + } + + /** + * Redraws the title after a zoom to display the new zoom factor. + */ + public void redrawTitle() { + fPaintListener.paintGraphTitle(); + } + + /** + * Removes the view's listeners before disposing of it. + */ + @Override + public void dispose() { + try { + if (fPaintListener != null) { + removePaintListener(fPaintListener); + fPaintListener = null; + } + if (fZoomListener != null) { + removeListener(SWT.MouseWheel, fZoomListener); + fZoomListener = null; + } + if (fMouseTraceListener != null) { + removeListener(SWT.MouseMove, fMouseTraceListener); + fMouseTraceListener = null; + } + } catch (SWTException e) { + // This exception will be thrown if the user closes the view + // while it is receiving data from the Analyzer. + + // ... + } + + super.dispose(); + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/GraphViewer.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/GraphViewer.java new file mode 100644 index 0000000000..2598543198 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/GraphViewer.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Adapted to new model-view-controller design + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency; + +import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.GraphMouseListener; +import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.GraphPaintListener; +import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.TimePointerListener; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphDataModel; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyGraphModel; +import org.eclipse.swt.widgets.Composite; + +/** + * GraphViewer + *

    + * Graph viewer. + * + * @author Philippe Sawicki + */ +public class GraphViewer extends AbstractViewer implements IGraphModelListener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * Latency graph model + */ + private LatencyGraphModel fModel; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param parent The parent composite node. + * @param style The SWT style to use to render the view. + */ + public GraphViewer(Composite parent, int style) { + super(parent, style); + + // Register the paint listener + fPaintListener = new GraphPaintListener(this); + addPaintListener(fPaintListener); + + // Register the mouse track listener + fMouseTraceListener = new TimePointerListener(this, (GraphPaintListener)fPaintListener); + addMouseTrackListener(fMouseTraceListener); + + // Register mouse listener + fMouseListener = new GraphMouseListener(this, (GraphPaintListener)fPaintListener); + addMouseListener(fMouseListener); + + fModel = new LatencyGraphModel(); + fModel.addGraphModelListener(this); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#dispose() + */ + @Override + public void dispose() { + fModel.removeGraphModelListener(this); + fPaintListener.dispose(); + super.dispose(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#clear() + */ + @Override + public void clear() { + fPaintListener.clear(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#clearBackground() + */ + @Override + public void clearBackground() { + fPaintListener.clear(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#increaseBarWidth() + */ + @Override + public void increaseBarWidth() { + fPaintListener.increaseBarWitdh(); + graphModelUpdated(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#decreaseBarWidth() + */ + @Override + public void decreaseBarWidth() { + fPaintListener.decreaseBarWitdh(); + graphModelUpdated(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#getModel() + */ + @Override + public IGraphDataModel getModel() { + return fModel; + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener#graphModelUpdated() + */ + @Override + public void graphModelUpdated() { + if (!isDisposed() && getDisplay() != null) { + getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + if (!isDisposed()) { + redraw(); + } + } + }); + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener#currentEventUpdated() + */ + @Override + public void currentEventUpdated(long currentEventTime) { + graphModelUpdated(); + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/HistogramViewer.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/HistogramViewer.java new file mode 100644 index 0000000000..96860d3a7f --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/HistogramViewer.java @@ -0,0 +1,157 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Adapted to new model-view-controller design + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency; + +import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramDataModel; +import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramDataModel; +import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramModelListener; +import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.HistogramPaintListener; +import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.TooltipListener; +import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.ZoomListener; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; + +/** + * HistogramViewer + *

    + * + * Histogram viewer. + * + * @author Philippe Sawicki + */ +public class HistogramViewer extends AbstractViewer implements IHistogramModelListener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * Usable width for data plotting. + */ + protected int fUsableWidth; + + /** + * Latency histogram model. + */ + private HistogramDataModel fModel; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param parent The parent composite node. + * @param style The SWT style to use to render the view. + */ + public HistogramViewer(Composite parent, int style) { + super(parent, style); + + // Register the paint listener + fPaintListener = new HistogramPaintListener(this); + addPaintListener(fPaintListener); + + // Register the zoom listener + fZoomListener = new ZoomListener(this); + addListener(SWT.MouseWheel, fZoomListener); + + // Register the mouse click listener + fMouseTraceListener = new TooltipListener(this, (HistogramPaintListener)fPaintListener); + addMouseTrackListener(fMouseTraceListener); + + fModel = new HistogramDataModel(); + fModel.addHistogramListener(this); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#dispose() + */ + @Override + public void dispose() { + fModel.removeHistogramListener(this); + fPaintListener.dispose(); + super.dispose(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#clear() + */ + @Override + public void clear() { + fPaintListener.clear(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#clearBackground() + */ + @Override + public void clearBackground() { + fPaintListener.clear(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#increaseBarWidth() + */ + @Override + public void increaseBarWidth() { + fPaintListener.increaseBarWitdh(); + modelUpdated(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#decreaseBarWidth() + */ + @Override + public void decreaseBarWidth() { + fPaintListener.decreaseBarWitdh(); + modelUpdated(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#getModel() + */ + @Override + public IHistogramDataModel getModel() { + return fModel; + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramModelListener#modelUpdated() + */ + @Override + public void modelUpdated() { + + if (!isDisposed() && getDisplay() != null) { + getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + if (!isDisposed()) { + redraw(); + } + } + }); + } + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/LatencyView.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/LatencyView.java new file mode 100644 index 0000000000..dcb227eb0d --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/LatencyView.java @@ -0,0 +1,477 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Adapted to new model-view-controller design + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.linuxtools.lttng.core.event.LttngEvent; +import org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AddDialog; +import org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.DeleteDialog; +import org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.ListDialog; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyController; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyGraphModel; +import org.eclipse.linuxtools.tmf.core.event.TmfEvent; +import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange; +import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp; +import org.eclipse.linuxtools.tmf.core.experiment.TmfExperiment; +import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest; +import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest.ExecutionType; +import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentDisposedSignal; +import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentRangeUpdatedSignal; +import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentSelectedSignal; +import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal; +import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler; +import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal; +import org.eclipse.linuxtools.tmf.ui.views.TmfView; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.plugin.AbstractUIPlugin; + +/** + * LatencyView + *

    + * TmfView displaying the latency views (i.e. the two latency charts). + * + * @author Philippe Sawicki + */ +public class LatencyView extends TmfView implements IGraphModelListener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + // The initial window span (in nanoseconds) + public static long INITIAL_WINDOW_SPAN = (1L * 100 * 1000 * 1000); // .1sec + + /** + * The view's unique ID. + */ + public static final String ID = "org.eclipse.linuxtools.lttng.ui.views.latency.LatencyView"; //$NON-NLS-1$ + + /** + * A reference to the currently selected experiment. + */ + protected TmfExperiment fExperiment = null; + + /** + * Parent composite. + */ + protected Composite fParent; + + /** + * Graph view. + */ + protected GraphViewer fGraphViewer; + + /** + * Histogram view. + */ + protected HistogramViewer fHistogramViewer; + + /** + * Action executed when the user wants to see the list of matching events. + */ + protected Action fListMatchingEvents; + + /** + * Action executed when the user wants to add matching events. + */ + protected Action fAddMatchingEvents; + + /** + * Action executed when the user wants to delete matching events. + */ + protected Action fDeleteMatchingEvents; + + /** + * Action executed when the user wants to increase the width of the histogram bars. + */ + protected Action fIncreaseBarWidth; + + /** + * Action executed when the user wants to decrease the width of the histogram bars. + */ + protected Action fDecreaseBarWidth; + + /** + * The current histogram window time range. + */ + protected TmfTimeRange fTimeRange = null; + + /** + * Controller of the latency model which is responsible to retrieve data from the trace + */ + final private LatencyController fController; + + /** + * Flag to notify that TimeSyncSignal was received and is being processed. + */ + private boolean fSyncSignalReceived = false; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructor. + */ + public LatencyView() { + super(Messages.LatencyView_ViewName); + fController = LatencyController.getInstance(); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /** + * Create the UI controls of this view. + * + * @param parent + * The composite parent of this view. + */ + @Override + public void createPartControl(Composite parent) { + // Save the parent + fParent = parent; + + makeActions(); + contributeToActionBars(); + + // Add a control listener to handle the view resize events (to redraw the canvas) + fParent.addControlListener(new ControlListener() { + @Override + public void controlMoved(ControlEvent event) { + fHistogramViewer.clearBackground(); + fGraphViewer.clearBackground(); + fController.handleCompleted(); + } + + @Override + public void controlResized(ControlEvent event) { + fHistogramViewer.clearBackground(); + fGraphViewer.clearBackground(); + fController.handleCompleted(); + } + }); + + // /////////////////////////////////////////////////////////////////////////////////// + // Layout for the whole view, other elements will be in a child composite of this one + // Contains : + // Composite layoutSelectionWindow + // Composite layoutTimesSpinner + // Composite layoutExperimentHistogram + // /////////////////////////////////////////////////////////////////////////////////// + Composite layoutFullView = new Composite(fParent, SWT.FILL); + FillLayout gridFullView = new FillLayout(); + gridFullView.marginHeight = 0; + gridFullView.marginWidth = 0; + layoutFullView.setLayout(gridFullView); + + // Create the graph views + fGraphViewer = new GraphViewer(layoutFullView, SWT.DOUBLE_BUFFERED); + fGraphViewer.setDrawLabelEachNTicks(2); + fGraphViewer.setGraphTitle(Messages.LatencyView_Graphs_Graph_Title); + fGraphViewer.setXAxisLabel(Messages.LatencyView_Graphs_Graph_XAxisLabel, 40); + fGraphViewer.setYAxisLabel(Messages.LatencyView_Graphs_Graph_YAxisLabel); + + fHistogramViewer = new HistogramViewer(layoutFullView, SWT.DOUBLE_BUFFERED); + fHistogramViewer.setDrawLabelEachNTicks(2); + fHistogramViewer.setGraphTitle(Messages.LatencyView_Graphs_Histogram_Title); + fHistogramViewer.setXAxisLabel(Messages.LatencyView_Graphs_Histogram_XAxisLabel, 55); + fHistogramViewer.setYAxisLabel(Messages.LatencyView_Graphs_Histogram_YAxisLabel); + + fController.registerModel(fGraphViewer.getModel()); + fController.registerModel(fHistogramViewer.getModel()); + + ((LatencyGraphModel)fGraphViewer.getModel()).addGraphModelListener(this); + + @SuppressWarnings("unchecked") + TmfExperiment experiment = (TmfExperiment) TmfExperiment.getCurrentExperiment(); + if (experiment != null) { + + TmfTimeRange experimentTRange = experiment.getTimeRange(); + + if (experimentTRange != TmfTimeRange.Null) { + TmfExperimentSelectedSignal signal = new TmfExperimentSelectedSignal(this, experiment); + experimentSelected(signal); + } + } + } + + @SuppressWarnings("nls") + @Override + public String toString() { + return "["+ Messages.LatencyView_ViewName+"]"; + } + + // ------------------------------------------------------------------------ + // Signal handlers + // ------------------------------------------------------------------------ + + @SuppressWarnings("unchecked") + @TmfSignalHandler + public void experimentSelected(TmfExperimentSelectedSignal signal) { + // Clear the views + fGraphViewer.clear(); + fHistogramViewer.clear(); + + if (fParent != null) { + // Update the trace reference + fExperiment = (TmfExperiment) signal.getExperiment(); + + fTimeRange = TmfTimeRange.Null; + TmfTimeRange experimentTRange = fExperiment.getTimeRange(); + + if (!experimentTRange.equals(TmfTimeRange.Null)) { + fTimeRange = new TmfTimeRange(experimentTRange.getStartTime(), + new TmfTimestamp(experimentTRange.getStartTime().getValue() + INITIAL_WINDOW_SPAN, experimentTRange.getStartTime().getScale(), experimentTRange.getStartTime().getPrecision())); + fController.refreshModels(fExperiment, fTimeRange); + } + } + } + @TmfSignalHandler + public void experimentRangeUpdated(TmfExperimentRangeUpdatedSignal signal) { + if (fTimeRange == TmfTimeRange.Null && signal.getExperiment().equals(fExperiment)) { + TmfTimeRange experimentTRange = signal.getRange(); + + if (experimentTRange != TmfTimeRange.Null) { + fTimeRange = new TmfTimeRange(experimentTRange.getStartTime(), + new TmfTimestamp(experimentTRange.getStartTime().getValue() + INITIAL_WINDOW_SPAN, experimentTRange.getStartTime().getScale(), experimentTRange.getStartTime().getPrecision())); + fController.refreshModels(fExperiment, fTimeRange); + } + } + } + + @TmfSignalHandler + public void experimentDisposed(TmfExperimentDisposedSignal signal) { + fTimeRange = TmfTimeRange.Null; + fExperiment = null; + fController.clear(); + } + + /** + * Called when the LatencyView is closed: disposes of the canvas and unregisters models from views. + */ + @Override + public void dispose() { + fController.dispose(); + fController.deregisterModel(fGraphViewer.getModel()); + fController.deregisterModel(fHistogramViewer.getModel()); + ((LatencyGraphModel)fGraphViewer.getModel()).removeGraphModelListener(this); + + fGraphViewer.dispose(); + fHistogramViewer.dispose(); + + super.dispose(); + } + + /** + * Method called when synchronization is active and that the user select an event. + * + * The models will be updated with the new current selected time. + * + * @param signal + * Signal received from the framework. Contain the event. + */ + @TmfSignalHandler + public void currentTimeUpdated(TmfTimeSynchSignal signal) { + if (signal.getSource() != this) { + fSyncSignalReceived = true; + fController.setCurrentEventTime(signal.getCurrentTime().getValue()); + fSyncSignalReceived = false; + } + } + + /** + * Method called when synchronization is active and that the user changed the current time range. + + * The models will be updated with the new time range. + * + * @param signal + * Signal received from the framework. Contain the new time range. + */ + @TmfSignalHandler + public void synchToTimeRange(TmfRangeSynchSignal signal) { + if (signal.getSource() != this) { + // Erase the graph views + fGraphViewer.clear(); + fHistogramViewer.clear(); + + TmfTimestamp startTime = signal.getCurrentRange().getStartTime(); + TmfTimestamp endTime = signal.getCurrentRange().getEndTime(); + fTimeRange = new TmfTimeRange(startTime, endTime); + + fController.refreshModels(fExperiment, fTimeRange); + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener#graphModelUpdated() + */ + @Override + public void graphModelUpdated() { + // Nothing to do - update of viewers will be done in the viewers + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener#currentEventUpdated(long) + */ + @Override + public void currentEventUpdated(final long currentEventTime) { + if (fExperiment != null && + !fSyncSignalReceived && // Don't broadcast the current time that was received just before with a time sync signal + currentEventTime != Config.INVALID_EVENT_TIME) { + + // Queue update in the event request queue + TmfTimeRange timeRange = new TmfTimeRange(new TmfTimestamp(currentEventTime, Config.TIME_SCALE), TmfTimestamp.BigCrunch); + TmfEventRequest request = new TmfEventRequest(LttngEvent.class, timeRange, 0, 1, ExecutionType.FOREGROUND) { + @Override + public void handleCompleted() { + broadcast(new TmfTimeSynchSignal(this, new TmfTimestamp(currentEventTime, Config.TIME_SCALE))); + } + }; + fExperiment.sendRequest(request); + } + } + + // ------------------------------------------------------------------------ + // Helper functions + // ------------------------------------------------------------------------ + + /** + * Fills the local pull down menu. + * @param manager + * The menu manager. + */ + private void fillLocalPullDown(IMenuManager manager) { + manager.add(new Separator()); + manager.add(fIncreaseBarWidth); + manager.add(fDecreaseBarWidth); + manager.add(new Separator()); + manager.add(fListMatchingEvents); + manager.add(fAddMatchingEvents); + manager.add(fDeleteMatchingEvents); + manager.add(new Separator()); + } + + /** + * Fills the local toolbar. + * @param manager + * The toolbar manager + */ + private void fillLocalToolBar(IToolBarManager manager) { + manager.add(new Separator()); + manager.add(fIncreaseBarWidth); + manager.add(fDecreaseBarWidth); + manager.add(new Separator()); + manager.add(fListMatchingEvents); + manager.add(fAddMatchingEvents); + manager.add(fDeleteMatchingEvents); + manager.add(new Separator()); + } + + /** + * Creates the actions required by the dialog events. + */ + private void makeActions() { + // Increase the histogram bar width + fIncreaseBarWidth = new Action() { + @Override + public void run() { + fHistogramViewer.increaseBarWidth(); + fGraphViewer.increaseBarWidth(); + } + }; + String tooltipText = Messages.LatencyView_Action_IncreaseBarWidth_Tooltip; + fIncreaseBarWidth.setText(tooltipText); + fIncreaseBarWidth.setToolTipText(tooltipText); + fIncreaseBarWidth.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/increasebar_button.gif")); //$NON-NLS-1$ + + // Decrease the histogram bar width + fDecreaseBarWidth = new Action() { + @Override + public void run() { + fHistogramViewer.decreaseBarWidth(); + fGraphViewer.decreaseBarWidth(); + } + }; + tooltipText = Messages.LatencyView_Action_DecreaseBarWidth_Tooltip; + fDecreaseBarWidth.setText(tooltipText); + fDecreaseBarWidth.setToolTipText(tooltipText); + fDecreaseBarWidth.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/decreasebar_button.gif")); //$NON-NLS-1$ + + // List matching events dialog + fListMatchingEvents = new Action() { + @Override + public void run() { + ListDialog listDialog = new ListDialog(fParent.getShell(), Messages.LatencyView_Dialogs_ListEvents_Title, Messages.LatencyView_Dialogs_ListEvents_Message); + listDialog.create(); + listDialog.open(); + } + }; + tooltipText = Messages.LatencyView_Action_ListEvents_Tooltip; + fListMatchingEvents.setText(tooltipText); + fListMatchingEvents.setToolTipText(tooltipText); + fListMatchingEvents.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/eview16/events_view.gif")); //$NON-NLS-1$ + + // Add matching events dialog + fAddMatchingEvents = new Action() { + @Override + public void run() { + AddDialog addDialog = new AddDialog(fParent.getShell(), Messages.LatencyView_Dialogs_AddEvents_Title, Messages.LatencyView_Dialogs_AddEvents_Message); + addDialog.create(); + addDialog.open(); + } + }; + tooltipText = Messages.LatencyView_Action_AddEvents_Tooltip; + fAddMatchingEvents.setText(tooltipText); + fAddMatchingEvents.setToolTipText(tooltipText); + fAddMatchingEvents.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/add_button.gif")); //$NON-NLS-1$ + + // Remove matching events dialog + fDeleteMatchingEvents = new Action() { + @Override + public void run() { + DeleteDialog deleteDialog = new DeleteDialog(fParent.getShell(), Messages.LatencyView_Dialogs_DeleteEvents_Title, + Messages.LatencyView_Dialogs_DeleteEvents_Message); + deleteDialog.create(); + deleteDialog.open(); + } + }; + tooltipText = Messages.LatencyView_Action_DeleteEvents_Tooltip; + fDeleteMatchingEvents.setText(tooltipText); + fDeleteMatchingEvents.setToolTipText(tooltipText); + fDeleteMatchingEvents.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/delete_button.gif")); //$NON-NLS-1$ + } + + /** + * Build the toolbar and menu by adding action buttons for dialogs. + */ + private void contributeToActionBars() { + IActionBars bars = getViewSite().getActionBars(); + fillLocalPullDown(bars.getMenuManager()); + fillLocalToolBar(bars.getToolBarManager()); + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/Messages.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/Messages.java new file mode 100644 index 0000000000..85cffa9179 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/Messages.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Updated + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency; + +import org.eclipse.osgi.util.NLS; + +/** + * Returns localized strings from the resource bundle (i.e. "messages.properties"). + * + * @author Philippe Sawicki + */ +public class Messages { + + public static String LatencyView_ViewName; + public static String LatencyView_Action_IncreaseBarWidth_Tooltip; + public static String LatencyView_Action_DecreaseBarWidth_Tooltip; + public static String LatencyView_Action_AddEvents_Tooltip; + public static String LatencyView_Action_DeleteEvents_Tooltip; + public static String LatencyView_Action_ListEvents_Tooltip; + public static String LatencyView_Dialogs_AddEvents_Title; + public static String LatencyView_Dialogs_AddEvents_Message; + public static String LatencyView_Dialogs_AddEvents_Buttons_Add; + public static String LatencyView_Dialogs_AddEvents_Buttons_Close; + public static String LatencyView_Dialogs_AddEvents_Columns_Start; + public static String LatencyView_Dialogs_AddEvents_Columns_End; + public static String LatencyView_Dialogs_AddEvents_Columns_List_Trigger; + public static String LatencyView_Dialogs_AddEvents_Columns_List_End; + public static String LatencyView_Dialogs_AddEvents_Errors_NoSelection; + public static String LatencyView_Dialogs_AddEvents_Errors_StartNotSelected; + public static String LatencyView_Dialogs_AddEvents_Errors_EndNotSelected; + public static String LatencyView_Dialogs_AddEvents_Errors_SameSelected; + public static String LatencyView_Dialogs_AddEvents_Errors_AlreadyMatched; + public static String LatencyView_Dialogs_AddEvents_Errors_StartAlreadyMatched; + public static String LatencyView_Dialogs_AddEvents_Errors_EndAlreadyMatched; + public static String LatencyView_Dialogs_AddEvents_Errors_StartAsEnd; + public static String LatencyView_Dialogs_AddEvents_Errors_EndAsStart; + public static String LatencyView_Dialogs_DeleteEvents_Title; + public static String LatencyView_Dialogs_DeleteEvents_Message; + public static String LatencyView_Dialogs_DeleteEvents_Buttons_Close; + public static String LatencyView_Dialogs_DeleteEvents_Buttons_Delete; + public static String LatencyView_Dialogs_DeleteEvents_Confirm_Title; + public static String LatencyView_Dialogs_DeleteEvents_Confirm_Message; + public static String LatencyView_Dialogs_ListEvents_Title; + public static String LatencyView_Dialogs_ListEvents_Message; + public static String LatencyView_Dialogs_ListEvents_Buttons_Close; + public static String LatencyView_Dialogs_ListEvents_Buttons_Reset; + public static String LatencyView_Dialogs_ListEvents_Columns_Trigger; + public static String LatencyView_Dialogs_ListEvents_Columns_End; + public static String LatencyView_Dialogs_ListEvents_Confirm_Title; + public static String LatencyView_Dialogs_ListEvents_Confirm_Message; + public static String LatencyView_Graphs_Graph_Title; + public static String LatencyView_Graphs_Graph_XAxisLabel; + public static String LatencyView_Graphs_Graph_YAxisLabel; + public static String LatencyView_Graphs_Histogram_Title; + public static String LatencyView_Graphs_Histogram_XAxisLabel; + public static String LatencyView_Graphs_Histogram_YAxisLabel; + public static String LatencyView_msgSlogan; + public static String LatencyView_tmf_UI; + public static String LatencyView_ClippingWarning; + + + /** + * Bundle name. + */ + private static final String BUNDLE_NAME = "org.eclipse.linuxtools.lttng.ui.views.latency.messages"; //$NON-NLS-1$ + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/AbstractDialog.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/AbstractDialog.java new file mode 100644 index 0000000000..2551eae068 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/AbstractDialog.java @@ -0,0 +1,240 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Adapted to new messages file, fixed warnings + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.dialogs; + +import java.util.Vector; + +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher; +import org.eclipse.linuxtools.lttng.core.util.EventsPair; +import org.eclipse.linuxtools.lttng.ui.LTTngUiPlugin; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyController; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; + +/** + * AbstractDialog + *

    + * Includes the main functions shared by all the different dialogs. + * + * @author Philippe Sawicki + */ +public abstract class AbstractDialog extends TitleAreaDialog { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * The dialog window title. + */ + protected String fDialogTitle; + /** + * The dialog window message. + */ + protected String fDialogMessage; + + /** + * The code returned by the dialog when the user closes the "Add" dialog. + */ + public static final int ADD = 53445; + /** + * The code returned by the dialog when the user closes the "Delete" dialog. + */ + public static final int DELETE = ADD + 1; + /** + * The code returned by the dialog when the user resets the latency pair to default. + */ + public static final int RESET = DELETE + 1; + + /** + * String ID of the number of pairs saved in the settings file. + */ + protected static final String LATENCY_NB_MATCH_PAIRS = "NB_LATENCY_MATCH_PAIRS"; //$NON-NLS-1$ + /** + * String ID of the start event pairs saved in the settings file. + */ + protected static final String LATENCY_PAIRS_START = "LATENCY_PAIRS_START"; //$NON-NLS-1$ + /** + * String ID of the end event pairs saved in the settings file. + */ + protected static final String LATENCY_PAIRS_END = "LATENCY_PAIRS_END"; //$NON-NLS-1$ + + /** + * Dialog settings, saves the event pairs across sessions. + */ + protected IDialogSettings fSettings; + + /** + * Do the graphs canvas need to be redrawn due to latency pairs changes ? + */ + protected boolean fRedrawGraphs = false; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param parentShell + * The parent shell. + * @param title + * The dialog window's title. + * @param message + * The dialog window's message. + */ + public AbstractDialog(Shell parentShell, String title, String message) { + super(parentShell); + fDialogTitle = title; + fDialogMessage = message; + + fSettings = LTTngUiPlugin.getDefault().getDialogSettings(); + } + + /** + * Constructor + * @param parentShell + * The parent shell. + * @param title + * The dialog window's title. + */ + @SuppressWarnings("nls") + public AbstractDialog(Shell parentShell, String title) { + this(parentShell, title, ""); + } + + /** + * Constructor. + * @param parentShell + * The parent shell. + */ + @SuppressWarnings("nls") + public AbstractDialog(Shell parentShell) { + this(parentShell, "", ""); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /** + * Creates the dialog. + * + * Note : Since there is an issue with the table's vertical scroll bar, this dialog "resize" is necessary to + * ensure a minimal height for the window. + */ + @Override + public void create() { + super.create(); + // Set the title + setTitle(fDialogTitle); + // Set the message + setMessage(fDialogMessage, IMessageProvider.INFORMATION); + + // Position the dialog at the center of the screen + int windowWidth = Display.getCurrent().getPrimaryMonitor().getBounds().width; + int windowHeight = Display.getCurrent().getPrimaryMonitor().getBounds().height; + int dialogWidth = getShell().getSize().x; + int dialogHeight = windowHeight / 2; + + int x = (windowWidth - dialogWidth) / 2; + int y = (windowHeight - dialogHeight) / 2; + + getShell().setSize(getShell().getSize().x, dialogHeight); + getShell().setLocation(x, y); + } + + /** + * Formats the "#" of the event in the table by adding "00" before it. + * @param number + * The number to format. + * @param max + * The maximum number of event pairs in the list. + * @return The formatted string. + */ + @SuppressWarnings("nls") + protected String formatListNumber(int number, int max) { + return String.format("%0" + max + "d", number); + } + + /** + * Returns the match pairs saved in the settings file. + * @return The match pairs saved in the settings file. + */ + protected EventsPair getMatchPairs() { + try { + // Check if the settings file has already some data (i.e. try provoking an exception) + fSettings.getInt(LATENCY_NB_MATCH_PAIRS); + + String[] starts = fSettings.getArray(LATENCY_PAIRS_START); + String[] ends = fSettings.getArray(LATENCY_PAIRS_END); + + EventMatcher.getInstance().resetMatches(); + for (int i = 0; i < starts.length; i++) { + EventMatcher.getInstance().addMatch(starts[i], ends[i]); + } + + return EventMatcher.getInstance().getEvents(); + } catch (NumberFormatException e) { + return EventMatcher.getInstance().getEvents(); + } + } + + /** + * Saves the event match pairs to a settings file. + * @param start + * The start event types. + * @param end + * The end event types. + */ + protected void saveMatchPairs(Vector start, Vector end) { + fSettings.put(LATENCY_NB_MATCH_PAIRS, start.size()); + fSettings.put(LATENCY_PAIRS_START, start.toArray(new String[] {})); + fSettings.put(LATENCY_PAIRS_END, end.toArray(new String[] {})); + } + + /** + * Ask the LatencyView to send a new analysis request to the views, so that they can be redrawn. + */ + protected void redrawGraphs() { + LatencyController.getInstance().refreshModels(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite) + */ + @Override + protected abstract Control createDialogArea(Composite parent); + + /* + * (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) + */ + @Override + protected abstract void createButtonsForButtonBar(Composite parent); + + /* + * (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#isResizable() + */ + @Override + protected boolean isResizable() { + return true; + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/AddDialog.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/AddDialog.java new file mode 100644 index 0000000000..aee1ef9e44 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/AddDialog.java @@ -0,0 +1,488 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Adapted to new messages file, fixed warnings + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.dialogs; + +import java.util.Vector; + +import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher; +import org.eclipse.linuxtools.lttng.core.util.EventsPair; +import org.eclipse.linuxtools.lttng.ui.views.latency.Messages; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; + +/** + * AddDialog + *

    + * Add dialog, lets the user add custom start/end event pairs. + * + * @author Philippe Sawicki + */ +public class AddDialog extends AbstractDialog { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * The dialog's start table. + */ + protected Table fStartTable; + + /** + * The dialog's end table. + */ + protected Table fEndTable; + + /** + * The dialog's list table. + */ + protected Table fListTable; + + /** + * Start table columns. + */ + protected TableColumn[] fStartColumns; + + /** + * End table columns. + */ + protected TableColumn[] fEndColumns; + + /** + * List table columns. + */ + protected TableColumn[] fListColumns; + + /** + * Start table column names (header titles). + */ + protected static final String[] START_COLUMN_NAMES = { "", Messages.LatencyView_Dialogs_AddEvents_Columns_Start }; //$NON-NLS-1$ + + /** + * End table column names (header titles). + */ + protected static final String[] END_COLUMN_NAMES = { "", Messages.LatencyView_Dialogs_AddEvents_Columns_End }; //$NON-NLS-1$ + + /** + * List table column names (header titles). + */ + protected static final String[] LIST_COLUMN_NAMES = { + "#", //$NON-NLS-1$ + Messages.LatencyView_Dialogs_AddEvents_Columns_List_Trigger, + Messages.LatencyView_Dialogs_AddEvents_Columns_List_End }; + + /** + * Column widths. + */ + protected static final int[] COLUMN_WIDTHS = { 25, 250, 250 }; + + /** + * Possible event types. + */ + protected Vector fEventTypes = new Vector(); + + /** + * Start event types. + */ + protected Vector fEventStartTypes; + + /** + * End event types. + */ + protected Vector fEventEndTypes; + + /** + * Selected start type. + */ + protected String fStartType; + + /** + * Selected end type. + */ + protected String fEndType; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param parentShell + * The parent shell. + * @param title + * The dialog's window title. + * @param message + * The dialog's window message. + */ + public AddDialog(Shell parentShell, String title, String message) { + super(parentShell, title, message); + + // Get the possible events from the list + fEventTypes = EventMatcher.getInstance().getTypeList(); + + // Get the list of start and end types from the EventMatcher + EventsPair pair = getMatchPairs(); + fEventStartTypes = pair.getFirst(); + fEventEndTypes = pair.getSecond(); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /** + * Creates the start table's columns (i.e. the table header). + */ + protected void createStartColumns() { + fStartColumns = new TableColumn[START_COLUMN_NAMES.length]; + for (int i = 0; i < START_COLUMN_NAMES.length; i++) { + fStartColumns[i] = new TableColumn(fStartTable, SWT.LEFT); + fStartColumns[i].setText(START_COLUMN_NAMES[i]); + fStartColumns[i].setWidth(COLUMN_WIDTHS[i]); + } + } + + /** + * Creates the end table's columns (i.e. the table header). + */ + protected void createEndColumns() { + fEndColumns = new TableColumn[END_COLUMN_NAMES.length]; + for (int i = 0; i < END_COLUMN_NAMES.length; i++) { + fEndColumns[i] = new TableColumn(fEndTable, SWT.LEFT); + fEndColumns[i].setText(END_COLUMN_NAMES[i]); + fEndColumns[i].setWidth(COLUMN_WIDTHS[i]); + } + } + + /** + * Creates the list table's columns (i.e. the table header). + */ + protected void createListColumns() { + fListColumns = new TableColumn[LIST_COLUMN_NAMES.length]; + for (int i = 0; i < LIST_COLUMN_NAMES.length; i++) { + fListColumns[i] = new TableColumn(fListTable, SWT.LEFT); + fListColumns[i].setText(LIST_COLUMN_NAMES[i]); + fListColumns[i].setWidth(COLUMN_WIDTHS[i]); + } + } + + /** + * Creates the start column list. + * @param parent + * The parent composite. + */ + protected void createStartColumn(Composite parent) { + final int style = SWT.SINGLE | SWT.CHECK | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL; + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + fStartTable = new Table(parent, style); + fStartTable.setLayoutData(layoutData); + + // Some cosmetic enhancements + fStartTable.setHeaderVisible(true); + fStartTable.setLinesVisible(true); + + createStartColumns(); + + for (int i = 0; i < fEventTypes.size(); i++) { + TableItem item = new TableItem(fStartTable, SWT.RIGHT); + + String[] columns = { fEventTypes.get(i), fEventTypes.get(i) }; + + item.setText(columns); + } + + fStartTable.setItemCount(fEventTypes.size()); + + fStartTable.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + if (event.detail == SWT.CHECK) { + TableItem[] items = fStartTable.getItems(); + for (TableItem item : items) { + if (item != event.item) { + item.setChecked(false); + } + } + } + } + }); + } + + /** + * Creates the end column list. + * @param parent + * The parent composite. + */ + protected void createEndColumn(Composite parent) { + final int style = SWT.SINGLE | SWT.CHECK | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL; + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + fEndTable = new Table(parent, style); + fEndTable.setLayoutData(layoutData); + + // Some cosmetic enhancements + fEndTable.setHeaderVisible(true); + fEndTable.setLinesVisible(true); + + createEndColumns(); + + for (int i = 0; i < fEventTypes.size(); i++) { + TableItem item = new TableItem(fEndTable, SWT.RIGHT); + + String[] columns = { fEventTypes.get(i), fEventTypes.get(i) }; + + item.setText(columns); + } + + fEndTable.setItemCount(fEventTypes.size()); + + fEndTable.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + if (event.detail == SWT.CHECK) { + TableItem[] items = fEndTable.getItems(); + for (TableItem item : items) { + if (item != event.item) { + item.setChecked(false); + } + } + } + } + }); + } + + /** + * Creates the list column for already existing event pairs. + * @param parent + * The parent composite. + */ + protected void createListColumn(Composite parent) { + final int style = SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL; + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + layoutData.horizontalSpan = 2; + fListTable = new Table(parent, style); + fListTable.setLayoutData(layoutData); + + // Some cosmetic enhancements + fListTable.setHeaderVisible(true); + fListTable.setLinesVisible(true); + + createListColumns(); + + for (int i = 0; i < fEventStartTypes.size(); i++) { + TableItem item = new TableItem(fListTable, SWT.RIGHT); + + String max = String.valueOf(fEventStartTypes.size()); + String number = formatListNumber(i + 1, max.length()); + + String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) }; + + item.setText(columns); + } + + fListTable.setItemCount(103); + fListTable.remove(fEventTypes.size(), 103 - 1); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AbstractDialog#createDialogArea(org.eclipse.swt.widgets.Composite) + */ + @Override + protected Control createDialogArea(Composite parent) { + GridLayout layout = new GridLayout(2, true); + parent.setLayout(layout); + + createStartColumn(parent); + createEndColumn(parent); + createListColumn(parent); + + return parent; + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AbstractDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) + */ + @Override + protected void createButtonsForButtonBar(Composite parent) { + GridData gridData = new GridData(); + gridData.verticalAlignment = GridData.FILL; + gridData.horizontalSpan = 1; + gridData.grabExcessHorizontalSpace = true; + gridData.grabExcessVerticalSpace = true; + gridData.horizontalAlignment = SWT.RIGHT; + + parent.setLayoutData(gridData); + + // Create the "Add" button + Button addButton = createButton(parent, ADD, Messages.LatencyView_Dialogs_AddEvents_Buttons_Add, false); + addButton.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + if (isValidInput()) { + // Add the event pair to the EventMatcher and save the pairs + EventMatcher.getInstance().addMatch(fStartType, fEndType); + fEventStartTypes.add(fStartType); + fEventEndTypes.add(fEndType); + saveMatchPairs(fEventStartTypes, fEventEndTypes); + + EventsPair pairs = EventMatcher.getInstance().getEvents(); + fEventStartTypes = pairs.getFirst(); + fEventEndTypes = pairs.getSecond(); + + fListTable.removeAll(); + + for (int i = 0; i < fEventStartTypes.size(); i++) { + TableItem item = new TableItem(fListTable, SWT.RIGHT); + + String max = String.valueOf(fEventStartTypes.size()); + String number = formatListNumber(i + 1, max.length()); + + String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) }; + + item.setText(columns); + } + + saveMatchPairs(fEventStartTypes, fEventEndTypes); + } + + fRedrawGraphs = true; + } + }); + + // Create the "Close" button + Button closeButton = createButton(parent, CANCEL, Messages.LatencyView_Dialogs_AddEvents_Buttons_Close, false); + closeButton.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + setReturnCode(CANCEL); + + if (fRedrawGraphs == true) + redrawGraphs(); + + close(); + } + }); + } + + /** + * Validate the list before adding event pairs. + * @return "true" if the input is valid, "false" otherwise. + */ + protected boolean isValidInput() { + // Remove the previous error message + setErrorMessage(null); + + boolean valid = true; + + // Check if an item from the start list is selected + TableItem[] items = fStartTable.getItems(); + fStartType = null; + boolean startHasSelectedItem = false; + for (int i = 0; i < items.length && !startHasSelectedItem; i++) { + if (items[i].getChecked() == true) { + fStartType = items[i].getText(); + startHasSelectedItem = true; + } + } + + // Check if an item from the end list is selected + items = fEndTable.getItems(); + fEndType = null; + boolean endHasSelectedItem = false; + for (int i = 0; i < items.length && !endHasSelectedItem; i++) { + if (items[i].getChecked() == true) { + fEndType = items[i].getText(); + endHasSelectedItem = true; + } + } + + // Print error message if needed. + if (!startHasSelectedItem && !endHasSelectedItem) { + setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_NoSelection); + valid = false; + } else if (!startHasSelectedItem) { + setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_StartNotSelected); + valid = false; + } else if (!endHasSelectedItem) { + setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_EndNotSelected); + valid = false; + } + + // Check if the same item is selected in both lists + if (startHasSelectedItem && endHasSelectedItem) { + if (fStartType.equalsIgnoreCase(fEndType)) { + setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_SameSelected); + valid = false; + } + } + + // Check if the selected item is already in the list + if (startHasSelectedItem && endHasSelectedItem) { + EventsPair pairs = getMatchPairs(); + Vector startEvents = pairs.getFirst(); + Vector endEvents = pairs.getSecond(); + + boolean startAlreadyUsed = false; + boolean endAlreadyUsed = false; + boolean startAsEndAlreadyUsed = false; + boolean endAsStartAlreadyUsed = false; + + if (startEvents.contains(fStartType)) { + startAlreadyUsed = true; + } + if (endEvents.contains(fEndType)) { + endAlreadyUsed = true; + } + if (startEvents.contains(fEndType)) { + endAsStartAlreadyUsed = true; + } + if (endEvents.contains(fStartType)) { + startAsEndAlreadyUsed = true; + } + + if (startAlreadyUsed && endAlreadyUsed) { + setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_AlreadyMatched); + valid = false; + } else if (startAlreadyUsed) { + setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_StartAlreadyMatched); + valid = false; + } else if (endAlreadyUsed) { + setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_EndAlreadyMatched); + valid = false; + } + + if (startAsEndAlreadyUsed) { + setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_StartAsEnd); + valid = false; + } + if (endAsStartAlreadyUsed) { + setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_EndAsStart); + valid = false; + } + } + + return valid; + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/DeleteDialog.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/DeleteDialog.java new file mode 100644 index 0000000000..c975688aa8 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/DeleteDialog.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Adapted to new messages file, fixed warnings + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.dialogs; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher; +import org.eclipse.linuxtools.lttng.ui.views.latency.Messages; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TableItem; + +/** + * DeleteDialog + *

    + * Remove dialog, lets the user remove start/end event pairs. + * + * @author Philippe Sawicki + */ +public class DeleteDialog extends ListDialog { + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param parentShell + * The parent shell. + * @param title + * The dialog's window title. + * @param message + * The dialog's window message. + */ + public DeleteDialog(Shell parentShell, String title, String message) { + super(parentShell, title, message); + + // Set the table style + fStyle = SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.ListDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) + */ + @Override + protected void createButtonsForButtonBar(Composite parent) { + GridData gridData = new GridData(); + gridData.verticalAlignment = GridData.FILL; + gridData.horizontalSpan = 1; + gridData.grabExcessHorizontalSpace = true; + gridData.grabExcessVerticalSpace = true; + gridData.horizontalAlignment = SWT.RIGHT; + + parent.setLayoutData(gridData); + + // Create the "Delete" button + Button deleteButton = createButton(parent, DELETE, Messages.LatencyView_Dialogs_DeleteEvents_Buttons_Delete, false); + deleteButton.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + TableItem selectedItem = fTable.getSelection()[0]; + if (selectedItem == null) + return; + + int[] selectedIndices = fTable.getSelectionIndices(); + + String deletePairs = ""; //$NON-NLS-1$ + for (int i = 0; i < selectedIndices.length; i++) { + int index = selectedIndices[i]; + deletePairs += "\t* " + fEventStartTypes.get(index) + " / " + fEventEndTypes.get(index); //$NON-NLS-1$ //$NON-NLS-2$ + + if (i < selectedIndices.length - 1) { + deletePairs += "\n"; //$NON-NLS-1$ + } + } + + boolean confirmDeletion = MessageDialog.openQuestion(getShell(), Messages.LatencyView_Dialogs_DeleteEvents_Confirm_Title, + Messages.LatencyView_Dialogs_DeleteEvents_Confirm_Message + "\n\n" + deletePairs); //$NON-NLS-1$ + + if (confirmDeletion) { + // Remove the events starting from the end of the list, otherwise the TableItem elements will lose + // their index from the table and may trigger an exception when removing an index that is no longer + // valid. + for (int i = selectedIndices.length - 1; i >= 0; i--) { + int selectedIndex = selectedIndices[i]; + EventMatcher.getInstance().removeMatch(fEventStartTypes.get(selectedIndex), fEventEndTypes.get(selectedIndex)); + + fTable.remove(selectedIndex); + + // Update the list of events + fEventStartTypes.remove(selectedIndex); + fEventEndTypes.remove(selectedIndex); + } + + // Save the events pairs in the settings file so it can be retrieved in the next session + saveMatchPairs(fEventStartTypes, fEventEndTypes); + + fTable.setItemCount(fEventStartTypes.size()); + + TableItem[] newItems = fTable.getItems(); + fTable.removeAll(); + for (int i = 0; i < newItems.length; i++) { + TableItem item = new TableItem(fTable, SWT.RIGHT); + + String max = String.valueOf(fEventStartTypes.size()); + String number = formatListNumber(i + 1, max.length()); + + String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) }; + + item.setText(columns); + } + + fRedrawGraphs = true; + } + } + }); + + // Create the "Close" button + Button closeButton = createButton(parent, CANCEL, Messages.LatencyView_Dialogs_AddEvents_Buttons_Close, false); + closeButton.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + // Remember the user's list + saveMatchPairs(fEventStartTypes, fEventEndTypes); + + setReturnCode(CANCEL); + + if (fRedrawGraphs == true) + redrawGraphs(); + + close(); + } + }); + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/ListDialog.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/ListDialog.java new file mode 100644 index 0000000000..fd993525a0 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/ListDialog.java @@ -0,0 +1,252 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Adapted to new messages file, fixed warnings + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.dialogs; + +import java.util.Vector; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher; +import org.eclipse.linuxtools.lttng.core.util.EventsPair; +import org.eclipse.linuxtools.lttng.ui.views.latency.Messages; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; + +/** + * ListDialog + *

    + * List dialog, shows the list of start/end event pairs. + * + * @author Philippe Sawicki + */ +public class ListDialog extends AbstractDialog { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * The dialog's table. + */ + protected Table fTable; + + /** + * Start event types. + */ + protected Vector fEventStartTypes; + + /** + * End event types. + */ + protected Vector fEventEndTypes; + + /** + * Table columns + */ + protected TableColumn[] fColumns; + + /** + * Column names (header titles). + */ + protected static final String[] COLUMN_NAMES = { "#", Messages.LatencyView_Dialogs_ListEvents_Columns_Trigger, Messages.LatencyView_Dialogs_ListEvents_Columns_End }; //$NON-NLS-1$ + + /** + * Column widths. + */ + protected static final int[] COLUMN_WIDTHS = { 25, 250, 250 }; + + /** + * The table style. + */ + protected int fStyle; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param parentShell + * The parent shell. + * @param title + * The dialog's window title. + * @param message + * The dialog's window message. + */ + public ListDialog(Shell parentShell, String title, String message) { + super(parentShell, title, message); + + // Set the table style + fStyle = SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL; + + // Get the list of start and end types from the EventMatcher + EventsPair pair = getMatchPairs(); + fEventStartTypes = pair.getFirst(); + fEventEndTypes = pair.getSecond(); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /** + * Creates the table's column (i.e. the table header). + */ + protected void createColumns() { + fColumns = new TableColumn[COLUMN_NAMES.length]; + for (int i = 0; i < COLUMN_NAMES.length; i++) { + fColumns[i] = new TableColumn(fTable, SWT.LEFT); + fColumns[i].setText(COLUMN_NAMES[i]); + fColumns[i].setWidth(COLUMN_WIDTHS[i]); + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AbstractDialog#createDialogArea(org.eclipse.swt.widgets.Composite) + */ + @Override + protected Control createDialogArea(Composite parent) { + GridLayout layout = new GridLayout(1, true); + parent.setLayout(layout); + + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + fTable = new Table(parent, fStyle); + fTable.setLayoutData(layoutData); + + // Some cosmetic enhancements + fTable.setHeaderVisible(true); + fTable.setLinesVisible(true); + + createColumns(); + + for (int i = 0; i < fEventStartTypes.size(); i++) { + TableItem item = new TableItem(fTable, SWT.RIGHT); + + String max = String.valueOf(fEventStartTypes.size()); + String number = formatListNumber(i + 1, max.length()); + + String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) }; + + item.setText(columns); + } + + return parent; + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AbstractDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) + */ + @Override + protected void createButtonsForButtonBar(Composite parent) { + GridData gridData = new GridData(); + gridData.verticalAlignment = GridData.FILL; + gridData.horizontalSpan = 1; + gridData.grabExcessHorizontalSpace = true; + gridData.grabExcessVerticalSpace = true; + gridData.horizontalAlignment = SWT.RIGHT; + + parent.setLayoutData(gridData); + + // Create the "Reset" button + Button resetButton = createButton(parent, RESET, Messages.LatencyView_Dialogs_ListEvents_Buttons_Reset, false); + resetButton.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + boolean confirmDeletion = MessageDialog.openQuestion(getShell(), Messages.LatencyView_Dialogs_ListEvents_Confirm_Title, + Messages.LatencyView_Dialogs_ListEvents_Confirm_Message); + + if (confirmDeletion) { + EventMatcher.getInstance().resetMatches(); + + fTable.removeAll(); + + Vector defaultStarts = new Vector(); + Vector defaultEnds = new Vector(); + + defaultStarts.add(EventMatcher.PAGE_FAULT_GET_USER_ENTRY); + defaultEnds.add(EventMatcher.PAGE_FAULT_GET_USER_EXIT); + defaultStarts.add(EventMatcher.TASKLET_LOW_ENTRY); + defaultEnds.add(EventMatcher.TASKLET_LOW_EXIT); + defaultStarts.add(EventMatcher.PAGE_FAULT_ENTRY); + defaultEnds.add(EventMatcher.PAGE_FAULT_EXIT); + defaultStarts.add(EventMatcher.SYSCALL_ENTRY); + defaultEnds.add(EventMatcher.SYSCALL_EXIT); + defaultStarts.add(EventMatcher.IRQ_ENTRY); + defaultEnds.add(EventMatcher.IRQ_EXIT); + defaultStarts.add(EventMatcher.READ); + defaultEnds.add(EventMatcher.WRITE); + defaultStarts.add(EventMatcher.OPEN); + defaultEnds.add(EventMatcher.CLOSE); + defaultStarts.add(EventMatcher.BUFFER_WAIT_START); + defaultEnds.add(EventMatcher.BUFFER_WAIT_END); + defaultStarts.add(EventMatcher.START_COMMIT); + defaultEnds.add(EventMatcher.END_COMMIT); + defaultStarts.add(EventMatcher.WAIT_ON_PAGE_START); + defaultEnds.add(EventMatcher.WAIT_ON_PAGE_END); + + saveMatchPairs(defaultStarts, defaultEnds); + + for (int i = 0; i < defaultStarts.size(); i++) { + EventMatcher.getInstance().addMatch(defaultStarts.get(i), defaultEnds.get(i)); + } + + // Get the list of start and end types from the EventMatcher + EventsPair pair = getMatchPairs(); + fEventStartTypes = pair.getFirst(); + fEventEndTypes = pair.getSecond(); + + for (int i = 0; i < fEventStartTypes.size(); i++) { + TableItem item = new TableItem(fTable, SWT.RIGHT); + + String max = String.valueOf(fEventStartTypes.size()); + String number = formatListNumber(i + 1, max.length()); + + String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) }; + + item.setText(columns); + } + + fTable.setItemCount(fEventStartTypes.size()); + + fRedrawGraphs = true; + } + } + }); + + // Create the "Close" button + Button closeButton = createButton(parent, CANCEL, Messages.LatencyView_Dialogs_ListEvents_Buttons_Close, false); + closeButton.addListener(SWT.Selection, new Listener() { + @Override + public void handleEvent(Event event) { + setReturnCode(CANCEL); + + if (fRedrawGraphs == true) + redrawGraphs(); + + close(); + } + }); + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractMouseListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractMouseListener.java new file mode 100644 index 0000000000..3d3b1a09bd --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractMouseListener.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.listeners; + +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; + +/** + * AbstractMouseListener + *

    + */ +public abstract class AbstractMouseListener implements MouseListener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * Mouse x-coordinate. + */ + protected int fMouseX; + + /** + * Mouse y-coordinate. + */ + protected int fMouseY; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseDoubleClick(MouseEvent e) { + } + + /* + * (non-Javadoc) + * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseDown(MouseEvent e) { + fMouseX = e.x; + fMouseY = e.y; + display(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseUp(MouseEvent e) { + } + + /** + * Callback to display information at the current x-y position + */ + protected abstract void display(); +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractMouseTrackListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractMouseTrackListener.java new file mode 100644 index 0000000000..b4e53feaa9 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractMouseTrackListener.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Changed implemented interface to MouseTraceListener + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.listeners; + +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseTrackListener; + +/** + * AbstractMouseListener + *

    + * AbstractMouseListener, base class for the canvas mouse listener. + * + * @author Philippe Sawicki + */ +public abstract class AbstractMouseTrackListener implements MouseTrackListener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * Mouse x-coordinate. + */ + protected int fMouseX; + /** + * Mouse y-coordinate. + */ + protected int fMouseY; + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.swt.events.MouseTrackListener#mouseEnter(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseEnter(MouseEvent event) { + } + + /* + * (non-Javadoc) + * @see org.eclipse.swt.events.MouseTrackListener#mouseExit(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseExit(MouseEvent event) { + } + + /* + * (non-Javadoc) + * @see org.eclipse.swt.events.MouseTrackListener#mouseHover(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseHover(MouseEvent event) { + fMouseX = event.x; + fMouseY = event.y; + display(); + } + + /** + * Tooltip display callback. + */ + protected abstract void display(); + +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractPaintListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractPaintListener.java new file mode 100644 index 0000000000..ae7be22b4a --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractPaintListener.java @@ -0,0 +1,735 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Adapted to new model-view-controller design, display improvements + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.listeners; + +import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; + +/** + * AbstractPaintListener + *

    + * Abstract paint listener. Draws the graphs on the view canvas. + * + * @author Philippe Sawicki + */ +public abstract class AbstractPaintListener implements PaintListener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * Default colors and fonts + */ + protected final Color DEFAULT_DATA_COLOR = new Color(Display.getDefault(), 74, 112, 139); + protected final static Color DEFAULT_LABEL_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_BLACK); + protected final static Color DEFAULT_TEXT_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY); + protected final static Color DEFAULT_DATA_BACKGROUND_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE); + protected final static Color DEFAULT_CURRENT_EVENT_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_RED); + + protected final Font DEFAULT_TITLE_FONT = new Font(Display.getDefault(), "Arial", 10, SWT.BOLD); //$NON-NLS-1$ + protected final Font DEFAULT_VALUES_FONT = new Font(Display.getDefault(), "Arial", 7, SWT.NORMAL); //$NON-NLS-1$ + protected final Font DEFAULT_LABEL_FONT = new Font(Display.getDefault(), "Arial", 8, SWT.NORMAL); //$NON-NLS-1$ + + /** + * A reference to the listener's view. + */ + protected AbstractViewer fViewer; + + /** + * Graph title + */ + protected String fGraphTitle; + + /** + * X-axis label. + */ + protected String fXAxisLabel; + + /** + * Y-axis label. + */ + protected String fYAxisLabel; + + /** + * Horizontal offset for the x-axis label. + */ + protected int fXAxisLabelOffset; + + /** + * Vertical offset for the horizontal axis offset. + */ + protected int fHorizontalAxisYOffset = 20; + + /** + * Graph padding. + */ + protected int fPadding = Config.GRAPH_PADDING; + + /** + * Graph client area. + */ + protected Rectangle fClientArea = new Rectangle(0, 0, 1, 1); + + /** + * Foreground color. + */ + protected Color fForegroundColor; + + /** + * Background color. + */ + protected Color fBackgroundColor; + + /** + * Data plotting color. + */ + protected Color fDataColor; + + /** + * Axis label color. + */ + protected Color fLabelColor; + + /** + * Text color. + */ + protected Color fTextColor; + + /** + * Data background color. + */ + protected Color fDataBackgroundColor; + + /** + * Color for current event time line. + */ + protected Color fCurrentEventColor; + + /** + * Original canvas font. + */ + protected Font fOriginalFont; + + /** + * Font for the title of the graph. + */ + protected Font fTitleFont; + + /** + * Font for the values on the horizontal and vertical axis. + */ + protected Font fValuesFont; + + /** + * Font for the horizontal and vertical labels. + */ + protected Font fLabelFont; + + /** + * Horizontal offset for the axis arrow. + */ + protected final int ARROW_DELTA_X = 10; + + /** + * Vertical offset for the axis arrow. + */ + protected final int ARROW_DELTA_Y = 4; + + /** + * Max horizontal distance between ticks. + */ + protected final int MAX_WIDTH_BETWEEN_TICKS = 40; + + /** + * Max vertical distance between ticks. + */ + protected final int MAX_HEIGHT_BETWEEN_TICKS = 30; + + /** + * Max characters that can be displayed on the vertical axis. + */ + protected final int MAX_CHAR_VERTICAL_DISPLAY = 5; + + /** + * Draw label each "drawLabelEachNTicks_" ticks. + */ + protected int fDrawLabelEachNTicks = 1; + + /** + * Image drawn on the canvas. + */ + protected Image fImage; + + /** + * Paint canvas, where the values are plotted. + */ + protected GC fAxisImage; + + /** + * Is the paint listener initialized ? + */ + protected boolean fInitialized = false; + + /** + * Draw area. + */ + protected Rectangle fDrawArea; + + /** + * Right padding (in pixels). + */ + protected int fPaddingRight = Config.GRAPH_PADDING; + + /** + * Top padding (in pixels). + */ + protected int fPaddingTop = Config.GRAPH_PADDING; + + /** + * Vertical axis offset (in pixels). + */ + protected int fVerticalAxisOffset = 2 * Config.GRAPH_PADDING; + + /** + * Vertical axis factor for values (10^delta). When values larger than MAX_CHAR_VERTICAL_DISPLAY. + */ + protected int fDelta = 0; + + /** + * The barWidth of a bar + */ + protected int fBarWith = Config.DEFAULT_HISTOGRAM_BAR_WIDTH; + + /** + * Minimum value on horizontal axis + */ + protected long fXMin = -1; + + /** + * Maximum value on horizontal axis + */ + protected long fXMax = -1; + + /** + * Minimum value on vertical axis + */ + protected long fYMin = -1; + + /** + * Maximum value on vertical axis + */ + protected long fYMax = -1; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param view + * A reference to the listener's view. + */ + public AbstractPaintListener(AbstractViewer view) { + fViewer = view; + fDataColor = DEFAULT_DATA_COLOR; + fLabelColor = DEFAULT_LABEL_COLOR; + fTextColor = DEFAULT_TEXT_COLOR; + fDataBackgroundColor = DEFAULT_DATA_BACKGROUND_COLOR; + fCurrentEventColor = DEFAULT_CURRENT_EVENT_COLOR; + + fTitleFont = DEFAULT_TITLE_FONT; + fValuesFont = DEFAULT_VALUES_FONT; + fLabelFont = DEFAULT_LABEL_FONT; + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + /** + * Returns the draw area height. + * @return The draw area height. + */ + public double getHeight() { + return (fClientArea.height - 2.0 * fPadding - fHorizontalAxisYOffset - fPaddingTop); + } + + /** + * Returns the histogram's draw area width. + * @return The histogram's draw area width. + */ + public double getWidth() { + return (fClientArea.width - 2.0 * fPadding - fVerticalAxisOffset - fPaddingRight); // width of the plot area; + } + + /** + * Returns the histogram's draw area padding. + * @return The histogram's draw area padding. + */ + public int getPadding() { + return fPadding; + } + + /** + * Returns the histogram's draw area top padding. + * @return The histogram's draw area top padding. + */ + public int getPaddingTop() { + return fPaddingTop; + } + + /** + * Returns the histogram's vertical axis offset. + * @return The histogram's vertical axis offset. + */ + public int getVerticalAxisOffset() { + return fVerticalAxisOffset; + } + + /** + * Returns the histogram's horizontal axis offset. + * @return The histogram's horizontal axis offset. + */ + public int getHorizontalAxisYOffset() { + return fHorizontalAxisYOffset; + } + + /** + * Returns the horizontal minimum value + * @return The horizontal minimum value. + */ + public long getXMin() { + return fXMin; + } + + /** + * Returns the horizontal maximum value + * @return The horizontal maximum value. + */ + public long getXMax() { + return fXMax; + } + + /** + * Returns the horizontal minimum value + * @return The horizontal minimum value. + */ + public long getYMin() { + return fYMin; + } + + /** + * Returns the vertical maximum value + * @return The vertical maximum value. + */ + public long getYMax() { + return fYMax; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /** + * Disposes local resources (e.g. colors or fonts) + */ + public void dispose() { + DEFAULT_DATA_COLOR.dispose(); + DEFAULT_TITLE_FONT.dispose(); + DEFAULT_VALUES_FONT.dispose(); + DEFAULT_LABEL_FONT.dispose(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent) + */ + @Override + public void paintControl(PaintEvent e) { + fClientArea = fViewer.getClientArea(); + + fForegroundColor = e.gc.getForeground(); + fBackgroundColor = e.gc.getBackground(); + fOriginalFont = e.gc.getFont(); + + scale(); + + if (!fInitialized) { + fImage = new Image(Display.getDefault(), fViewer.getBounds()); + + fAxisImage = new GC(fImage); + + fAxisImage.setForeground(fForegroundColor); + fAxisImage.setBackground(fBackgroundColor); + fAxisImage.fillRectangle(fImage.getBounds()); + + fInitialized = true; + } + + paintGraphTitle(); + paintBackground(); + paintHorizontalAxis(); + paintVerticalAxis(); + paintContent(); + + e.gc.drawImage(fImage, 0, 0); + } + + /** + * Paints the title of the graph. + */ + public void paintGraphTitle() { + if (fGraphTitle != null) { + fAxisImage.setFont(fTitleFont); + fAxisImage.setForeground(fLabelColor); + fAxisImage.setBackground(fBackgroundColor); + + int zoomFactor = fViewer.getZoomFactor() / fViewer.getZoomIncrement() + 1; + int labelWidth = fAxisImage.stringExtent(fGraphTitle).x; + // Draws the zoom factor in the title only if there is one + if (fViewer.getZoomFactor() > 1) + fAxisImage.drawText(fGraphTitle + " (" + zoomFactor + "x)", (fViewer.getBounds().width - fPadding - labelWidth) / 2, 0); //$NON-NLS-1$ //$NON-NLS-2$ + else + fAxisImage.drawText(fGraphTitle, (fViewer.getBounds().width - fPadding - labelWidth) / 2, 0); + } + } + + /** + * Paints the background of the draw area. + */ + public void paintBackground() { + fAxisImage.setBackground(fDataBackgroundColor); + + fAxisImage.fillRectangle(fPadding + fVerticalAxisOffset, fPadding + fPaddingTop, (int)getWidth() + 1, (int)getHeight()); + } + + /** + * Paints the horizontal axis. + */ + public void paintHorizontalAxis() { + fAxisImage.setForeground(fForegroundColor); + + int y = fClientArea.height - fPadding - fHorizontalAxisYOffset; + + fAxisImage.drawLine(fClientArea.x + fPadding + fVerticalAxisOffset, y, fClientArea.width - fPadding, y); + + paintHorizontalArrow(fClientArea.width - fPadding, y); + // Draw the axis graphic details only if there are some data points (i.e. do not draw the axis graphic details + // if the window timerange is so small that no latency can be computed, or if there are no matching events in + // the timerange (for example, when an experiment has many traces with a large time gap between the logged + // events sets). + if (fXMin != Long.MAX_VALUE && fXMax != Long.MIN_VALUE && fXMin != fXMax) { + paintHorizontalTicks(y); + paintHorizontalAxisValues(y + 30); + } + paintHorizontalAxisLabel(y + fHorizontalAxisYOffset - 5); + } + + /** + * Paints the vertical axis. + */ + public void paintVerticalAxis() { + fAxisImage.setForeground(fForegroundColor); + + int x = fClientArea.x + fPadding + fVerticalAxisOffset; + + fAxisImage.drawLine(x, fPadding, x, fClientArea.height - fPadding - fHorizontalAxisYOffset); + + paintVerticalArrow(x, fClientArea.y + fPadding); + // Draw the axis graphic details only if there are some data points (i.e. do not draw the axis graphic details + // if the window timerange is so small that no latency can be computed, or if there are no matching events in + // the timerange (for example, when an experiment has many traces with a large time gap between the logged + // events sets). + if (fXMin != Long.MAX_VALUE && fXMax != Long.MIN_VALUE && fXMin != fXMax) { + paintVerticalTicks(x); + paintVerticalAxisValues(x); + } + paintVerticalAxisLabel(x); + } + + /** + * Paints the arrow on the horizontal axis. + * @param x + * The x-coordinate of the point where the arrow points. + * @param y + * The y-coordinate of the point where the arrow points. + */ + public void paintHorizontalArrow(int x, int y) { + // Arrow top line + fAxisImage.drawLine(x - ARROW_DELTA_X, y - ARROW_DELTA_Y, x, y); + // Arrow bottom line + fAxisImage.drawLine(x - ARROW_DELTA_X, y + ARROW_DELTA_Y, x, y); + } + + /** + * Paints the arrow on the vertical axis. + * @param x + * The x-coordinate of the point where the arrow points. + * @param y + * The y-coordinate of the point where the arrow points. + */ + public void paintVerticalArrow(int x, int y) { + // Arrow left line + fAxisImage.drawLine(x - ARROW_DELTA_Y, y + ARROW_DELTA_X, x, y); + // Arrow right line + fAxisImage.drawLine(x + ARROW_DELTA_Y, y + ARROW_DELTA_X, x, y); + } + + /** + * Paints the horizontal ticks. + * @param y + * The y coordinate where to draw the axis. + */ + public void paintHorizontalTicks(int y) { + if (fXMin >= 0L && fXMin >= 0L) { + int nbTicks = (int)(getWidth()) / MAX_WIDTH_BETWEEN_TICKS + 1; + + for (int i = 0; i < nbTicks; i++) { + if (i % fDrawLabelEachNTicks == 0) { + int x = i * MAX_WIDTH_BETWEEN_TICKS + fPadding + fVerticalAxisOffset; + fAxisImage.drawLine(x, y, x, y + 3); + } + } + } + } + + /** + * Paints the horizontal axis values. + * @param y + * The y coordinate where to draw the axis. + */ + public void paintHorizontalAxisValues(int y) { + if (fXMin >= 0L && fXMax >= 0L) { + fAxisImage.setForeground(fTextColor); + fAxisImage.setBackground(fBackgroundColor); + + double width = getWidth(); + int nbTicks = ((int)getWidth()) / MAX_WIDTH_BETWEEN_TICKS + 1; + + for (int i = 0; i < nbTicks; i++) { + if (i % fDrawLabelEachNTicks == 0) { + int x = i * MAX_WIDTH_BETWEEN_TICKS + fPadding + fVerticalAxisOffset; + + long currentValue = (i * MAX_WIDTH_BETWEEN_TICKS)* (long)((fXMax - fXMin) / width) + fXMin; + String currentLabel = formatStringForHorizontalAxis(currentValue); + + fAxisImage.setFont(fValuesFont); + fAxisImage.drawText(currentLabel, x, y - 24); + } + } + } + } + + /** + * Paints the horizontal axis label. + * @param y + * The y-coordinate where to draw the label. + */ + public void paintHorizontalAxisLabel(int y) { + if (fXAxisLabel != null) { + fAxisImage.setFont(fLabelFont); + fAxisImage.setForeground(fLabelColor); + + int labelWidth = fAxisImage.stringExtent(fXAxisLabel).x; + + fAxisImage.drawText(fXAxisLabel, fClientArea.width - fPadding - labelWidth, y); + } + } + + /** + * Paints the vertical axis ticks. + * @param x + * The x-coordinate where to draw the ticks. + */ + public void paintVerticalTicks(int x) { + if (fYMin != 0L && fYMin != 0L) { + int nbTicks = (int)(getHeight() / MAX_HEIGHT_BETWEEN_TICKS + 1); + + for (int i = 0; i < nbTicks; i++) { + int y = fClientArea.height - fPadding - fHorizontalAxisYOffset - i * MAX_HEIGHT_BETWEEN_TICKS; + fAxisImage.drawLine(x - 3, y, x, y); + } + } + } + + /** + * Paints the vertical axis values. + * @param x + * The x-coordinate where to draw the values. + */ + public void paintVerticalAxisValues(int x) { + if (fYMin >= 0L && fYMax >= 0L) { + fAxisImage.setForeground(fTextColor); + fAxisImage.setBackground(fBackgroundColor); + + double height = getHeight(); + int nbTicks = (int)(height / MAX_HEIGHT_BETWEEN_TICKS + 1); + + // System.out.println("nbTicks = " + nbTicks); + + for (int i = 0; i < nbTicks; i++) { + int y = fClientArea.height - fPadding - fHorizontalAxisYOffset - i * MAX_HEIGHT_BETWEEN_TICKS; + + long currentValue = (i * MAX_HEIGHT_BETWEEN_TICKS)* (long)((fYMax - fYMin) / height) + fYMin; + String currentLabel = formatStringForVerticalAxis(currentValue); + + fAxisImage.setFont(fValuesFont); + + Point textDimensions = fAxisImage.stringExtent(currentLabel); + fAxisImage.drawText(currentLabel, x - textDimensions.x - 5, y - textDimensions.y / 2); + } + } + } + + /** + * Increases the bar width. + */ + public void increaseBarWitdh() { + fBarWith = fBarWith << 1; + if (fBarWith > Config.MAX_HISTOGRAM_BAR_WIDTH) { + fBarWith = Config.MAX_HISTOGRAM_BAR_WIDTH; + } + } + + /** + * Decreases the bar width. + */ + public void decreaseBarWitdh() { + fBarWith = fBarWith >> 1; + if (fBarWith < Config.MIN_HISTOGRAM_BAR_WIDTH) { + fBarWith = Config.MIN_HISTOGRAM_BAR_WIDTH; + } + } + + + /** + * Paints the vertical axis label. + * @param x + * The x-coordinate where to draw the label. + */ + public void paintVerticalAxisLabel(int x) { + if (fYAxisLabel != null) { + fAxisImage.setFont(fLabelFont); + fAxisImage.setForeground(fLabelColor); + fAxisImage.setBackground(fBackgroundColor); + + if (fDelta >= 1) + fAxisImage.drawText(fYAxisLabel + " (x10^" + fDelta + ")", x + 10, fHorizontalAxisYOffset - 5); //$NON-NLS-1$//$NON-NLS-2$ + else + fAxisImage.drawText(fYAxisLabel, x + 10, fPadding); + } + } + + /** + * Adds points to the graph and draws them to the canvas. + * @param points + * The buffer of points to draw. + * @param nbPoints + * The number of points in the buffer. + */ + abstract public String formatToolTipLabel(int x, int y); + + /** + * Method to be implemented to scale the model data to the actual screen size. + */ + abstract public void scale(); + + /** + * Called for drawing elements after points are added to the graph. + */ + abstract public void paintContent(); + + /** + * Clears the image and prepares it for redrawing. + */ + public void clear() { + fInitialized = false; + fXMin = -1; + fXMax = -1; + fYMin = -1; + fYMax = -1; + } + + /** + * Draw horizontal label each "nbTicks" ticks. + * @param nbTicks + * The draw interval. + */ + public void setDrawLabelEachNTicks(int nbTicks) { + fDrawLabelEachNTicks = nbTicks; + } + + /** + * Sets the title of the graph. + * @param graphTitle + * The title of the graph. + */ + public void setGraphTitle(String graphTitle) { + fGraphTitle = graphTitle; + } + + /** + * Sets the horizontal axis label. + * @param xAxisLabel + * The horizontal axis label. + * @param offset + * The horizontal axis draw offset (in pixels). + */ + public void setXAxisLabel(String xAxisLabel, int offset) { + fXAxisLabel = xAxisLabel; + fXAxisLabelOffset = offset; + } + + /** + * Sets the vertical axis label. + * @param yAxisLabel + * The vertical axis label. + */ + public void setYAxisLabel(String yAxisLabel) { + fYAxisLabel = yAxisLabel; + } + + /** + * Returns a string representing the given value. + * + * @param value + * The numeric value to convert to String. + * @return The String-formatted value. + */ + public String formatStringForHorizontalAxis(long value) { + return String.valueOf(value); + } + + /** + * Returns a string representing the given value. + * + * @param value + * The numeric value to convert to String. + * @return The String-formatted value. + */ + public String formatStringForVerticalAxis(long value) { + return String.valueOf(value); + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/GraphMouseListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/GraphMouseListener.java new file mode 100644 index 0000000000..5d6cb75372 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/GraphMouseListener.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.listeners; + +import org.eclipse.linuxtools.lttng.ui.views.latency.GraphViewer; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyGraphModel; + +/** + * GraphMouseListener + *

    + */ +public class GraphMouseListener extends AbstractMouseListener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * A reference to the observed view. + */ + protected GraphViewer fView; + + /** + * A reference to the HistogramPaintListener. + */ + protected GraphPaintListener fGraph; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param view + * A reference to the observed view. + * @param histogramPaintListener + * A reference to the histogram's paintListener. + */ + public GraphMouseListener(GraphViewer view, GraphPaintListener graphPaintListener) { + fView = view; + fGraph = graphPaintListener; + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseListener#display() + */ + @Override + protected void display() { + long currentTime = fGraph.getCurrentTimeFromHorizontalValue(fMouseX); + ((LatencyGraphModel)fView.getModel()).setCurrentEventNotifyListeners(currentTime); + } +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/GraphPaintListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/GraphPaintListener.java new file mode 100644 index 0000000000..a6732c2fee --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/GraphPaintListener.java @@ -0,0 +1,227 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Adapted to new model-view-controller design, display improvements + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.listeners; + +import java.text.DecimalFormat; + +import org.eclipse.linuxtools.lttng.ui.views.distribution.model.BaseDistributionData; +import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramUtils; +import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer; +import org.eclipse.linuxtools.lttng.ui.views.latency.GraphViewer; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.GraphScaledData; +import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphDataModel; + +/** + * GraphPaintListener + *

    + * Graph paint listener. + * + * @author Philippe Sawicki + */ +public class GraphPaintListener extends AbstractPaintListener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * Scaled data from data model + */ + protected GraphScaledData fScaledData; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param viewer + * A reference to the listener's viewer. + */ + public GraphPaintListener(AbstractViewer view) { + super(view); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#scale() + */ + @Override + public void scale() { + + // width of the plot area + double width = getWidth(); + // height of the plot area + double height = getHeight(); + + IGraphDataModel model = ((GraphViewer)fViewer).getModel(); + fScaledData = model.scaleTo((int)width, (int)height, fBarWith); + + fXMin = fScaledData.getHorFirstBucketTime() > 0 ? fScaledData.getHorFirstBucketTime() : 0; + fXMax = 0; + if (fScaledData.getHorLastBucket() > 0) { + fXMax = fScaledData.getHorBucketEndTime(fScaledData.getHorNbBuckets() - 1); + } + + fYMin = fScaledData.getVerFirstBucketTime() > 0 ? fScaledData.getVerFirstBucketTime() : 0; + fYMax = 0; + if (fScaledData.getVerLastBucket() > 0) { + fYMax = fScaledData.getVerBucketEndTime(fScaledData.getVerNbBuckets() - 1); + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintContent() + */ + @Override + public void paintContent() { + if (fXMin >= 0 && fXMax >= 0 && fYMin >= 0 && fYMax >= 0 && fScaledData != null) { + + fAxisImage.setForeground(fDataColor); + fAxisImage.setBackground(fDataColor); + + double height = getHeight(); + + int xLen = fScaledData.getHorNbBuckets(); + int yLen = fScaledData.getVerNbBuckets(); + + int barWidth = fScaledData.getBarWidth(); + + for (int i = 0; i < xLen; i++) { + for (int j = 0; j < yLen; j++) { + if (fScaledData.getEventCount(i, j) > 0) { + + double x = fPadding + i * barWidth + fVerticalAxisOffset + 1; + double y = fPadding + fPaddingTop + height - j * barWidth; + + // Avoid over-drawing background area + int yBarWidth = fBarWith; + if (y - yBarWidth < fPadding + fPaddingTop) { + yBarWidth = (int) (y - fPadding - fPaddingTop); + } + int xBarWidth = fBarWith; + if(x + xBarWidth > fClientArea.width - fPadding - fPaddingRight) { + xBarWidth = (int)(fClientArea.width - fPadding - fPaddingRight - x); + } + fAxisImage.fillRectangle((int) x, (int) y - (int) yBarWidth, (int) xBarWidth, (int) yBarWidth); + } + } + } + + if (fScaledData.isCurrentEventTimeValid()) { + // Draw vertical line + int index = fScaledData.getHorBucketIndex(fScaledData.getCurrentEventTime()); + + int x = fPadding + index * barWidth + fVerticalAxisOffset + 1; + fAxisImage.setForeground(fCurrentEventColor); + fAxisImage.setBackground(fCurrentEventColor); + fAxisImage.drawLine(x, fPadding + fPaddingTop, x, fClientArea.height - fPadding - fHorizontalAxisYOffset); + } + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatStringForVerticalAxis(long) + */ + @Override + public String formatStringForVerticalAxis(long value) { + DecimalFormat formatter = new DecimalFormat("0.0E0"); //$NON-NLS-1$ + return formatter.format(value); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatStringForHorizontalAxis(long) + */ + @Override + public String formatStringForHorizontalAxis(long value) { + return HistogramUtils.nanosecondsToString(value); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatToolTipLabel(int, int) + */ + @Override + public String formatToolTipLabel(int x, int y) { + + int index = getIndexFromHorizontalValue(x); + int yIndex = getIndexFromVerticalValue(y); + + if (index != BaseDistributionData.OUT_OF_RANGE_BUCKET && yIndex != BaseDistributionData.OUT_OF_RANGE_BUCKET) { + if (fScaledData.getEventCount(index, yIndex) > 0) { + StringBuffer buffer = new StringBuffer(); + buffer.append("Time Range in s = ["); //$NON-NLS-1$ + // TODO change Utility + long startTime = fScaledData.getHorBucketStartTime(index) > 0 ? fScaledData.getHorBucketStartTime(index) : 0; + buffer.append(HistogramUtils.nanosecondsToString(startTime)); + buffer.append(","); //$NON-NLS-1$ + buffer.append(HistogramUtils.nanosecondsToString(fScaledData.getHorBucketEndTime(index))); + buffer.append("]\n"); //$NON-NLS-1$ + buffer.append("Latency Range in s = ["); //$NON-NLS-1$ + long yStartTime = fScaledData.getVerBucketStartTime(yIndex) > 0 ? fScaledData.getVerBucketStartTime(yIndex) : 0; + buffer.append(HistogramUtils.nanosecondsToString(yStartTime)); + buffer.append(","); //$NON-NLS-1$ + buffer.append(HistogramUtils.nanosecondsToString(fScaledData.getVerBucketEndTime(yIndex))); + buffer.append("]\n"); //$NON-NLS-1$ + buffer.append("Latency count = "); //$NON-NLS-1$ + buffer.append(fScaledData.getEventCount(index, yIndex)); + return buffer.toString(); + } + } + return ""; //$NON-NLS-1$ + } + + public int getIndexFromHorizontalValue(int x) { + if (fScaledData != null) { + double barWidth = fScaledData.getBarWidth(); + + int index = (int) ((x - fPadding - fVerticalAxisOffset - 1) / barWidth); + if ((index >= 0) && (fScaledData.getHorNbBuckets() > index)) { + return index; + } + } + return BaseDistributionData.OUT_OF_RANGE_BUCKET; + } + + public int getIndexFromVerticalValue(int y) { + if (fScaledData != null) { + double barWidth = fScaledData.getBarWidth(); + double height = getHeight(); // height of the plot area + + int index = (int) ((height - (y - fPadding - fPaddingTop)) / barWidth); + if (index >= 0 && fScaledData.getVerNbBuckets() > index) { + return index; + } + } + return BaseDistributionData.OUT_OF_RANGE_BUCKET; + } + + public long getCurrentTimeFromHorizontalValue(int x) { + if (fXMin >= 0 && fXMax >= 0) { + int index = getIndexFromHorizontalValue(x); + if (index != BaseDistributionData.OUT_OF_RANGE_BUCKET) { + return fScaledData.getHorBucketStartTime(index); + } + } + return Config.INVALID_EVENT_TIME; + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/HistogramPaintListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/HistogramPaintListener.java new file mode 100644 index 0000000000..0241f647cc --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/HistogramPaintListener.java @@ -0,0 +1,355 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Adapted to new model-view-controller design, display improvements + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.listeners; + +import java.text.DecimalFormat; +import java.util.Collections; +import java.util.Vector; + +import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramScaledData; +import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramUtils; +import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramDataModel; +import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer; +import org.eclipse.linuxtools.lttng.ui.views.latency.HistogramViewer; +import org.eclipse.linuxtools.lttng.ui.views.latency.Messages; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.plugin.AbstractUIPlugin; + +/** + * HistogramPaintListener + *

    + * Histogram paint listener. + * + * @author Philippe Sawicki + */ +public class HistogramPaintListener extends AbstractPaintListener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * Is a histogram bar so high that it is clipped from the draw area ? + */ + private boolean fBarIsClipped = false; + + /** + * Scaled data from data model + */ + protected HistogramScaledData fScaledData; + + /** + * Warning Image + */ + protected Image fWarningImage; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param view + * A reference to the listener's viewer. + */ + public HistogramPaintListener(AbstractViewer viewer) { + super(viewer); + fWarningImage = AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/warning.gif").createImage(Display.getCurrent()); //$NON-NLS-1$ + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + /** + * Returns the histogram's bar Width. + * @return The histogram's bar Width. + */ + public int getBarWidth() { + return fBarWith; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#dispose() + */ + @Override + public void dispose() { + fWarningImage.dispose(); + super.dispose(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#scale() + */ + @Override + public void scale() { + // width of the plot area + double width = getWidth(); + // height of the plot area + double height = getHeight(); + + int barWidth = getBarWidth(); + + IHistogramDataModel model = ((HistogramViewer)fViewer).getModel(); + fScaledData = model.scaleTo((int)width, (int)height, barWidth); + + fYMin = 0; + fYMax = fScaledData.fMaxValue; + + fXMin = fScaledData.getFirstBucketTime(); + fXMin = fXMin > 0 ? fXMin : 0; + fXMax = fScaledData.getBucketEndTime(fScaledData.fLastBucket - 1); + + // No data to display - set end time to 0 + if (fYMax == 0) { + fXMax = 0; + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintVerticalTicks(int) + */ + @Override + public void paintVerticalTicks(int x) { + // done in method paintVerticalAxisValues() + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintVerticalAxisValues(int) + */ + @Override + public void paintVerticalAxisValues(int x) { + int zoomFactor = 1; + + zoomFactor = fViewer.getZoomFactor(); + + if (fYMin >= 0L && fYMax != 0L) { + fAxisImage.setForeground(fTextColor); + fAxisImage.setBackground(fBackgroundColor); + + // Apply the zoom to the max value of the graph for the next calculations + long yMax = fYMax / zoomFactor; + + int nbTicks = ((int)getHeight()) / MAX_HEIGHT_BETWEEN_TICKS + 1; + + Vector values = new Vector(); + boolean multipleSameValues = true; + while (multipleSameValues) { + double valueStep = (double) (yMax - fYMin) / (double) (nbTicks); + + for (int i = 0; i < nbTicks; i++) { + double currentValue = (double) (fYMin + i * valueStep) / (Math.pow(10, fDelta)); + + values.add((int) currentValue); + } + + Collections.sort(values); + boolean hasRepetition = false; + for (int i = 1; i < values.size(); i++) { + if (values.get(i) == values.get(i - 1)) { + hasRepetition = true; + break; + } + } + + if (hasRepetition) { + nbTicks--; + values.clear(); + } else { + multipleSameValues = false; + + // Draw rectangle over the old values + int height = fViewer.getBounds().height - 2 * fPadding - fPaddingTop - fHorizontalAxisYOffset; + fAxisImage.fillRectangle(0, fPadding + fPaddingTop, fPadding + fVerticalAxisOffset, height); + + double pixelStep = (getHeight()) / values.size() + 1; + + for (int i = 0; i < values.size(); i++) { + double currentValue = values.get(i); + + int y = (int) (fClientArea.height - fPadding - fHorizontalAxisYOffset - i * pixelStep); + String currentLabel = formatStringForVerticalAxis((long) currentValue); + + fAxisImage.setFont(fValuesFont); + + Point textDimensions = fAxisImage.stringExtent(currentLabel); + fAxisImage.drawText(currentLabel, x - textDimensions.x - 5, y - textDimensions.y / 2); + fAxisImage.drawLine(x - 3, y, x, y); + } + } + } + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintContent() + */ + @Override + public void paintContent() { + double zoomFactor = fViewer.getZoomFactor(); + + // Calculate the vertical axis factor and see if it has changed + double tmpDelta = fDelta; + fDelta = 0; + if (Long.toString(fYMax / (long) zoomFactor).length() > MAX_CHAR_VERTICAL_DISPLAY) { + fDelta = Long.toString(fYMax / (long) zoomFactor).length() - MAX_CHAR_VERTICAL_DISPLAY; + } + if (tmpDelta != fDelta) { + fViewer.clearBackground(); + } + + paintBackground(); + paintVerticalAxis(); + paintHorizontalAxis(); + + fAxisImage.setForeground(fDataColor); + fAxisImage.setBackground(fDataColor); + + // height of the plot area + double height = getHeight(); + + int barWidth = getBarWidth(); + + // axisImage_.setBackground(backgroundColor_); + // 1.a Iterate over the points, from 0 to nbPoints + // 1.b Find the max counter value + // 2. Assign the max value to the "yMax_" class attribute + // 3. Draw the histogram bars using "axisImage_.fillRectangle(...)" + boolean oneBarIsClipped = false; + + for (int i = 0; i < fScaledData.fData.length; i++) { + double pointY = fScaledData.fData[i]; + + // in pixels + double x = fPadding + i * barWidth + fVerticalAxisOffset + 1; + + if (i == fScaledData.fData.length - 1) + x -= 1.0; + double barHeight = zoomFactor * ((double)(pointY - fYMin) / (double)(fYMax - fYMin)) * height; + + if (barHeight > height + 1) { + barHeight = height; + oneBarIsClipped = true; + + fAxisImage.drawImage(fWarningImage, 5, 3); + } + + // Only draw the bars that have a barHeight of more than 1 pixel + if (barHeight > 0) { + double y = fPadding + fPaddingTop + height - barHeight; + fAxisImage.setBackground(fDataColor); + + if (barHeight > height - 1) { + fAxisImage.fillRectangle((int) x, (int) y, (int) barWidth, (int) (barHeight + 1)); + } else { + fAxisImage.fillRectangle((int) x, (int) y, (int) barWidth, (int) (barHeight + 2)); + } + } + } + + if (oneBarIsClipped) + fBarIsClipped = true; + else + fBarIsClipped = false; + } + + /** + * Paints the histogram horizontal axis values in engineering notation in which the exponent is a multiple of three. + * @param value + * The numeric value to convert to engineering notation. + * @return The given value formatted according to the engineering notation. + */ + @Override + public String formatStringForHorizontalAxis(long value) { + DecimalFormat formatter = new DecimalFormat("##0.#E0"); //$NON-NLS-1$ + return formatter.format(value); + } + + /** + * Sets the bar width. + * @param barWidth + * bar width to set + */ + public void setBarWidth(int barWidth) { + fBarWith = barWidth; + } + + /** + * Returns "true" if a histogram bar is so high that it cannot be drawn in the draw area, "false" otherwise. + * @return "true" if a histogram bar is so high that it cannot be drawn in the draw area, "false" otherwise. + */ + public boolean barIsClipped() { + return fBarIsClipped; + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatToolTipLabel(int, int) + */ + @Override + public String formatToolTipLabel(int x, int y) { + if (fScaledData != null) { + + double barWidth = getBarWidth(); + double height = getHeight(); // height of the plot area + + double zoomFactor = fViewer.getZoomFactor(); + + int index = (int) ((x - fPadding - fVerticalAxisOffset - 1) / barWidth); + + double barHeight = 0.0; + if (index >= 0 && index <= fScaledData.fLastBucket) { + barHeight = (zoomFactor * height * (fScaledData.fData[index] - fYMin) / (fYMax - fYMin)); + } + + long fMouseY = (long) (height - (y - fPadding - fPaddingTop)); + + // Verifying mouse pointer is over histogram bar + if (index >= 0 && fScaledData.fLastBucket >= index && fMouseY >= 0 && fMouseY < barHeight && fMouseY < height && x >= (fVerticalAxisOffset + fPadding)) { + + fScaledData.fCurrentBucket = index; + + long startTime = fScaledData.getBucketStartTime(index); + // negative values are possible if time values came into the model in decreasing order + if (startTime < 0) { + startTime = 0; + } + long endTime = fScaledData.getBucketEndTime(index); + int nbEvents = fScaledData.fData[index]; + + StringBuffer buffer = new StringBuffer(); + buffer.append("Latency Range in s = ["); //$NON-NLS-1$ + buffer.append(HistogramUtils.nanosecondsToString(startTime)); + buffer.append(","); //$NON-NLS-1$ + buffer.append(HistogramUtils.nanosecondsToString(endTime)); + buffer.append("]\n"); //$NON-NLS-1$ + buffer.append("Latency count = "); //$NON-NLS-1$ + buffer.append(nbEvents); + return buffer.toString(); + } + } + return ""; //$NON-NLS-1$ + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/TimePointerListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/TimePointerListener.java new file mode 100644 index 0000000000..31027ca4aa --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/TimePointerListener.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + * Bernd Hufmann - Changed display interface implementation + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.listeners; + +import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer; + +/** + * TimePointerListener + *

    + * Displays a tooltip showing the approximate values of the point under the mouse cursor. + * + * @author Philippe Sawicki + */ +public class TimePointerListener extends AbstractMouseTrackListener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * A reference to the observed view. + */ + protected AbstractViewer fView; + + /** + * A reference to the HistogramPaintListener. + */ + protected GraphPaintListener fGraph; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param view + * A reference to the observed view. + * @param histogramPaintListener + * A reference to the histogram's paintListener. + */ + public TimePointerListener(AbstractViewer view, GraphPaintListener graphPaintListener) { + fView = view; + fGraph = graphPaintListener; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseTrackListener#display() + */ + @Override + protected void display() { + fView.setToolTipText(fGraph.formatToolTipLabel(fMouseX, fMouseY)); + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/TooltipListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/TooltipListener.java new file mode 100644 index 0000000000..ccb8bc2d74 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/TooltipListener.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Bernd Hufmann - Changed display interface implementation + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.listeners; + +import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer; +import org.eclipse.linuxtools.lttng.ui.views.latency.Messages; + +/** + * TooltipListener + *

    + * Tooltip listener, displays the event count for each latency selected by the mouse click area on histogram. + * + * @author Ali Jawhar + */ +public class TooltipListener extends AbstractMouseTrackListener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * A reference to the observed view. + */ + protected AbstractViewer fView; + + /** + * A reference to the HistogramPaintListener. + */ + protected HistogramPaintListener fHistogram; + + /** + * Is the mouse over the warning icon, indicating that a bar is higher than the draw area due to zooming ? + */ + protected boolean fDisplayWarning = false; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param view + * A reference to the observed view. + * @param histogramPaintListener + * A reference to the histogram's paintListener. + */ + public TooltipListener(AbstractViewer view, HistogramPaintListener histogramPaintListener) { + fView = view; + fHistogram = histogramPaintListener; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseTrackListener#display() + */ + @Override + protected void display() { + displayWarningTooltip(); + displayTooltip(); + } + + // ------------------------------------------------------------------------ + // Helper Functions + // ------------------------------------------------------------------------ + + /** + * Displays a tooltip if the mouse is over the warning icon indication that a bar cannot be draw entirely due to the + * zoom factor. + */ + protected void displayWarningTooltip() { + if (fHistogram.barIsClipped() && fMouseX > 5 && fMouseX < 21 && fMouseY > 3 && fMouseY < 18) { + fView.setToolTipText(Messages.LatencyView_ClippingWarning); + fDisplayWarning = true; + } else { + fDisplayWarning = false; + } + } + + /** + * Displays the tooltip showing the details of the histogram bar pointed by the mouse. + */ + protected void displayTooltip() { + if (!fDisplayWarning) + fView.setToolTipText(fHistogram.formatToolTipLabel(fMouseX, fMouseY)); + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/ZoomListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/ZoomListener.java new file mode 100644 index 0000000000..266f926a1f --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/ZoomListener.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.listeners; + +import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; + +/** + * ZoomListener + *

    + * + * Canvas zoom listener. + * + * @author Philippe Sawicki + */ +public class ZoomListener implements Listener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + /** + * A reference to the observed view. + */ + protected AbstractViewer fView; + /** + * Default zoom factor. + */ + protected int fZoomFactor; + /** + * Zoom increment. + */ + protected int fZoomIncrement = 30; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructor. + * @param view + * A reference to the observed view. + * @param defaultZoomFactor + * Default zoom factor. + */ + public ZoomListener(AbstractViewer view, int defaultZoomFactor) { + fView = view; + fZoomFactor = defaultZoomFactor; + } + + /** + * Constructor. + * @param view + * A reference to the observed view. + */ + public ZoomListener(AbstractViewer view) { + this(view, 1); + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + /** + * Returns the zoom factor. + * @return The zoom factor. + */ + public int getZoomFactor() { + if (fZoomFactor < 1) + return 1; + else + return fZoomFactor; + } + + /** + * Returns the zoom increment. + * @return The zoom increment. + */ + public int getZoomIncrement() { + return fZoomIncrement; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event) + */ + @Override + public void handleEvent(Event event) { + switch (event.type) { + case SWT.MouseWheel: + boolean scrollDown = (event.count == 0 ? false : (event.count > 0 ? false : true)); + int zoomStep = fZoomIncrement; + if (scrollDown) + zoomStep = -fZoomIncrement; + fZoomFactor = Math.max(0, fZoomFactor + zoomStep); + + Canvas canvas = (Canvas) event.widget; + if (fView != null) { + // clear the background to allow redraw of values of the vertical axis. + fView.clearBackground(); + fView.redrawTitle(); + fView.askForRedraw(); + } + canvas.redraw(); + break; + } + } + + /** + * Sets the zoom increment. + * @param zoomIncrement + * The new zoom increment. + */ + public void setZoomIncrement(int zoomIncrement) { + fZoomIncrement = zoomIncrement; + } +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/messages.properties b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/messages.properties new file mode 100644 index 0000000000..cf907c03d5 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/messages.properties @@ -0,0 +1,59 @@ +#******************************************************************************* +# Copyright (c) 2011 Ericsson +# +# All rights reserved. This program and the accompanying materials are +# made available under the terms of the Eclipse Public License v1.0 which +# accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation +# Bernd Hufmann - Updated and added properties +# *******************************************************************************/ + +LatencyView_ViewName=LatencyView +LatencyView_Action_IncreaseBarWidth_Tooltip=Increase bar width/height +LatencyView_Action_DecreaseBarWidth_Tooltip=Decrease bar width/height +LatencyView_Action_AddEvents_Tooltip=Add matching events +LatencyView_Action_DeleteEvents_Tooltip=Delete matching events +LatencyView_Action_ListEvents_Tooltip=List matching events +LatencyView_Dialogs_AddEvents_Title=Add event pairs +LatencyView_Dialogs_AddEvents_Message=Select a pair of events to add it to the match list : +LatencyView_Dialogs_AddEvents_Buttons_Add=Add +LatencyView_Dialogs_AddEvents_Buttons_Close=Close +LatencyView_Dialogs_AddEvents_Columns_Start=Start event types +LatencyView_Dialogs_AddEvents_Columns_End=End event types +LatencyView_Dialogs_AddEvents_Columns_List_Trigger=Trigger event type +LatencyView_Dialogs_AddEvents_Columns_List_End=End event type +LatencyView_Dialogs_AddEvents_Errors_NoSelection=You must select one item from both lists_ +LatencyView_Dialogs_AddEvents_Errors_StartNotSelected=You must select one item from the start event list_ +LatencyView_Dialogs_AddEvents_Errors_EndNotSelected=You must select one item from the end event list_ +LatencyView_Dialogs_AddEvents_Errors_SameSelected=The same event cannot be selected in both list at the same time_ +LatencyView_Dialogs_AddEvents_Errors_AlreadyMatched=The start and end events are already matched_ +LatencyView_Dialogs_AddEvents_Errors_StartAlreadyMatched=The start event is already matched_ +LatencyView_Dialogs_AddEvents_Errors_EndAlreadyMatched=The end event is already matched_ +LatencyView_Dialogs_AddEvents_Errors_StartAsEnd=The start event is already matched as an end event_ +LatencyView_Dialogs_AddEvents_Errors_EndAsStart=The end event is already matched as a start event_ +LatencyView_Dialogs_DeleteEvents_Title=Delete event pairs +LatencyView_Dialogs_DeleteEvents_Message=Select a pair of matched events to remove it from the list : +LatencyView_Dialogs_DeleteEvents_Buttons_Close=Close +LatencyView_Dialogs_DeleteEvents_Buttons_Delete=Delete +LatencyView_Dialogs_DeleteEvents_Confirm_Title=Confirm event deletion +LatencyView_Dialogs_DeleteEvents_Confirm_Message=Are you sure you want to delete these event pairs? +LatencyView_Dialogs_ListEvents_Title=Matched events list +LatencyView_Dialogs_ListEvents_Message=List of matched events for latency computation : +LatencyView_Dialogs_ListEvents_Buttons_Close=Close +LatencyView_Dialogs_ListEvents_Buttons_Reset=Reset to default pairs +LatencyView_Dialogs_ListEvents_Columns_Trigger=Trigger event type +LatencyView_Dialogs_ListEvents_Columns_End=End event type +LatencyView_Dialogs_ListEvents_Confirm_Title=Confirm pairs reset +LatencyView_Dialogs_ListEvents_Confirm_Message=Are you sure you want to reset the event pairs to their default values? +LatencyView_Graphs_Graph_Title=Latency vs Time +LatencyView_Graphs_Graph_XAxisLabel=time (s) +LatencyView_Graphs_Graph_YAxisLabel=latency (ms) +LatencyView_Graphs_Histogram_Title=Latency Distribution +LatencyView_Graphs_Histogram_XAxisLabel=latency (ms) +LatencyView_Graphs_Histogram_YAxisLabel=# events +LatencyView_msgSlogan=Latency View +LatencyView_tmf_UI=org.eclipse.linuxtools.lttng.ui +LatencyView_ClippingWarning=One or more bars are higher than the drawing area due to zooming \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/Config.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/Config.java new file mode 100644 index 0000000000..e2d77ead64 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/Config.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation + * Mathieu Denis (mathieu.denis55@gmail.com) - Refactor code + * Bernd Hufmann - Added and updated constants + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.model; + +/** + * Config + *

    + * Configuration class, holds some application constants. + * + * @author Philippe Sawicki + */ +public class Config { + + /** + * Private constructor to defeat instantiation. + */ + private Config() { + } + + /** + * Time scale for TMF events; + */ + public static byte TIME_SCALE = -9; + + /** + * Size of the point buffer holding point values before sending them to the view. + */ + public static final int POINT_BUFFER_SIZE = 10000; + + /** + * Histogram bar width. + */ + public static final int DEFAULT_HISTOGRAM_BAR_WIDTH = 2; + + /** + * Histogram bar width increase step. + */ + public static final int MIN_HISTOGRAM_BAR_WIDTH = 1; + + /** + * Histogram bar width increase step. + */ + public static final int MAX_HISTOGRAM_BAR_WIDTH = 16; + + + /** + * Diameter of a point drawn on the chart (in pixels). + */ + public static final int GRAPH_POINT_DIAMETER = 1; + + /** + * Graph padding. + */ + public static final int GRAPH_PADDING = 10; + + /** + * Default number of buckets used in data models + */ + public static final int DEFAULT_NUMBER_OF_BUCKETS = 2 * 1000; + + /** + * Invalid event time + */ + public static final long INVALID_EVENT_TIME = -1; +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/GraphScaledData.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/GraphScaledData.java new file mode 100644 index 0000000000..d41e684eaf --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/GraphScaledData.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.model; + +/** + * GraphScaledData + * Convenience class for scaled distribution data. + *

    + */ +import java.util.Arrays; + +import org.eclipse.linuxtools.lttng.ui.views.distribution.model.BaseDistributionData; + +public class GraphScaledData { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + private int fWidth; + private int fHeight; + private int fBarWidth; + private int[][] fData; + private BaseDistributionData fHorDistributionData; + private BaseDistributionData fVerDistributionData; + private long fCurrentEventTime; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + public GraphScaledData(int width, int height, int barWidth) { + fWidth = width; + fHeight = height; + fBarWidth = barWidth; + int horNbBuckets = (int)width/barWidth; + int verNbBuckets = (int)height/barWidth; + fData = new int[horNbBuckets][verNbBuckets]; + for (int[] row : fData) { + Arrays.fill(row, 0); + } + fHorDistributionData = new BaseDistributionData(horNbBuckets); + fHorDistributionData.clear(); + + fVerDistributionData = new BaseDistributionData(verNbBuckets); + fVerDistributionData.clear(); + + fCurrentEventTime = Config.INVALID_EVENT_TIME; + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + public int getWidth() { + return fWidth; + } + + public int getHeight() { + return fHeight; + } + + public int getBarWidth() { + return fBarWidth; + } + + public int[][] getData() { + return fData; + } + + public int getHorNbBuckets() { + return fHorDistributionData.getNbBuckets(); + } + + public int getVerNbBuckets() { + return fVerDistributionData.getNbBuckets(); + } + + public long getHorFirstBucketTime() { + return fHorDistributionData.getFirstBucketTime(); + } + + public long getVerFirstBucketTime() { + return fVerDistributionData.getFirstBucketTime(); + } + + public long getHorLastBucketTime() { + return fHorDistributionData.getLastBucketTime(); + } + + public long getVerLastBucketTime() { + return fVerDistributionData.getLastBucketTime(); + } + + public long getHorFirstEventTime() { + return fHorDistributionData.getFirstEventTime(); + } + + public long getVerFirstEventTime() { + return fVerDistributionData.getFirstEventTime(); + } + + public long getHorLastEventTime() { + return fHorDistributionData.getLastEventTime(); + } + + public long getVerLastEventTime() { + return fVerDistributionData.getLastEventTime(); + } + + public long getHorBucketDuration() { + return fHorDistributionData.getBucketDuration(); + } + + public long getVerBucketDuration() { + return fVerDistributionData.getBucketDuration(); + } + + public int getHorLastBucket() { + return fHorDistributionData.getLastBucket(); + } + + public int getVerLastBucket() { + return fVerDistributionData.getLastBucket(); + } + + public long getHorBucketStartTime(int index) { + return fHorDistributionData.getBucketStartTime(index); + } + + public long getHorBucketEndTime(int index) { + return fHorDistributionData.getBucketEndTime(index); + } + + public long getVerBucketStartTime(int index) { + return fVerDistributionData.getBucketStartTime(index); + } + + public long getVerBucketEndTime(int index) { + return fVerDistributionData.getBucketEndTime(index); + } + + public int getEventCount(int horIndex, int verIndex) { + return fData[horIndex][verIndex]; + } + + public long getCurrentEventTime() { + return fCurrentEventTime; + } + + public boolean isCurrentEventTimeValid() { + if (fCurrentEventTime == Config.INVALID_EVENT_TIME || fCurrentEventTime < getHorFirstEventTime() || fCurrentEventTime > getHorLastEventTime()) { + return false; + } + return true; + } + + public int getHorBucketIndex(long time) { + return fHorDistributionData.getIndex(time); + } + + public int getVerBucketIndex(long time) { + return fVerDistributionData.getIndex(time); + } + + public boolean isHorIndexValid(int index) { + return fHorDistributionData.isIndexValid(index); + } + + public boolean isVerIndexValid(int index) { + return fVerDistributionData.isIndexValid(index); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + public void setWidth(int width) { + fWidth = width; + } + + public void setHeight(int height) { + fHeight = height; + } + + public void setBarWidth(int barWidth) { + fBarWidth = barWidth; + } + + public void setData(int[][] data) { + fData = data; + } + + public void setHorFirstBucketTime(long firstBucketTime) { + fHorDistributionData.setFirstBucketTime(firstBucketTime); + } + + public void setVerFirstBucketTime(long firstBucketTime) { + fVerDistributionData.setFirstBucketTime(firstBucketTime); + } + + public void setHorFirstEventTime(long firstEventTime) { + fHorDistributionData.setFirstEventTime(firstEventTime); + } + + public void setVerFirstEventTime(long firstEventTime) { + fVerDistributionData.setFirstEventTime(firstEventTime); + } + + public void setHorLastEventTime(long lastEventTime) { + fHorDistributionData.setLastEventTime(lastEventTime); + } + + public void setVerLastEventTime(long lastEventTime) { + fVerDistributionData.setLastEventTime(lastEventTime); + } + + public void setHorBucketDuration(long bucketDuration) { + fHorDistributionData.setBucketDuration(bucketDuration); + } + + public void setVerBucketDuration(long bucketDuration) { + fVerDistributionData.setBucketDuration(bucketDuration); + } + + public void setHorLastBucket(int lastBucket) { + fHorDistributionData.setLastBucket(lastBucket); + } + + public void setVerLastBucket(int lastBucket) { + fVerDistributionData.setLastBucket(lastBucket); + } + + public void setCurrentEventTime(long currentEventTime) { + fCurrentEventTime = currentEventTime; + } +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/IGraphDataModel.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/IGraphDataModel.java new file mode 100644 index 0000000000..182004bbb5 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/IGraphDataModel.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.lttng.ui.views.latency.model; + +import org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDistributionModel; + +/** + * IGraphDataModel + *

    + */ +public interface IGraphDataModel extends IBaseDistributionModel { + + /** + * Add event to the correct bucket, compacting the if needed. + * + * @param eventCount - the event count + * @param timestamp - the timestamp (x-coordinate) of the event to count + * @param time - the time (y-coordinate) of the event to count + */ + public void countEvent(int eventCount, long timestamp, long time); + + /** + * Scale the model data to the width and height requested. + * + * @param width - width of graph + * @param height - height of graph + * @param barWidth - width of bar + * @return the result array of size [width] and where the highest value + * doesn't exceed [height] + */ + public GraphScaledData scaleTo(int width, int height, int barWidth); +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/IGraphModelListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/IGraphModelListener.java new file mode 100644 index 0000000000..b6643991a3 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/IGraphModelListener.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.latency.model; + +/** + * IGraphModelListener + *

    + */ +public interface IGraphModelListener { + + /** + * Method to notify listeners about model updates + */ + public void graphModelUpdated(); + + /** + * Method to inform listeners about current time updates + */ + public void currentEventUpdated(long currentEventTime); + +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyController.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyController.java new file mode 100644 index 0000000000..fa212d3fc1 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyController.java @@ -0,0 +1,189 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.latency.model; + +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDistributionModel; +import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramDataModel; +import org.eclipse.linuxtools.tmf.core.component.TmfEventProvider; +import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange; +import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest; +import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest.ExecutionType; + +/** + * LatencyController + *

    + */ +public class LatencyController { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + private static LatencyController fInstance = null; + + private LatencyEventRequest fEventRequest; + + private TmfEventProvider fProvider; + + private final ListenerList fModels; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + private LatencyController() { + fModels = new ListenerList(); + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + public static LatencyController getInstance() { + if (fInstance == null) { + fInstance = new LatencyController(); + } + return fInstance; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /** + * Refresh all registered models + * + * @param provider - TmfEventProvider to request data from + * @param timeRange - time range of request + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void refreshModels(TmfEventProvider provider, TmfTimeRange timeRange) { + // save provider + fProvider = provider; + if (fProvider != null) { + if (fEventRequest != null && !fEventRequest.isCompleted()) { + fEventRequest.cancel(); + } + clear(); + fEventRequest = new LatencyEventRequest(this, timeRange, ExecutionType.FOREGROUND); + fProvider.sendRequest((TmfDataRequest)fEventRequest); + } + } + + /** + * Refreshes registered models by re-sending previous request to saved provider + */ + public void refreshModels() { + if (fProvider != null && fEventRequest != null) { + refreshModels(fProvider, fEventRequest.getRange()); + } + } + + /** + * Clear all models + */ + public void clear() { + Object models[] = fModels.getListeners(); + + for (int i = 0; i < models.length; i++) { + ((IBaseDistributionModel)models[i]).clear(); + } + } + + /** + * Dispose of controller + */ + public void dispose() { + if (fEventRequest != null && !fEventRequest.isCompleted()) { + fEventRequest.cancel(); + } + fProvider = null; + } + + /** + * Register given model. + * @param model - model to register + */ + public void registerModel(IBaseDistributionModel model) { + fModels.add(model); + } + + /** + * Deregister given model. + * + * @param model - model to deregister + */ + public void deregisterModel(IBaseDistributionModel model) { + fModels.remove(model); + } + + /** + * Handle data of event request and pass it information to the registered models + * + * @param eventCount - event count + * @param timestamp - start timestamp of latency calculation + * @param latency - latency value (startTimestamp - endTimestamp) + */ + public void handleData(int eventCount, long timestamp, long latency) { + Object[] models = fModels.getListeners(); + for (int i = 0; i < models.length; i++) { + IBaseDistributionModel model = (IBaseDistributionModel)models[i]; + if (model instanceof IHistogramDataModel) { + ((IHistogramDataModel)model).countEvent(eventCount, latency); + } else if (model instanceof IGraphDataModel) { + ((IGraphDataModel)model).countEvent(eventCount, timestamp, latency); + } + } + } + + /** + * Handle complete indication from request. + */ + public void handleCompleted() { + Object[] models = fModels.getListeners(); + for (int i = 0; i < models.length; i++) { + ((IBaseDistributionModel)models[i]).complete(); + } + } + + /** + * Handle cancel indication from request. + */ + public void handleCancel() { + clear(); + } + + /** + * Set event provider for refresh. + * + * @param provider + */ + public void setEventProvider(TmfEventProvider provider) { + fProvider = provider; + } + + /** + * Set current event time in model(s). + * + * @param timestamp + */ + public void setCurrentEventTime(long timestamp) { + Object[] models = fModels.getListeners(); + for (int i = 0; i < models.length; i++) { + IBaseDistributionModel model = (IBaseDistributionModel)models[i]; + if (model instanceof LatencyGraphModel) { + ((LatencyGraphModel)model).setCurrentEventNotifyListeners(timestamp); + } + } + } +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyEventRequest.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyEventRequest.java new file mode 100644 index 0000000000..d871ecb4fa --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyEventRequest.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.latency.model; + +import org.eclipse.linuxtools.lttng.core.LttngConstants; +import org.eclipse.linuxtools.lttng.core.event.LttngEvent; +import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher; +import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange; +import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest; +import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest; + +/** + * LatencyEventRequest + *

    + */ +public class LatencyEventRequest extends TmfEventRequest { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + final private LatencyController fController; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + public LatencyEventRequest(LatencyController controller, TmfTimeRange range, int rank, int nbEvents, ITmfDataRequest.ExecutionType execType) { + super(LttngEvent.class, range, rank, nbEvents, LttngConstants.DEFAULT_BLOCK_SIZE, execType); + fController = controller; + EventMatcher.getInstance().clearStack(); + } + + public LatencyEventRequest(LatencyController controller, TmfTimeRange range, ITmfDataRequest.ExecutionType execType) { + this(controller, range, 0, ALL_DATA, execType); + } + + public LatencyEventRequest(LatencyController controller, TmfTimeRange range, int rank, ITmfDataRequest.ExecutionType execType) { + this(controller, range, rank, ALL_DATA, execType); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.tmf.request.TmfDataRequest#handleData(org.eclipse.linuxtools.tmf.event.TmfData) + */ + @Override + public void handleData(LttngEvent event) { + super.handleData(event); + + LttngEvent startEvent = EventMatcher.getInstance().process(event); + + if (startEvent != null) { + long latency = event.getTimestamp().getValue() - startEvent.getTimestamp().getValue(); + fController.handleData(getNbRead(), startEvent.getTimestamp().getValue(), latency); + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.tmf.request.TmfDataRequest#handleCompleted() + */ + @Override + public void handleCompleted() { + fController.handleCompleted(); + super.handleCompleted(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.tmf.request.TmfDataRequest#handleCancel() + */ + @Override + public void handleCancel() { + EventMatcher.getInstance().clearStack(); + fController.handleCancel(); + super.handleCancel(); + } +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyGraphModel.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyGraphModel.java new file mode 100644 index 0000000000..399379f2da --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyGraphModel.java @@ -0,0 +1,380 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Bernd Hufmann - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.latency.model; + +import java.util.Arrays; +import java.util.concurrent.locks.ReentrantLock; + +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.linuxtools.lttng.ui.views.distribution.model.DistributionData; +import org.eclipse.linuxtools.lttng.ui.views.distribution.model.HorDistributionData; +import org.eclipse.linuxtools.lttng.ui.views.distribution.model.VerDistributionData; + +/** + * LatencyGraphModel + *

    + */ +public class LatencyGraphModel implements IGraphDataModel { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + private final int fNbBuckets; + private final int [][] fBuckets; + private final DistributionData fHorDistributionData; + private final DistributionData fVerDistributionData; + private long fCurrentEventTime; + + // private listener lists + private final ListenerList fModelListeners; + + private final ReentrantLock fLock; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + public LatencyGraphModel() { + this(Config.DEFAULT_NUMBER_OF_BUCKETS); + } + + public LatencyGraphModel(int nbBuckets) { + fNbBuckets = nbBuckets; + fBuckets = new int[nbBuckets][nbBuckets]; + fHorDistributionData = new HorDistributionData(nbBuckets, fBuckets); + fVerDistributionData = new VerDistributionData(nbBuckets, fBuckets); + fCurrentEventTime = Config.INVALID_EVENT_TIME; + + fModelListeners = new ListenerList(); + fLock = new ReentrantLock(); + clear(); + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + public int getNbBuckets() { + return fNbBuckets; + } + + public long getHorBucketDuration() { + fLock.lock(); + try { + return fHorDistributionData.getBucketDuration(); + } finally { + fLock.unlock(); + } + } + + public long getVerBucketDuration() { + fLock.lock(); + try { + return fVerDistributionData.getBucketDuration(); + } finally { + fLock.unlock(); + } + } + + public long getHorFirstBucketTime() { + fLock.lock(); + try { + return fHorDistributionData.getFirstBucketTime(); + } finally { + fLock.unlock(); + } + } + + public long getVerFirstBucketTime() { + fLock.lock(); + try { + return fVerDistributionData.getFirstBucketTime(); + } finally { + fLock.unlock(); + } + } + + public long getHorFirstEventTime() { + fLock.lock(); + try { + return fHorDistributionData.getFirstEventTime(); + } finally { + fLock.unlock(); + } + } + + public long getVerFirstEventTime() { + fLock.lock(); + try { + return fVerDistributionData.getFirstEventTime(); + } finally { + fLock.unlock(); + } + } + + public long getHorLastEventTime() { + fLock.lock(); + try { + return fHorDistributionData.getLastEventTime(); + } finally { + fLock.unlock(); + } + } + + public long getVerLastEventTime() { + fLock.lock(); + try { + return fVerDistributionData.getLastEventTime(); + } finally { + fLock.unlock(); + } + } + + public long getHorTimeLimit() { + fLock.lock(); + try { + return fHorDistributionData.getTimeLimit(); + } finally { + fLock.unlock(); + } + } + + public long getVerTimeLimit() { + fLock.lock(); + try { + return fVerDistributionData.getTimeLimit(); + } finally { + fLock.unlock(); + } + } + + public int getHorLastBucket() { + fLock.lock(); + try { + return fHorDistributionData.getLastBucket(); + } finally { + fLock.unlock(); + } + } + + public int getVerLastBucket() { + fLock.lock(); + try { + return fVerDistributionData.getLastBucket(); + } finally { + fLock.unlock(); + } + } + + public long getCurrentEventTime() { + fLock.lock(); + try { + return fCurrentEventTime; + } finally { + fLock.unlock(); + } + } + + // ------------------------------------------------------------------------ + // Listener interface + // ------------------------------------------------------------------------ + public void addGraphModelListener(IGraphModelListener listener) { + fModelListeners.add(listener); + } + + public void removeGraphModelListener(IGraphModelListener listener) { + fModelListeners.remove(listener); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDataModel#clear() + */ + @Override + public void clear() { + fLock.lock(); + try { + for (int[] row : fBuckets) { + Arrays.fill(row, 0, fNbBuckets, 0); + } + fHorDistributionData.clear(); + fVerDistributionData.clear(); + } finally { + fLock.unlock(); + } + fireModelUpdateNotification(); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphDataModel#countEvent(int, long, long) + */ + @Override + public void countEvent(int eventCount, long timestamp, long time) { + fLock.lock(); + try { + int horIndex = fHorDistributionData.countEvent(timestamp); + int verIndex = fVerDistributionData.countEvent(time); + + fBuckets[horIndex][verIndex]++; + } finally { + fLock.unlock(); + } + + fireModelUpdateNotification(eventCount); + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphDataModel#scaleTo(int, int, int) + */ + @Override + public GraphScaledData scaleTo(int width, int height, int barWidth) { + GraphScaledData scaledData = new GraphScaledData(width, height, barWidth); + fLock.lock(); + try { + if (!fHorDistributionData.isFirst() && !fVerDistributionData.isFirst() ) { + + // Basic validation + if (width <= 0 || height <= 0 || barWidth <= 0) + throw new AssertionError("Invalid histogram dimensions (" + width + "x" + height + ", barWidth=" + barWidth + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$ + + // Scale horizontally + int nbBars = width / barWidth; + int bucketsPerBar = fHorDistributionData.getLastBucket() / nbBars + 1; + + int horData[][] = new int[nbBars][fNbBuckets]; + for (int y = 0; y < fNbBuckets; y++) { + for (int i = 0; i < nbBars; i++) { + int count = 0; + for (int j = i * bucketsPerBar; j < (i + 1) * bucketsPerBar; j++) { + if (fNbBuckets <= j) + break; + count += fBuckets[j][y]; + } + horData[i][y] = count; + } + } + + // Scale vertically + int nbVerBars = height / barWidth; + int bucketsPerVerBar = fVerDistributionData.getLastBucket() / nbVerBars + 1; + + int verData[][] = new int[nbBars][nbVerBars]; + for (int x = 0; x < nbBars; x++) { + for (int i = 0; i < nbVerBars; i++) { + int count = 0; + for (int j = i * bucketsPerVerBar; j < (i + 1) * bucketsPerVerBar; j++) { + if (fNbBuckets <= j) + break; + count += horData[x][j]; + } + verData[x][i] = count; + } + } + + scaledData.setData(verData); + scaledData.setHorFirstBucketTime(fHorDistributionData.getFirstBucketTime()); + scaledData.setVerFirstBucketTime(fVerDistributionData.getFirstBucketTime()); + scaledData.setHorFirstEventTime(fHorDistributionData.getFirstEventTime()); + scaledData.setVerFirstEventTime(fVerDistributionData.getFirstEventTime()); + scaledData.setHorLastEventTime(fHorDistributionData.getLastEventTime()); + scaledData.setVerLastEventTime(fVerDistributionData.getLastEventTime()); + scaledData.setHorBucketDuration(bucketsPerBar * fHorDistributionData.getBucketDuration()); + scaledData.setVerBucketDuration(bucketsPerVerBar * fVerDistributionData.getBucketDuration()); + scaledData.setHorLastBucket(fHorDistributionData.getLastBucket() / bucketsPerBar); + scaledData.setVerLastBucket(fVerDistributionData.getLastBucket() / bucketsPerVerBar); + scaledData.setCurrentEventTime(fCurrentEventTime); + } + } finally { + fLock.unlock(); + } + + return scaledData; + } + + /* + * (non-Javadoc) + * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDataModel#complete() + */ + @Override + public void complete() { + fireModelUpdateNotification(); + } + + /** + * Sets the current event time but don't notify listeners. + * + * @param timestamp + */ + public void setCurrentEvent(long timestamp) { + fLock.lock(); + try { + fCurrentEventTime = timestamp; + } finally { + fLock.unlock(); + } + } + + /** + * Sets the current event time and notify listeners. + * + * @param timestamp + */ + public void setCurrentEventNotifyListeners(long timestamp) { + fLock.lock(); + try { + fCurrentEventTime = timestamp; + } finally { + fLock.unlock(); + } + fireCurrentEventUpdateNotification(); + } + + // ------------------------------------------------------------------------ + // Helper functions + // ------------------------------------------------------------------------ + + /* + * Notify listeners immediately + */ + private void fireModelUpdateNotification() { + fireModelUpdateNotification(0); + } + + /* + * Notify listeners with certain refresh rate. + */ + private void fireModelUpdateNotification(int count) { + if (count % Config.POINT_BUFFER_SIZE == 0) { + Object[] listeners = fModelListeners.getListeners(); + for (int i = 0; i < listeners.length; i++) { + IGraphModelListener listener = (IGraphModelListener) listeners[i]; + listener.graphModelUpdated(); + } + } + } + + /* + * Notify listeners immediately + */ + private void fireCurrentEventUpdateNotification() { + Object[] listeners = fModelListeners.getListeners(); + for (int i = 0; i < listeners.length; i++) { + IGraphModelListener listener = (IGraphModelListener) listeners[i]; + listener.currentEventUpdated(fCurrentEventTime); + } + } +}