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,
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
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse\r
+ * Public License v1.0 which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors: \r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.core.latency.analyzer;\r
+\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Map.Entry;\r
+import java.util.Set;\r
+import java.util.Stack;\r
+import java.util.Vector;\r
+\r
+import org.eclipse.linuxtools.lttng.core.event.LttngEvent;\r
+import org.eclipse.linuxtools.lttng.core.util.EventsPair;\r
+\r
+/**\r
+ * <b><u>EventMatcher</u></b>\r
+ * <p>\r
+ * Event matching class. Saves events in a list and returns the previously saved event if the currently processed one is\r
+ * its response, so that the latency can be computed by subtracting their respective timestamps.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class EventMatcher {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Class instance (Singleton pattern).\r
+ */\r
+ private static EventMatcher fInstance = null;\r
+\r
+ /**\r
+ * Stack abstraction, used to save the events in a list.\r
+ */\r
+ private StackWrapper fStack;\r
+\r
+ /**\r
+ * Match table, associates a request class to a response class.\r
+ */\r
+ private HashMap<String, String> fMatch;\r
+ /**\r
+ * Inverse match table, associates a response class to a request class.\r
+ */\r
+ private HashMap<String, String> fInverseMatch;\r
+\r
+ /**\r
+ * The number of events processed.\r
+ */\r
+ private int fProcessedEvents;\r
+ /**\r
+ * The number of events matched.\r
+ */\r
+ private int fMatchedEvents;\r
+ \r
+ /**\r
+ * Event types identification Strings.\r
+ */\r
+ @SuppressWarnings("nls")\r
+ public static String\r
+ ADD_TO_PAGE_CACHE = "add_to_page_cache",\r
+ BIO_BACKMERGE = "bio_backmerge",\r
+ BIO_FRONTMERGE = "bio_frontmerge",\r
+ BIO_QUEUE = "bio_queue",\r
+ BUFFER_WAIT_END = "buffer_wait_end",\r
+ BUFFER_WAIT_START = "buffer_wait_start",\r
+ CALL = "call",\r
+ CLOSE = "close",\r
+ CORE_MARKER_FORMAT = "core_marker_format",\r
+ CORE_MARKER_ID = "core_marker_id",\r
+ DEV_RECEIVE = "dev_receive",\r
+ DEV_XMIT = "dev_xmit",\r
+ END_COMMIT = "end_commit",\r
+ EXEC = "exec",\r
+ FILE_DESCRIPTOR = "file_descriptor",\r
+ GETRQ = "getrq",\r
+ GETRQ_BIO = "getrq_bio",\r
+ IDT_TABLE = "idt_table",\r
+ INTERRUPT = "interrupt",\r
+ IOCTL = "ioctl",\r
+ IRQ_ENTRY = "irq_entry",\r
+ IRQ_EXIT = "irq_exit",\r
+ LIST_MODULE = "list_module",\r
+ LLSEEK = "llseek",\r
+ LSEEK = "lseek",\r
+ NAPI_COMPLETE = "napi_complete",\r
+ NAPI_POLL = "napi_poll",\r
+ NAPI_SCHEDULE = "napi_schedule",\r
+ NETWORK_IPV4_INTERFACE = "network_ipv4_interface",\r
+ NETWORK_IP_INTERFACE = "network_ip_interface",\r
+ OPEN = "open",\r
+ PAGE_FAULT_ENTRY = "page_fault_entry",\r
+ PAGE_FAULT_EXIT = "page_fault_exit",\r
+ PAGE_FAULT_GET_USER_ENTRY = "page_fault_get_user_entry",\r
+ PAGE_FAULT_GET_USER_EXIT = "page_fault_get_user_exit",\r
+ PAGE_FREE = "page_free",\r
+ PLUG = "plug",\r
+ POLLFD = "pollfd",\r
+ PREAD64 = "pread64",\r
+ PRINTF = "printf",\r
+ PRINTK = "printk",\r
+ PROCESS_EXIT = "process_exit",\r
+ PROCESS_FORK = "process_fork",\r
+ PROCESS_FREE = "process_free",\r
+ PROCESS_STATE = "process_state",\r
+ PROCESS_WAIT = "process_wait",\r
+ READ = "read",\r
+ REMAP = "remap",\r
+ REMOVE_FROM_PAGE_CACHE = "remove_from_page_cache",\r
+ RQ_COMPLETE_FS = "rq_complete_fs",\r
+ RQ_COMPLETE_PC = "rq_complete_pc",\r
+ RQ_INSERT_FS = "rq_insert_fs",\r
+ RQ_INSERT_PC = "rq_insert_pc",\r
+ RQ_ISSUE_FS = "rq_issue_fs",\r
+ RQ_ISSUE_PC = "rq_issue_pc",\r
+ RQ_REQUEUE_PC = "rq_requeue_pc",\r
+ SCHED_MIGRATE_TASK = "sched_migrate_task",\r
+ SCHED_SCHEDULE = "sched_schedule",\r
+ SCHED_TRY_WAKEUP = "sched_try_wakeup",\r
+ SCHED_WAKEUP_NEW_TASK = "sched_wakeup_new_task",\r
+ SELECT = "select",\r
+ SEM_CREATE = "sem_create",\r
+ SEND_SIGNAL = "send_signal",\r
+ SHM_CREATE = "shm_create",\r
+ SLEEPRQ_BIO = "sleeprq_bio",\r
+ SOCKET_ACCEPT = "socket_accept",\r
+ SOCKET_BIND = "socket_bind",\r
+ SOCKET_CALL = "socket_call",\r
+ SOCKET_CONNECT = "socket_connect",\r
+ SOCKET_CREATE = "socket_create",\r
+ SOCKET_GETPEERNAME = "socket_getpeername",\r
+ SOCKET_GETSOCKNAME = "socket_getsockname",\r
+ SOCKET_GETSOCKOPT = "socket_getsockopt",\r
+ SOCKET_LISTEN = "socket_listen",\r
+ SOCKET_SETSOCKOPT = "socket_setsockopt",\r
+ SOCKET_SHUTDOWN = "socket_shutdown",\r
+ SOCKET_SOCKETPAIR = "socket_socketpair",\r
+ SOFTIRQ_ENTRY = "softirq_entry",\r
+ SOFTIRQ_EXIT = "softirq_exit",\r
+ SOFTIRQ_RAISE = "softirq_raise",\r
+ SOFTIRQ_VEC = "softirq_vec",\r
+ START_COMMIT = "start_commit",\r
+ STATEDUMP_END = "statedump_end",\r
+ SYS_CALL_TABLE = "sys_call_table",\r
+ SYSCALL_ENTRY = "syscall_entry",\r
+ SYSCALL_EXIT = "syscall_exit",\r
+ TASKLET_LOW_ENTRY = "tasklet_low_entry",\r
+ TASKLET_LOW_EXIT = "tasklet_low_exit",\r
+ TCPV4_RCV = "tcpv4_rcv",\r
+ TIMER_ITIMER_EXPIRED = "timer_itimer_expired",\r
+ TIMER_ITIMER_SET = "timer_itimer_set",\r
+ TIMER_SET = "timer_set",\r
+ TIMER_TIMEOUT = "timer_timeout",\r
+ TIMER_UPDATE_TIME = "timer_update_time",\r
+ UDPV4_RCV = "udpv4_rcv",\r
+ UNPLUG_IO = "unplug_io",\r
+ UNPLUG_TIMER = "unplug_timer",\r
+ VM_MAP = "vm_map",\r
+ VPRINTK = "vprintk",\r
+ WAIT_ON_PAGE_END = "wait_on_page_end",\r
+ WAIT_ON_PAGE_START = "wait_on_page_start",\r
+ WRITE = "write",\r
+ WRITEV = "writev";\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructor\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Private constructor to defeat instantiation (Singleton pattern).\r
+ */\r
+ private EventMatcher() {\r
+ fStack = new StackWrapper();\r
+ fMatch = new HashMap<String, String>();\r
+ fInverseMatch = new HashMap<String, String>();\r
+\r
+ fProcessedEvents = 0;\r
+ fMatchedEvents = 0;\r
+\r
+ createMatchTable();\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Accessors\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Returns an instance to the EventMatcher class (Singleton pattern).\r
+ * @return An instance to the EventMatcher class (Singleton pattern).\r
+ */\r
+ public static EventMatcher getInstance() {\r
+ if (fInstance == null)\r
+ fInstance = new EventMatcher();\r
+ return fInstance;\r
+ }\r
+\r
+ /**\r
+ * Returns the number of events processed.\r
+ * @return The number of events processed.\r
+ */\r
+ public int getNBProcessedEvents() {\r
+ return fProcessedEvents;\r
+ }\r
+\r
+ /**\r
+ * Returns the number of events matched.\r
+ * @return The number of events matched.\r
+ */\r
+ public int getNBMatchedEvents() {\r
+ return fMatchedEvents;\r
+ }\r
+ \r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Releases the instance to the EventMatcher class.\r
+ */\r
+ public static void releaseInstance() {\r
+ fInstance = null;\r
+ }\r
+\r
+ /**\r
+ * Creates the event matching table, linking a response class to a request class.\r
+ */\r
+ private void createMatchTable() {\r
+ // Build the default matches\r
+ fMatch.put(PAGE_FAULT_GET_USER_EXIT, PAGE_FAULT_GET_USER_ENTRY);\r
+ fMatch.put(TASKLET_LOW_EXIT, TASKLET_LOW_ENTRY);\r
+ fMatch.put(PAGE_FAULT_EXIT, PAGE_FAULT_ENTRY);\r
+ fMatch.put(SYSCALL_EXIT, SYSCALL_ENTRY);\r
+ fMatch.put(IRQ_EXIT, IRQ_ENTRY);\r
+ fMatch.put(WRITE, READ);\r
+ fMatch.put(CLOSE, OPEN);\r
+ fMatch.put(BUFFER_WAIT_END, BUFFER_WAIT_START);\r
+ fMatch.put(END_COMMIT, START_COMMIT);\r
+ fMatch.put(WAIT_ON_PAGE_END, WAIT_ON_PAGE_START);\r
+\r
+ // Build the inverse matches based on the matches\r
+ Set<Entry<String, String>> pairs = fMatch.entrySet();\r
+ Iterator<Entry<String, String>> it = pairs.iterator();\r
+ while (it.hasNext()) {\r
+ Entry<String, String> pair = it.next();\r
+ fInverseMatch.put(pair.getValue(), pair.getKey());\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Processes an event received: if it is identified as a response, try to get its request to remove it from the\r
+ * list. If no request was saved, dismiss the current response. If it is a request, save it to the list of requests\r
+ * waiting for a response.\r
+ * @param event\r
+ * The event to identify, and maybe process if it is a response.\r
+ * @return The request event associated with the current event (a response), or null if nothing was found (no\r
+ * request associated with this response, or the event to identify was a request that was added to the\r
+ * list).\r
+ */\r
+ public LttngEvent process(LttngEvent event) {\r
+ fProcessedEvents++;\r
+\r
+ String markerName = event.getMarkerName();\r
+ if (fMatch.containsKey(markerName)) {\r
+ String startEventType = fMatch.get(markerName);\r
+ Stack<LttngEvent> events = fStack.getStackOf(startEventType);\r
+ \r
+ if (events != null) {\r
+ for (int i = events.size() - 1; i >= 0; i--) {\r
+ LttngEvent request = events.get(i);\r
+\r
+ if (request.getCpuId() == event.getCpuId() && event.getTimestamp().getValue() > request.getTimestamp().getValue()) {\r
+ fStack.removeEvent(startEventType, request);\r
+ fMatchedEvents++;\r
+ return request;\r
+ }\r
+ }\r
+ }\r
+ return null;\r
+ } else {\r
+ // Add only if there can later be a match for this request\r
+ if (fMatch.containsValue(event.getMarkerName())) {\r
+ fStack.put(event.clone());\r
+ }\r
+ return null;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Clears the stack content.\r
+ */\r
+ public void clearStack() {\r
+ fStack.clear();\r
+\r
+ // Reset the processed and matched events counter\r
+ fProcessedEvents = 0;\r
+ fMatchedEvents = 0;\r
+ }\r
+\r
+ /**\r
+ * Resets all.\r
+ */\r
+ public void resetMatches() {\r
+ fMatch.clear();\r
+ fInverseMatch.clear();\r
+\r
+ fStack.clear();\r
+\r
+ // Reset the processed and matched events counter\r
+ fProcessedEvents = 0;\r
+ fMatchedEvents = 0;\r
+ }\r
+\r
+ /**\r
+ * Returns the list of start events.\r
+ * @return The list of start events.\r
+ */\r
+ public Collection<String> getStartEvents() {\r
+ return fMatch.values();\r
+ }\r
+\r
+ /**\r
+ * Returns the list of end events.\r
+ * @return The list of end events.\r
+ */\r
+ public Set<String> getEndEvents() {\r
+ return fMatch.keySet();\r
+ }\r
+\r
+ /**\r
+ * Returns the alphabetically-sorted list of start/end events pairs.\r
+ * @return The alphabetically-sorted list of start/end events pairs.\r
+ */\r
+ public EventsPair getEvents() {\r
+ Vector<String> start = new Vector<String>(getStartEvents());\r
+ Vector<String> end = new Vector<String>(fMatch.size());\r
+\r
+ Collections.sort(start);\r
+ for (int i = 0; i < start.size(); i++) {\r
+ end.add(fInverseMatch.get(start.get(i)));\r
+ }\r
+ return new EventsPair(start, end);\r
+ }\r
+\r
+ /**\r
+ * Adds a match to the list of events pairs.\r
+ * @param startType\r
+ * The start event type.\r
+ * @param endType\r
+ * The end event type.\r
+ */\r
+ public void addMatch(String startType, String endType) {\r
+ fMatch.put(endType, startType);\r
+ fInverseMatch.put(startType, endType);\r
+ }\r
+\r
+ /**\r
+ * Removes a matched pair based on the their type.\r
+ * \r
+ * <b>Note :</b> For now, only the pair's end type is used, since a type can only be either one start or one end.\r
+ * This function takes both types to account for the future, if a pairing process ever becomes more complex.\r
+ * \r
+ * @param startType\r
+ * The type of the pair's start type.\r
+ * @param endType\r
+ * The type of the pair's end type.\r
+ */\r
+ public void removeMatch(String startType, String endType) {\r
+ fMatch.remove(endType);\r
+ fInverseMatch.remove(startType);\r
+ }\r
+\r
+ /**\r
+ * Returns the list of all event possible types.\r
+ * @return The list of all event possible types.\r
+ */\r
+ public Vector<String> getTypeList() {\r
+ // Reserve some space for the 103 default event types.\r
+ Vector<String> eventsList = new Vector<String>(103);\r
+\r
+ eventsList.add(ADD_TO_PAGE_CACHE);\r
+ eventsList.add(BIO_BACKMERGE);\r
+ eventsList.add(BIO_FRONTMERGE);\r
+ eventsList.add(BIO_QUEUE);\r
+ eventsList.add(BUFFER_WAIT_END);\r
+ eventsList.add(BUFFER_WAIT_START);\r
+ eventsList.add(CALL);\r
+ eventsList.add(CLOSE);\r
+ eventsList.add(CORE_MARKER_FORMAT);\r
+ eventsList.add(CORE_MARKER_ID);\r
+ eventsList.add(DEV_RECEIVE);\r
+ eventsList.add(DEV_XMIT);\r
+ eventsList.add(END_COMMIT);\r
+ eventsList.add(EXEC);\r
+ eventsList.add(FILE_DESCRIPTOR);\r
+ eventsList.add(GETRQ);\r
+ eventsList.add(GETRQ_BIO);\r
+ eventsList.add(IDT_TABLE);\r
+ eventsList.add(INTERRUPT);\r
+ eventsList.add(IOCTL);\r
+ eventsList.add(IRQ_ENTRY);\r
+ eventsList.add(IRQ_EXIT);\r
+ eventsList.add(LIST_MODULE);\r
+ eventsList.add(LLSEEK);\r
+ eventsList.add(LSEEK);\r
+ eventsList.add(NAPI_COMPLETE);\r
+ eventsList.add(NAPI_POLL);\r
+ eventsList.add(NAPI_SCHEDULE);\r
+ eventsList.add(NETWORK_IPV4_INTERFACE);\r
+ eventsList.add(NETWORK_IP_INTERFACE);\r
+ eventsList.add(OPEN);\r
+ eventsList.add(PAGE_FAULT_ENTRY);\r
+ eventsList.add(PAGE_FAULT_EXIT);\r
+ eventsList.add(PAGE_FAULT_GET_USER_ENTRY);\r
+ eventsList.add(PAGE_FAULT_GET_USER_EXIT);\r
+ eventsList.add(PAGE_FREE);\r
+ eventsList.add(PLUG);\r
+ eventsList.add(POLLFD);\r
+ eventsList.add(PREAD64);\r
+ eventsList.add(PRINTF);\r
+ eventsList.add(PRINTK);\r
+ eventsList.add(PROCESS_EXIT);\r
+ eventsList.add(PROCESS_FORK);\r
+ eventsList.add(PROCESS_FREE);\r
+ eventsList.add(PROCESS_STATE);\r
+ eventsList.add(PROCESS_WAIT);\r
+ eventsList.add(READ);\r
+ eventsList.add(REMAP);\r
+ eventsList.add(REMOVE_FROM_PAGE_CACHE);\r
+ eventsList.add(RQ_COMPLETE_FS);\r
+ eventsList.add(RQ_COMPLETE_PC);\r
+ eventsList.add(RQ_INSERT_FS);\r
+ eventsList.add(RQ_INSERT_PC);\r
+ eventsList.add(RQ_ISSUE_FS);\r
+ eventsList.add(RQ_ISSUE_PC);\r
+ eventsList.add(RQ_REQUEUE_PC);\r
+ eventsList.add(SCHED_MIGRATE_TASK);\r
+ eventsList.add(SCHED_SCHEDULE);\r
+ eventsList.add(SCHED_TRY_WAKEUP);\r
+ eventsList.add(SCHED_WAKEUP_NEW_TASK);\r
+ eventsList.add(SELECT);\r
+ eventsList.add(SEM_CREATE);\r
+ eventsList.add(SEND_SIGNAL);\r
+ eventsList.add(SHM_CREATE);\r
+ eventsList.add(SLEEPRQ_BIO);\r
+ eventsList.add(SOCKET_ACCEPT);\r
+ eventsList.add(SOCKET_BIND);\r
+ eventsList.add(SOCKET_CALL);\r
+ eventsList.add(SOCKET_CONNECT);\r
+ eventsList.add(SOCKET_CREATE);\r
+ eventsList.add(SOCKET_GETPEERNAME);\r
+ eventsList.add(SOCKET_GETSOCKNAME);\r
+ eventsList.add(SOCKET_GETSOCKOPT);\r
+ eventsList.add(SOCKET_LISTEN);\r
+ eventsList.add(SOCKET_SETSOCKOPT);\r
+ eventsList.add(SOCKET_SHUTDOWN);\r
+ eventsList.add(SOCKET_SOCKETPAIR);\r
+ eventsList.add(SOFTIRQ_ENTRY);\r
+ eventsList.add(SOFTIRQ_EXIT);\r
+ eventsList.add(SOFTIRQ_RAISE);\r
+ eventsList.add(SOFTIRQ_VEC);\r
+ eventsList.add(START_COMMIT);\r
+ eventsList.add(STATEDUMP_END);\r
+ eventsList.add(SYS_CALL_TABLE);\r
+ eventsList.add(SYSCALL_ENTRY);\r
+ eventsList.add(SYSCALL_EXIT);\r
+ eventsList.add(TASKLET_LOW_ENTRY);\r
+ eventsList.add(TASKLET_LOW_EXIT);\r
+ eventsList.add(TCPV4_RCV);\r
+ eventsList.add(TIMER_ITIMER_EXPIRED);\r
+ eventsList.add(TIMER_ITIMER_SET);\r
+ eventsList.add(TIMER_SET);\r
+ eventsList.add(TIMER_TIMEOUT);\r
+ eventsList.add(TIMER_UPDATE_TIME);\r
+ eventsList.add(UDPV4_RCV);\r
+ eventsList.add(UNPLUG_IO);\r
+ eventsList.add(UNPLUG_TIMER);\r
+ eventsList.add(VM_MAP);\r
+ eventsList.add(VPRINTK);\r
+ eventsList.add(WAIT_ON_PAGE_END);\r
+ eventsList.add(WAIT_ON_PAGE_START);\r
+ eventsList.add(WRITE);\r
+ eventsList.add(WRITEV);\r
+\r
+ return eventsList;\r
+ }\r
+\r
+ /**\r
+ * Prints the stack content to the console.\r
+ */\r
+ public void print() {\r
+ fStack.printContent();\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.core.latency.analyzer;\r
+\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Set;\r
+import java.util.Stack;\r
+\r
+import org.eclipse.linuxtools.lttng.core.event.LttngEvent;\r
+\r
+/**\r
+ * <b><u>StackWrapper</u></b>\r
+ * <p>\r
+ * Stack pile.\r
+ * \r
+ * TODO Change the types of the HashMaps from <String,String> to <Integer,Integer>, in order to take advantage of the\r
+ * compilation-time String.hashCode() speedup over execution-time String hash computation.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class StackWrapper {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Hash map of event stacks.\r
+ */\r
+ private HashMap<String, Stack<LttngEvent>> fStacks = null;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructors\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Constructor.\r
+ */\r
+ public StackWrapper() {\r
+ fStacks = new HashMap<String, Stack<LttngEvent>>();\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Adds an event to the list of events of the same type.\r
+ * @param event\r
+ * The event to add to the list.\r
+ */\r
+ public void put(LttngEvent event) {\r
+ String key = event.getMarkerName();\r
+\r
+ if (fStacks.containsKey(key)) {\r
+ fStacks.get(key).add(event);\r
+ } else {\r
+ Stack<LttngEvent> newStack = new Stack<LttngEvent>();\r
+ newStack.add(event);\r
+ fStacks.put(key, newStack);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Checks if the stack contains a list of events of the given type.\r
+ * @param key\r
+ * The type of events to check for.\r
+ * @return "true" if the stack contains events of the given type, "false" otherwise.\r
+ */\r
+ public boolean containsKey(String key) {\r
+ return fStacks.containsKey(key);\r
+ }\r
+\r
+ /**\r
+ * Returns the list of events of the given type.\r
+ * @param key\r
+ * The type of events to return.\r
+ * @return The list of events of the given type, or null.\r
+ */\r
+ public Stack<LttngEvent> getStackOf(String key) {\r
+ return fStacks.get(key);\r
+ }\r
+\r
+ /**\r
+ * Removes the given event from the given stack list.\r
+ * @param key\r
+ * The given stack type.\r
+ * @param event\r
+ * The event to remove from the given stack type.\r
+ * @return "true" if the event was removed, "false" otherwise.\r
+ */\r
+ public boolean removeEvent(String key, LttngEvent event) {\r
+ Stack<LttngEvent> stack = fStacks.get(key);\r
+\r
+ boolean removed = false;\r
+\r
+ try {\r
+ /**\r
+ * TODO Correct this... Here, no matter what CPU or other content field, we always remove the last event\r
+ * added to the stack. Should be something like : return stack.remove(event);\r
+ */\r
+ stack.pop();\r
+ removed = true;\r
+ } catch (Exception e) {\r
+ e.printStackTrace();\r
+ }\r
+\r
+ // Remove the stack from the stack list if it is empty\r
+ if (stack.isEmpty()) {\r
+ fStacks.remove(key);\r
+ }\r
+\r
+ return removed;\r
+ }\r
+\r
+ /**\r
+ * Clears the stack content.\r
+ */\r
+ public void clear() {\r
+ fStacks.clear();\r
+ }\r
+\r
+ /**\r
+ * Prints the content of the stack to the console.\r
+ */\r
+ @SuppressWarnings("nls")\r
+ public void printContent() {\r
+ Collection<Stack<LttngEvent>> values = fStacks.values();\r
+ Iterator<Stack<LttngEvent>> valueIt = values.iterator();\r
+\r
+ Set<String> keys = fStacks.keySet();\r
+ Iterator<String> keyIt = keys.iterator();\r
+\r
+ while (valueIt.hasNext() && keyIt.hasNext()) {\r
+ Stack<LttngEvent> stack = valueIt.next();\r
+\r
+ System.out.println(" " + keyIt.next() + " [" + stack.size() + "] : " + stack);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * 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<String>, Vector<String>> {
+
+ public EventsPair() {
+ super();
+ }
+
+ public EventsPair(Vector<String> startingEvents, Vector<String> endingEvents) {
+ super(startingEvents, endingEvents);
+ }
+}
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.core.util;\r
+\r
+/**\r
+ * Pair utility class, encapsulates a pair of objects.\r
+ * \r
+ * @author Philippe Sawicki\r
+ * \r
+ * @param <A>\r
+ * The type of the first object.\r
+ * @param <B>\r
+ * The type of the second object.\r
+ */\r
+public abstract class Pair<A, B> {\r
+\r
+ /**\r
+ * A reference to the first object.\r
+ */\r
+ protected A fFirst;\r
+ /**\r
+ * A reference to the second object.\r
+ */\r
+ protected B fSecond;\r
+\r
+ /**\r
+ * Constructor.\r
+ * @param first\r
+ * The pair's first object.\r
+ * @param second\r
+ * The pair's second object.\r
+ */\r
+ public Pair(A first, B second) {\r
+ fFirst = first;\r
+ fSecond = second;\r
+ }\r
+\r
+ /**\r
+ * Constructor.\r
+ */\r
+ public Pair() {\r
+ this(null, null);\r
+ }\r
+\r
+ /**\r
+ * Pair hash code.\r
+ */\r
+ @Override\r
+ public int hashCode() {\r
+ int hashFirst = fFirst != null ? fFirst.hashCode() : 0;\r
+ int hashSecond = fSecond != null ? fSecond.hashCode() : 0;\r
+\r
+ return (hashFirst + hashSecond) * hashSecond + hashFirst;\r
+ }\r
+\r
+ /**\r
+ * Object comparison.\r
+ */\r
+ @Override\r
+ @SuppressWarnings("unchecked")\r
+ public boolean equals(Object other) {\r
+ if (other instanceof Pair) {\r
+ Pair<A, B> otherPair = (Pair<A, B>) other;\r
+ return ((fFirst == otherPair.fFirst || (fFirst != null && otherPair.fFirst != null && fFirst.equals(otherPair.fFirst))) && (fSecond == otherPair.fSecond || (fSecond != null\r
+ && otherPair.fSecond != null && fSecond.equals(otherPair.fSecond))));\r
+ }\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Object to string.\r
+ */\r
+ @Override\r
+ public String toString() {\r
+ return "(" + fFirst + ", " + fSecond + ")"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$\r
+ }\r
+\r
+ /**\r
+ * Returns a reference to the pair's first object.\r
+ * @return A reference to the pair's first object.\r
+ */\r
+ public A getFirst() {\r
+ return fFirst;\r
+ }\r
+\r
+ /**\r
+ * Sets the pair's first object.\r
+ * @param first\r
+ * The pair's first object.\r
+ */\r
+ public void setFirst(A first) {\r
+ fFirst = first;\r
+ }\r
+\r
+ /**\r
+ * Returns a reference to the pair's second object.\r
+ * @return A reference to the pair's second object.\r
+ */\r
+ public B getSecond() {\r
+ return fSecond;\r
+ }\r
+\r
+ /**\r
+ * Sets the pair's second object.\r
+ * @param second\r
+ * The pair's second object.\r
+ */\r
+ public void setSecond(B second) {\r
+ fSecond = second;\r
+ }\r
+}
\ No newline at end of file
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;
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+}
--- /dev/null
+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());
+ }
+}
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;
/**
* <b><u>HistogramDataModelTest</u></b>
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);
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);
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);
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);
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);
}
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);
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);
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);
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);
}
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);
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);
}
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);
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);
}
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);
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;
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]);
}
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);
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]);
}
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);
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]);
}
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);
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]);
}
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);
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]);
}
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);
}
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]);
}
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);
+ }
}
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",
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
name="%histogram.view.name"
restorable="true">
</view>
+ <view
+ allowMultiple="false"
+ category="org.eclipse.linuxtools.lttng.ui.views.category"
+ class="org.eclipse.linuxtools.lttng.ui.views.latency.LatencyView"
+ icon="icons/eview16/graph.gif"
+ id="org.eclipse.linuxtools.lttng.ui.views.latency"
+ name="%latency.view.name"
+ restorable="true">
+ </view>
</extension>
<extension
point="org.eclipse.ui.newWizards">
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+
+/**
+ * <b><u>BaseDistributionData</u></b>
+ * <p>
+ */
+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
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>DistributionData</u></b>
+ * <p>
+ * 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
+ * <p>
+ */
+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;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>HorDistributionData</u></b>
+ * <p>
+ * 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;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>VerDistributionData</u></b>
+ *
+ * Implementation of DistributionData for vertical direction.
+ * <p>
+ */
+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;
+ }
+}
*
* Contributors:
* Francois Chouinard - Initial API and implementation
+ * Bernd Hufmann - Changed to updated histogram data model
*******************************************************************************/
package org.eclipse.linuxtools.lttng.ui.views.histogram;
fRangeStartTime = startTime;
fRangeDuration = duration;
fZoom.setNewRange(fRangeStartTime, fRangeDuration);
- refresh();
+ fDataModel.complete();
}
@Override
newStart = newEnd - fZoom.getDuration();
}
fRangeStartTime = newStart;
- refresh();
+ fDataModel.complete();
}
}
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;
*
* Contributors:
* Francois Chouinard - Initial API and implementation
+ * Bernd Hufmann - Changed to updated histogram data model
*******************************************************************************/
package org.eclipse.linuxtools.lttng.ui.views.histogram;
* <li>number of events in that time range
* </ul>
*/
-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);
// Timestamp scale (nanosecond)
public static final byte TIME_SCALE = -9;
+
+ public static final int HISTOGRAM_BAR_WIDTH = 1;
// ------------------------------------------------------------------------
// Attributes
createWidget(parent);
fDataModel = new HistogramDataModel();
+ fDataModel.addHistogramListener(this);
clear();
fCanvas.addControlListener(this);
public void dispose() {
fHistoBarColor.dispose();
+ fDataModel.removeHistogramListener(this);
}
private void createWidget(Composite parent) {
// ------------------------------------------------------------------------
public long getStartTime() {
- return fDataModel.getStartTime();
+ return fDataModel.getFirstBucketTime();
}
public long getEndTime() {
public long getTimeLimit() {
return fDataModel.getTimeLimit();
}
+
+ public HistogramDataModel getDataModel() {
+ return fDataModel;
+ }
// ------------------------------------------------------------------------
// Operations
public void clear() {
fDataModel.clear();
fScaledData = null;
- refresh();
}
/**
*
* @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);
}
/**
*/
public void setCurrentEvent(long timestamp) {
fCurrentEventTime = (timestamp > 0) ? timestamp : 0;
- fDataModel.setCurrentEvent(timestamp);
- refresh();
+ fDataModel.setCurrentEventNotifyListeners(timestamp);
}
/**
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)
}
* @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);
}
/**
/**
* Refresh the histogram display
*/
- protected void refresh() {
+ @Override
+ public void modelUpdated() {
if (!fCanvas.isDisposed() && fCanvas.getDisplay() != null) {
fCanvas.getDisplay().asyncExec(new Runnable() {
@Override
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
}
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();
@Override
public void controlMoved(ControlEvent event) {
- refresh();
+ fDataModel.complete();
}
@Override
public void controlResized(ControlEvent event) {
- refresh();
+ fDataModel.complete();
}
-
}
*
* 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;
* <i>timespan</i> (<i>timespan'</i> = <i>n</i> * <i>d'</i>, where <i>d'</i> =
* 2<i>d</i>). This compaction happens as needed as the trace is read.
* <p>
+ * 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
+ * <i>basetime</i>, the buckets will be moved to the right to account for the
+ * new smaller timestamp. The new <i>basetime</i> is a multiple of the bucket
+ * duration smaller then the previous <i>basetime</i>. Note that the <i>basetime</i>
+ * 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.
+ * <p>
* The mapping from the model to the UI is performed by the <i>scaleTo()</i>
* method. By keeping the number of buckets <i>n</i> relatively large with
* respect to to the number of pixels in the actual histogram, we should achieve
* <p>
* TODO: Cut-off eccentric values? TODO: Support for going back in time?
*/
-public class HistogramDataModel {
+public class HistogramDataModel implements IHistogramDataModel {
// ------------------------------------------------------------------------
// Constants
// 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;
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);
}
public HistogramDataModel(int nbBuckets) {
fNbBuckets = nbBuckets;
fBuckets = new long[nbBuckets];
+ fModelListeners = new ListenerList();
clear();
}
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);
+ }
}
// ------------------------------------------------------------------------
public long getBucketDuration() {
return fBucketDuration;
}
+
+ public long getFirstBucketTime() {
+ return fFirstBucketTime;
+ }
public long getStartTime() {
return fFirstEventTime;
}
-
+
public long getEndTime() {
return fLastEventTime;
}
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();
}
/**
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)
}
// 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;
}
// ------------------------------------------------------------------------
private void updateEndTime() {
- fTimeLimit = fFirstEventTime + fNbBuckets * fBucketDuration;
+ fTimeLimit = fFirstBucketTime + fNbBuckets * fBucketDuration;
}
private void mergeBuckets() {
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;
+ }
}
// 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);
}
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();
}
*
* Contributors:
* Francois Chouinard - Initial API and implementation
+ * Bernd Hufmann - Added setter and getter
*******************************************************************************/
package org.eclipse.linuxtools.lttng.ui.views.histogram;
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
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) {
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);
}
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);
}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>IHistogramDataModel</u></b>
+ * <p>
+ */
+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);
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>IHistogramModelListener</u></b>
+ * <p>
+ */
+public interface IHistogramModelListener {
+ /**
+ * Method to notify listeners about model updates
+ */
+ public void modelUpdated();
+}
/*******************************************************************************
- * 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
*
* Contributors:
* Francois Chouinard - Initial API and implementation
+ * Bernd Hufmann - Changed to updated histogram data model
*******************************************************************************/
package org.eclipse.linuxtools.lttng.ui.views.histogram;
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Adapted to new model-view-controller design\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDistributionModel;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseTrackListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.ZoomListener;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.SWTException;\r
+import org.eclipse.swt.widgets.Canvas;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Display;\r
+\r
+/**\r
+ * <b><u>AbstractViewer</u></b>\r
+ * <p>\r
+ * Abstract viewer.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public abstract class AbstractViewer extends Canvas {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Parent composite node.\r
+ */\r
+ protected Composite fParent;\r
+\r
+ /**\r
+ * Paint listener.\r
+ */\r
+ protected AbstractPaintListener fPaintListener;\r
+\r
+ /**\r
+ * Zoom listener, to zoom in and out of a graph using the scroll wheel.\r
+ */\r
+ protected ZoomListener fZoomListener;\r
+\r
+ /**\r
+ * Tool tip listener.\r
+ */\r
+ protected AbstractMouseTrackListener fMouseTraceListener;\r
+\r
+ /**\r
+ * Mouse listener\r
+ */\r
+ protected AbstractMouseListener fMouseListener;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructor\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Constructor.\r
+ * @param parent\r
+ * The parent composite node.\r
+ * @param style\r
+ * The SWT style to use to render the view.\r
+ */\r
+ public AbstractViewer(Composite parent, int style) {\r
+ super(parent, style);\r
+\r
+ fParent = parent;\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Abstract interface\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Clears the view.\r
+ */\r
+ abstract public void clear();\r
+\r
+ /**\r
+ * Clears the background of the view but keeps min and max values.\r
+ */\r
+ abstract public void clearBackground();\r
+\r
+ /**\r
+ * Method to increase bar width\r
+ */\r
+ abstract public void increaseBarWidth();\r
+ \r
+ /**\r
+ * Method to decrease bar width\r
+ */\r
+ abstract public void decreaseBarWidth();\r
+\r
+ /**\r
+ * Return data model\r
+ */\r
+ abstract public IBaseDistributionModel getModel();\r
+ \r
+ \r
+ // ------------------------------------------------------------------------\r
+ // Accessors\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Returns the zoom factor for the canvas.\r
+ * @return The zoom factor for the canvas.\r
+ */\r
+ public int getZoomFactor() {\r
+ if (fZoomListener != null) {\r
+ return fZoomListener.getZoomFactor();\r
+ } else {\r
+ return 1;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns the zoom increment for the canvas.\r
+ * @return The zoom increment for the canvas.\r
+ */\r
+ public int getZoomIncrement() {\r
+ if (fZoomListener != null) {\r
+ return fZoomListener.getZoomIncrement();\r
+ } else {\r
+ return 1;\r
+ }\r
+ }\r
+\r
+ \r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Draw horizontal label each "nbTicks" ticks.\r
+ * @param nbTicks\r
+ * The draw interval.\r
+ */\r
+ public void setDrawLabelEachNTicks(int nbTicks) {\r
+ fPaintListener.setDrawLabelEachNTicks(nbTicks);\r
+ }\r
+\r
+ /**\r
+ * Sets the title of the graph.\r
+ * @param graphTitle\r
+ * The title of the graph.\r
+ */\r
+ public void setGraphTitle(String graphTitle) {\r
+ fPaintListener.setGraphTitle(graphTitle);\r
+ }\r
+\r
+ /**\r
+ * Sets the horizontal axis label.\r
+ * @param xLabel\r
+ * The horizontal axis label.\r
+ * @param offset\r
+ * The horizontal axis draw offset (in pixels).\r
+ */\r
+ public void setXAxisLabel(String xLabel, int offset) {\r
+ fPaintListener.setXAxisLabel(xLabel, offset);\r
+ }\r
+\r
+ /**\r
+ * Sets the vertical axis label.\r
+ * @param yLabel\r
+ * The vertical axis label.\r
+ */\r
+ public void setYAxisLabel(String yLabel) {\r
+ fPaintListener.setYAxisLabel(yLabel);\r
+ }\r
+\r
+ /**\r
+ * Asks for the view to be redrawn, synchronously or asynchronously.\r
+ * @param asyncRedraw\r
+ * If "true", the view will be redrawn asynchronously, otherwise it will be redraw synchronously.\r
+ */\r
+ public void askForRedraw(boolean asyncRedraw) {\r
+ if (asyncRedraw == true) {\r
+ Display.getDefault().asyncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ try {\r
+ redraw();\r
+ } catch (SWTException e) {\r
+ // ...\r
+ }\r
+ }\r
+ });\r
+ } else {\r
+ Display.getDefault().syncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ try {\r
+ redraw();\r
+ } catch (SWTException e) {\r
+ // ...\r
+ }\r
+ }\r
+ });\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Asks for the view to be redrawn (asynchronously).\r
+ */\r
+ public void askForRedraw() {\r
+ askForRedraw(true);\r
+ }\r
+\r
+ /**\r
+ * Redraws the title after a zoom to display the new zoom factor.\r
+ */\r
+ public void redrawTitle() {\r
+ fPaintListener.paintGraphTitle();\r
+ }\r
+\r
+ /**\r
+ * Removes the view's listeners before disposing of it.\r
+ */\r
+ @Override\r
+ public void dispose() {\r
+ try {\r
+ if (fPaintListener != null) {\r
+ removePaintListener(fPaintListener);\r
+ fPaintListener = null;\r
+ }\r
+ if (fZoomListener != null) {\r
+ removeListener(SWT.MouseWheel, fZoomListener);\r
+ fZoomListener = null;\r
+ }\r
+ if (fMouseTraceListener != null) {\r
+ removeListener(SWT.MouseMove, fMouseTraceListener);\r
+ fMouseTraceListener = null;\r
+ }\r
+ } catch (SWTException e) {\r
+ // This exception will be thrown if the user closes the view\r
+ // while it is receiving data from the Analyzer.\r
+\r
+ // ...\r
+ }\r
+\r
+ super.dispose();\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Adapted to new model-view-controller design\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.GraphMouseListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.GraphPaintListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.TimePointerListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphDataModel;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyGraphModel;\r
+import org.eclipse.swt.widgets.Composite;\r
+\r
+/**\r
+ * <b><u>GraphViewer</u></b>\r
+ * <p>\r
+ * Graph viewer.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class GraphViewer extends AbstractViewer implements IGraphModelListener {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Latency graph model\r
+ */\r
+ private LatencyGraphModel fModel;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructors\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Constructor.\r
+ * @param parent The parent composite node.\r
+ * @param style The SWT style to use to render the view.\r
+ */\r
+ public GraphViewer(Composite parent, int style) {\r
+ super(parent, style);\r
+\r
+ // Register the paint listener\r
+ fPaintListener = new GraphPaintListener(this);\r
+ addPaintListener(fPaintListener);\r
+\r
+ // Register the mouse track listener\r
+ fMouseTraceListener = new TimePointerListener(this, (GraphPaintListener)fPaintListener);\r
+ addMouseTrackListener(fMouseTraceListener);\r
+\r
+ // Register mouse listener\r
+ fMouseListener = new GraphMouseListener(this, (GraphPaintListener)fPaintListener);\r
+ addMouseListener(fMouseListener);\r
+\r
+ fModel = new LatencyGraphModel();\r
+ fModel.addGraphModelListener(this);\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#dispose()\r
+ */\r
+ @Override\r
+ public void dispose() {\r
+ fModel.removeGraphModelListener(this);\r
+ fPaintListener.dispose();\r
+ super.dispose();\r
+ }\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#clear()\r
+ */\r
+ @Override\r
+ public void clear() {\r
+ fPaintListener.clear();\r
+ }\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#clearBackground()\r
+ */\r
+ @Override\r
+ public void clearBackground() {\r
+ fPaintListener.clear();\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#increaseBarWidth()\r
+ */\r
+ @Override\r
+ public void increaseBarWidth() {\r
+ fPaintListener.increaseBarWitdh();\r
+ graphModelUpdated();\r
+ }\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#decreaseBarWidth()\r
+ */\r
+ @Override\r
+ public void decreaseBarWidth() {\r
+ fPaintListener.decreaseBarWitdh();\r
+ graphModelUpdated();\r
+ }\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#getModel()\r
+ */\r
+ @Override\r
+ public IGraphDataModel getModel() {\r
+ return fModel;\r
+ }\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener#graphModelUpdated()\r
+ */\r
+ @Override\r
+ public void graphModelUpdated() {\r
+ if (!isDisposed() && getDisplay() != null) {\r
+ getDisplay().asyncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ if (!isDisposed()) {\r
+ redraw();\r
+ }\r
+ }\r
+ });\r
+ }\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener#currentEventUpdated()\r
+ */\r
+ @Override\r
+ public void currentEventUpdated(long currentEventTime) {\r
+ graphModelUpdated();\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Adapted to new model-view-controller design\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramDataModel;\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramDataModel;\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramModelListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.HistogramPaintListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.TooltipListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.ZoomListener;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.widgets.Composite;\r
+\r
+/**\r
+ * <b><u>HistogramViewer</u></b>\r
+ * <p>\r
+ * \r
+ * Histogram viewer.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class HistogramViewer extends AbstractViewer implements IHistogramModelListener {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Usable width for data plotting.\r
+ */\r
+ protected int fUsableWidth;\r
+\r
+ /**\r
+ * Latency histogram model.\r
+ */\r
+ private HistogramDataModel fModel;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructors\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Constructor.\r
+ * @param parent The parent composite node.\r
+ * @param style The SWT style to use to render the view.\r
+ */\r
+ public HistogramViewer(Composite parent, int style) {\r
+ super(parent, style);\r
+ \r
+ // Register the paint listener\r
+ fPaintListener = new HistogramPaintListener(this);\r
+ addPaintListener(fPaintListener);\r
+ \r
+ // Register the zoom listener\r
+ fZoomListener = new ZoomListener(this);\r
+ addListener(SWT.MouseWheel, fZoomListener);\r
+ \r
+ // Register the mouse click listener\r
+ fMouseTraceListener = new TooltipListener(this, (HistogramPaintListener)fPaintListener);\r
+ addMouseTrackListener(fMouseTraceListener);\r
+ \r
+ fModel = new HistogramDataModel();\r
+ fModel.addHistogramListener(this);\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#dispose()\r
+ */\r
+ @Override\r
+ public void dispose() {\r
+ fModel.removeHistogramListener(this);\r
+ fPaintListener.dispose();\r
+ super.dispose();\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#clear()\r
+ */\r
+ @Override\r
+ public void clear() {\r
+ fPaintListener.clear();\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#clearBackground()\r
+ */\r
+ @Override\r
+ public void clearBackground() {\r
+ fPaintListener.clear();\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#increaseBarWidth()\r
+ */\r
+ @Override\r
+ public void increaseBarWidth() {\r
+ fPaintListener.increaseBarWitdh();\r
+ modelUpdated();\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#decreaseBarWidth()\r
+ */\r
+ @Override\r
+ public void decreaseBarWidth() {\r
+ fPaintListener.decreaseBarWitdh();\r
+ modelUpdated();\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#getModel()\r
+ */\r
+ @Override\r
+ public IHistogramDataModel getModel() {\r
+ return fModel;\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramModelListener#modelUpdated()\r
+ */\r
+ @Override\r
+ public void modelUpdated() {\r
+ \r
+ if (!isDisposed() && getDisplay() != null) {\r
+ getDisplay().asyncExec(new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ if (!isDisposed()) {\r
+ redraw();\r
+ }\r
+ }\r
+ });\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Adapted to new model-view-controller design\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.IMenuManager;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.eclipse.jface.action.Separator;\r
+import org.eclipse.linuxtools.lttng.core.event.LttngEvent;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AddDialog;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.DeleteDialog;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.ListDialog;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyController;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyGraphModel;\r
+import org.eclipse.linuxtools.tmf.core.event.TmfEvent;\r
+import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;\r
+import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;\r
+import org.eclipse.linuxtools.tmf.core.experiment.TmfExperiment;\r
+import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest;\r
+import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest.ExecutionType;\r
+import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentDisposedSignal;\r
+import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentRangeUpdatedSignal;\r
+import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentSelectedSignal;\r
+import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;\r
+import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;\r
+import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;\r
+import org.eclipse.linuxtools.tmf.ui.views.TmfView;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.ControlEvent;\r
+import org.eclipse.swt.events.ControlListener;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.ui.IActionBars;\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+\r
+/**\r
+ * <b><u>LatencyView</u></b>\r
+ * <p>\r
+ * TmfView displaying the latency views (i.e. the two latency charts).\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class LatencyView extends TmfView implements IGraphModelListener {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+ \r
+ // The initial window span (in nanoseconds)\r
+ public static long INITIAL_WINDOW_SPAN = (1L * 100 * 1000 * 1000); // .1sec\r
+\r
+ /**\r
+ * The view's unique ID.\r
+ */\r
+ public static final String ID = "org.eclipse.linuxtools.lttng.ui.views.latency.LatencyView"; //$NON-NLS-1$\r
+\r
+ /**\r
+ * A reference to the currently selected experiment.\r
+ */\r
+ protected TmfExperiment<LttngEvent> fExperiment = null;\r
+\r
+ /**\r
+ * Parent composite.\r
+ */\r
+ protected Composite fParent;\r
+\r
+ /**\r
+ * Graph view.\r
+ */\r
+ protected GraphViewer fGraphViewer;\r
+ \r
+ /**\r
+ * Histogram view.\r
+ */\r
+ protected HistogramViewer fHistogramViewer;\r
+\r
+ /**\r
+ * Action executed when the user wants to see the list of matching events.\r
+ */\r
+ protected Action fListMatchingEvents;\r
+ \r
+ /**\r
+ * Action executed when the user wants to add matching events.\r
+ */\r
+ protected Action fAddMatchingEvents;\r
+ \r
+ /**\r
+ * Action executed when the user wants to delete matching events.\r
+ */\r
+ protected Action fDeleteMatchingEvents;\r
+ \r
+ /**\r
+ * Action executed when the user wants to increase the width of the histogram bars.\r
+ */\r
+ protected Action fIncreaseBarWidth;\r
+ \r
+ /**\r
+ * Action executed when the user wants to decrease the width of the histogram bars.\r
+ */\r
+ protected Action fDecreaseBarWidth;\r
+\r
+ /**\r
+ * The current histogram window time range.\r
+ */\r
+ protected TmfTimeRange fTimeRange = null;\r
+\r
+ /**\r
+ * Controller of the latency model which is responsible to retrieve data from the trace\r
+ */\r
+ final private LatencyController fController;\r
+\r
+ /**\r
+ * Flag to notify that TimeSyncSignal was received and is being processed.\r
+ */\r
+ private boolean fSyncSignalReceived = false;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructor\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Constructor.\r
+ */\r
+ public LatencyView() {\r
+ super(Messages.LatencyView_ViewName);\r
+ fController = LatencyController.getInstance();\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Create the UI controls of this view.\r
+ * \r
+ * @param parent\r
+ * The composite parent of this view.\r
+ */\r
+ @Override\r
+ public void createPartControl(Composite parent) {\r
+ // Save the parent\r
+ fParent = parent;\r
+\r
+ makeActions();\r
+ contributeToActionBars();\r
+\r
+ // Add a control listener to handle the view resize events (to redraw the canvas)\r
+ fParent.addControlListener(new ControlListener() {\r
+ @Override\r
+ public void controlMoved(ControlEvent event) {\r
+ fHistogramViewer.clearBackground();\r
+ fGraphViewer.clearBackground();\r
+ fController.handleCompleted();\r
+ }\r
+\r
+ @Override\r
+ public void controlResized(ControlEvent event) {\r
+ fHistogramViewer.clearBackground();\r
+ fGraphViewer.clearBackground();\r
+ fController.handleCompleted();\r
+ }\r
+ });\r
+\r
+ // ///////////////////////////////////////////////////////////////////////////////////\r
+ // Layout for the whole view, other elements will be in a child composite of this one\r
+ // Contains :\r
+ // Composite layoutSelectionWindow\r
+ // Composite layoutTimesSpinner\r
+ // Composite layoutExperimentHistogram\r
+ // ///////////////////////////////////////////////////////////////////////////////////\r
+ Composite layoutFullView = new Composite(fParent, SWT.FILL);\r
+ FillLayout gridFullView = new FillLayout();\r
+ gridFullView.marginHeight = 0;\r
+ gridFullView.marginWidth = 0;\r
+ layoutFullView.setLayout(gridFullView);\r
+\r
+ // Create the graph views\r
+ fGraphViewer = new GraphViewer(layoutFullView, SWT.DOUBLE_BUFFERED);\r
+ fGraphViewer.setDrawLabelEachNTicks(2);\r
+ fGraphViewer.setGraphTitle(Messages.LatencyView_Graphs_Graph_Title);\r
+ fGraphViewer.setXAxisLabel(Messages.LatencyView_Graphs_Graph_XAxisLabel, 40);\r
+ fGraphViewer.setYAxisLabel(Messages.LatencyView_Graphs_Graph_YAxisLabel);\r
+\r
+ fHistogramViewer = new HistogramViewer(layoutFullView, SWT.DOUBLE_BUFFERED);\r
+ fHistogramViewer.setDrawLabelEachNTicks(2);\r
+ fHistogramViewer.setGraphTitle(Messages.LatencyView_Graphs_Histogram_Title);\r
+ fHistogramViewer.setXAxisLabel(Messages.LatencyView_Graphs_Histogram_XAxisLabel, 55);\r
+ fHistogramViewer.setYAxisLabel(Messages.LatencyView_Graphs_Histogram_YAxisLabel);\r
+\r
+ fController.registerModel(fGraphViewer.getModel());\r
+ fController.registerModel(fHistogramViewer.getModel());\r
+ \r
+ ((LatencyGraphModel)fGraphViewer.getModel()).addGraphModelListener(this);\r
+ \r
+ @SuppressWarnings("unchecked")\r
+ TmfExperiment<TmfEvent> experiment = (TmfExperiment<TmfEvent>) TmfExperiment.getCurrentExperiment();\r
+ if (experiment != null) {\r
+\r
+ TmfTimeRange experimentTRange = experiment.getTimeRange();\r
+\r
+ if (experimentTRange != TmfTimeRange.Null) {\r
+ TmfExperimentSelectedSignal<TmfEvent> signal = new TmfExperimentSelectedSignal<TmfEvent>(this, experiment);\r
+ experimentSelected(signal);\r
+ }\r
+ }\r
+ }\r
+\r
+ @SuppressWarnings("nls")\r
+ @Override\r
+ public String toString() {\r
+ return "["+ Messages.LatencyView_ViewName+"]";\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Signal handlers\r
+ // ------------------------------------------------------------------------\r
+\r
+ @SuppressWarnings("unchecked")\r
+ @TmfSignalHandler\r
+ public void experimentSelected(TmfExperimentSelectedSignal<TmfEvent> signal) {\r
+ // Clear the views\r
+ fGraphViewer.clear();\r
+ fHistogramViewer.clear();\r
+\r
+ if (fParent != null) {\r
+ // Update the trace reference\r
+ fExperiment = (TmfExperiment<LttngEvent>) signal.getExperiment();\r
+\r
+ fTimeRange = TmfTimeRange.Null;\r
+ TmfTimeRange experimentTRange = fExperiment.getTimeRange();\r
+\r
+ if (!experimentTRange.equals(TmfTimeRange.Null)) {\r
+ fTimeRange = new TmfTimeRange(experimentTRange.getStartTime(), \r
+ new TmfTimestamp(experimentTRange.getStartTime().getValue() + INITIAL_WINDOW_SPAN, experimentTRange.getStartTime().getScale(), experimentTRange.getStartTime().getPrecision()));\r
+ fController.refreshModels(fExperiment, fTimeRange);\r
+ }\r
+ }\r
+ } \r
+ @TmfSignalHandler\r
+ public void experimentRangeUpdated(TmfExperimentRangeUpdatedSignal signal) {\r
+ if (fTimeRange == TmfTimeRange.Null && signal.getExperiment().equals(fExperiment)) {\r
+ TmfTimeRange experimentTRange = signal.getRange();\r
+\r
+ if (experimentTRange != TmfTimeRange.Null) {\r
+ fTimeRange = new TmfTimeRange(experimentTRange.getStartTime(), \r
+ new TmfTimestamp(experimentTRange.getStartTime().getValue() + INITIAL_WINDOW_SPAN, experimentTRange.getStartTime().getScale(), experimentTRange.getStartTime().getPrecision()));\r
+ fController.refreshModels(fExperiment, fTimeRange);\r
+ }\r
+ }\r
+ }\r
+ \r
+ @TmfSignalHandler\r
+ public void experimentDisposed(TmfExperimentDisposedSignal<TmfEvent> signal) {\r
+ fTimeRange = TmfTimeRange.Null;\r
+ fExperiment = null;\r
+ fController.clear();\r
+ }\r
+\r
+ /**\r
+ * Called when the LatencyView is closed: disposes of the canvas and unregisters models from views.\r
+ */\r
+ @Override\r
+ public void dispose() {\r
+ fController.dispose();\r
+ fController.deregisterModel(fGraphViewer.getModel());\r
+ fController.deregisterModel(fHistogramViewer.getModel());\r
+ ((LatencyGraphModel)fGraphViewer.getModel()).removeGraphModelListener(this);\r
+\r
+ fGraphViewer.dispose();\r
+ fHistogramViewer.dispose();\r
+\r
+ super.dispose();\r
+ }\r
+\r
+ /**\r
+ * Method called when synchronization is active and that the user select an event.\r
+ * \r
+ * The models will be updated with the new current selected time.\r
+ * \r
+ * @param signal\r
+ * Signal received from the framework. Contain the event.\r
+ */\r
+ @TmfSignalHandler\r
+ public void currentTimeUpdated(TmfTimeSynchSignal signal) {\r
+ if (signal.getSource() != this) {\r
+ fSyncSignalReceived = true;\r
+ fController.setCurrentEventTime(signal.getCurrentTime().getValue());\r
+ fSyncSignalReceived = false;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Method called when synchronization is active and that the user changed the current time range.\r
+\r
+ * The models will be updated with the new time range.\r
+ * \r
+ * @param signal\r
+ * Signal received from the framework. Contain the new time range.\r
+ */\r
+ @TmfSignalHandler\r
+ public void synchToTimeRange(TmfRangeSynchSignal signal) {\r
+ if (signal.getSource() != this) {\r
+ // Erase the graph views\r
+ fGraphViewer.clear();\r
+ fHistogramViewer.clear();\r
+ \r
+ TmfTimestamp startTime = signal.getCurrentRange().getStartTime();\r
+ TmfTimestamp endTime = signal.getCurrentRange().getEndTime();\r
+ fTimeRange = new TmfTimeRange(startTime, endTime);\r
+\r
+ fController.refreshModels(fExperiment, fTimeRange);\r
+ }\r
+ }\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener#graphModelUpdated()\r
+ */\r
+ @Override\r
+ public void graphModelUpdated() {\r
+ // Nothing to do - update of viewers will be done in the viewers\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener#currentEventUpdated(long)\r
+ */\r
+ @Override\r
+ public void currentEventUpdated(final long currentEventTime) {\r
+ if (fExperiment != null && \r
+ !fSyncSignalReceived && // Don't broadcast the current time that was received just before with a time sync signal\r
+ currentEventTime != Config.INVALID_EVENT_TIME) {\r
+\r
+ // Queue update in the event request queue \r
+ TmfTimeRange timeRange = new TmfTimeRange(new TmfTimestamp(currentEventTime, Config.TIME_SCALE), TmfTimestamp.BigCrunch);\r
+ TmfEventRequest<LttngEvent> request = new TmfEventRequest<LttngEvent>(LttngEvent.class, timeRange, 0, 1, ExecutionType.FOREGROUND) {\r
+ @Override\r
+ public void handleCompleted() {\r
+ broadcast(new TmfTimeSynchSignal(this, new TmfTimestamp(currentEventTime, Config.TIME_SCALE)));\r
+ }\r
+ };\r
+ fExperiment.sendRequest(request);\r
+ }\r
+ }\r
+ \r
+ // ------------------------------------------------------------------------\r
+ // Helper functions\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Fills the local pull down menu.\r
+ * @param manager\r
+ * The menu manager.\r
+ */\r
+ private void fillLocalPullDown(IMenuManager manager) {\r
+ manager.add(new Separator());\r
+ manager.add(fIncreaseBarWidth);\r
+ manager.add(fDecreaseBarWidth);\r
+ manager.add(new Separator());\r
+ manager.add(fListMatchingEvents);\r
+ manager.add(fAddMatchingEvents);\r
+ manager.add(fDeleteMatchingEvents);\r
+ manager.add(new Separator());\r
+ }\r
+\r
+ /**\r
+ * Fills the local toolbar.\r
+ * @param manager\r
+ * The toolbar manager\r
+ */\r
+ private void fillLocalToolBar(IToolBarManager manager) {\r
+ manager.add(new Separator());\r
+ manager.add(fIncreaseBarWidth);\r
+ manager.add(fDecreaseBarWidth);\r
+ manager.add(new Separator());\r
+ manager.add(fListMatchingEvents);\r
+ manager.add(fAddMatchingEvents);\r
+ manager.add(fDeleteMatchingEvents);\r
+ manager.add(new Separator());\r
+ }\r
+\r
+ /**\r
+ * Creates the actions required by the dialog events.\r
+ */\r
+ private void makeActions() {\r
+ // Increase the histogram bar width\r
+ fIncreaseBarWidth = new Action() {\r
+ @Override\r
+ public void run() {\r
+ fHistogramViewer.increaseBarWidth();\r
+ fGraphViewer.increaseBarWidth();\r
+ }\r
+ };\r
+ String tooltipText = Messages.LatencyView_Action_IncreaseBarWidth_Tooltip;\r
+ fIncreaseBarWidth.setText(tooltipText);\r
+ fIncreaseBarWidth.setToolTipText(tooltipText);\r
+ fIncreaseBarWidth.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/increasebar_button.gif")); //$NON-NLS-1$\r
+\r
+ // Decrease the histogram bar width\r
+ fDecreaseBarWidth = new Action() {\r
+ @Override\r
+ public void run() {\r
+ fHistogramViewer.decreaseBarWidth();\r
+ fGraphViewer.decreaseBarWidth();\r
+ }\r
+ };\r
+ tooltipText = Messages.LatencyView_Action_DecreaseBarWidth_Tooltip;\r
+ fDecreaseBarWidth.setText(tooltipText);\r
+ fDecreaseBarWidth.setToolTipText(tooltipText);\r
+ fDecreaseBarWidth.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/decreasebar_button.gif")); //$NON-NLS-1$\r
+\r
+ // List matching events dialog\r
+ fListMatchingEvents = new Action() {\r
+ @Override\r
+ public void run() {\r
+ ListDialog listDialog = new ListDialog(fParent.getShell(), Messages.LatencyView_Dialogs_ListEvents_Title, Messages.LatencyView_Dialogs_ListEvents_Message);\r
+ listDialog.create();\r
+ listDialog.open();\r
+ }\r
+ };\r
+ tooltipText = Messages.LatencyView_Action_ListEvents_Tooltip;\r
+ fListMatchingEvents.setText(tooltipText);\r
+ fListMatchingEvents.setToolTipText(tooltipText);\r
+ fListMatchingEvents.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/eview16/events_view.gif")); //$NON-NLS-1$\r
+\r
+ // Add matching events dialog\r
+ fAddMatchingEvents = new Action() {\r
+ @Override\r
+ public void run() {\r
+ AddDialog addDialog = new AddDialog(fParent.getShell(), Messages.LatencyView_Dialogs_AddEvents_Title, Messages.LatencyView_Dialogs_AddEvents_Message);\r
+ addDialog.create();\r
+ addDialog.open();\r
+ }\r
+ };\r
+ tooltipText = Messages.LatencyView_Action_AddEvents_Tooltip;\r
+ fAddMatchingEvents.setText(tooltipText);\r
+ fAddMatchingEvents.setToolTipText(tooltipText);\r
+ fAddMatchingEvents.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/add_button.gif")); //$NON-NLS-1$\r
+\r
+ // Remove matching events dialog\r
+ fDeleteMatchingEvents = new Action() {\r
+ @Override\r
+ public void run() {\r
+ DeleteDialog deleteDialog = new DeleteDialog(fParent.getShell(), Messages.LatencyView_Dialogs_DeleteEvents_Title,\r
+ Messages.LatencyView_Dialogs_DeleteEvents_Message);\r
+ deleteDialog.create();\r
+ deleteDialog.open();\r
+ }\r
+ };\r
+ tooltipText = Messages.LatencyView_Action_DeleteEvents_Tooltip;\r
+ fDeleteMatchingEvents.setText(tooltipText);\r
+ fDeleteMatchingEvents.setToolTipText(tooltipText);\r
+ fDeleteMatchingEvents.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/delete_button.gif")); //$NON-NLS-1$\r
+ }\r
+\r
+ /**\r
+ * Build the toolbar and menu by adding action buttons for dialogs.\r
+ */\r
+ private void contributeToActionBars() {\r
+ IActionBars bars = getViewSite().getActionBars();\r
+ fillLocalPullDown(bars.getMenuManager());\r
+ fillLocalToolBar(bars.getToolBarManager());\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Updated \r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency;\r
+\r
+import org.eclipse.osgi.util.NLS;\r
+\r
+/**\r
+ * Returns localized strings from the resource bundle (i.e. "messages.properties").\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class Messages {\r
+\r
+ public static String LatencyView_ViewName;\r
+ public static String LatencyView_Action_IncreaseBarWidth_Tooltip;\r
+ public static String LatencyView_Action_DecreaseBarWidth_Tooltip;\r
+ public static String LatencyView_Action_AddEvents_Tooltip;\r
+ public static String LatencyView_Action_DeleteEvents_Tooltip;\r
+ public static String LatencyView_Action_ListEvents_Tooltip;\r
+ public static String LatencyView_Dialogs_AddEvents_Title;\r
+ public static String LatencyView_Dialogs_AddEvents_Message;\r
+ public static String LatencyView_Dialogs_AddEvents_Buttons_Add;\r
+ public static String LatencyView_Dialogs_AddEvents_Buttons_Close;\r
+ public static String LatencyView_Dialogs_AddEvents_Columns_Start;\r
+ public static String LatencyView_Dialogs_AddEvents_Columns_End;\r
+ public static String LatencyView_Dialogs_AddEvents_Columns_List_Trigger;\r
+ public static String LatencyView_Dialogs_AddEvents_Columns_List_End;\r
+ public static String LatencyView_Dialogs_AddEvents_Errors_NoSelection;\r
+ public static String LatencyView_Dialogs_AddEvents_Errors_StartNotSelected;\r
+ public static String LatencyView_Dialogs_AddEvents_Errors_EndNotSelected;\r
+ public static String LatencyView_Dialogs_AddEvents_Errors_SameSelected;\r
+ public static String LatencyView_Dialogs_AddEvents_Errors_AlreadyMatched;\r
+ public static String LatencyView_Dialogs_AddEvents_Errors_StartAlreadyMatched;\r
+ public static String LatencyView_Dialogs_AddEvents_Errors_EndAlreadyMatched;\r
+ public static String LatencyView_Dialogs_AddEvents_Errors_StartAsEnd;\r
+ public static String LatencyView_Dialogs_AddEvents_Errors_EndAsStart;\r
+ public static String LatencyView_Dialogs_DeleteEvents_Title;\r
+ public static String LatencyView_Dialogs_DeleteEvents_Message;\r
+ public static String LatencyView_Dialogs_DeleteEvents_Buttons_Close;\r
+ public static String LatencyView_Dialogs_DeleteEvents_Buttons_Delete;\r
+ public static String LatencyView_Dialogs_DeleteEvents_Confirm_Title;\r
+ public static String LatencyView_Dialogs_DeleteEvents_Confirm_Message;\r
+ public static String LatencyView_Dialogs_ListEvents_Title;\r
+ public static String LatencyView_Dialogs_ListEvents_Message;\r
+ public static String LatencyView_Dialogs_ListEvents_Buttons_Close;\r
+ public static String LatencyView_Dialogs_ListEvents_Buttons_Reset;\r
+ public static String LatencyView_Dialogs_ListEvents_Columns_Trigger;\r
+ public static String LatencyView_Dialogs_ListEvents_Columns_End;\r
+ public static String LatencyView_Dialogs_ListEvents_Confirm_Title;\r
+ public static String LatencyView_Dialogs_ListEvents_Confirm_Message;\r
+ public static String LatencyView_Graphs_Graph_Title;\r
+ public static String LatencyView_Graphs_Graph_XAxisLabel;\r
+ public static String LatencyView_Graphs_Graph_YAxisLabel;\r
+ public static String LatencyView_Graphs_Histogram_Title;\r
+ public static String LatencyView_Graphs_Histogram_XAxisLabel;\r
+ public static String LatencyView_Graphs_Histogram_YAxisLabel;\r
+ public static String LatencyView_msgSlogan;\r
+ public static String LatencyView_tmf_UI;\r
+ public static String LatencyView_ClippingWarning;\r
+ \r
+\r
+ /**\r
+ * Bundle name.\r
+ */\r
+ private static final String BUNDLE_NAME = "org.eclipse.linuxtools.lttng.ui.views.latency.messages"; //$NON-NLS-1$\r
+\r
+ static {\r
+ // initialize resource bundle\r
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);\r
+ }\r
+\r
+ private Messages() {\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Adapted to new messages file, fixed warnings\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.dialogs;\r
+\r
+import java.util.Vector;\r
+\r
+import org.eclipse.jface.dialogs.IDialogSettings;\r
+import org.eclipse.jface.dialogs.IMessageProvider;\r
+import org.eclipse.jface.dialogs.TitleAreaDialog;\r
+import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher;\r
+import org.eclipse.linuxtools.lttng.core.util.EventsPair;\r
+import org.eclipse.linuxtools.lttng.ui.LTTngUiPlugin;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyController;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Shell;\r
+\r
+/**\r
+ * <b><u>AbstractDialog</u></b>\r
+ * <p> \r
+ * Includes the main functions shared by all the different dialogs.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public abstract class AbstractDialog extends TitleAreaDialog {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * The dialog window title.\r
+ */\r
+ protected String fDialogTitle;\r
+ /**\r
+ * The dialog window message.\r
+ */\r
+ protected String fDialogMessage;\r
+\r
+ /**\r
+ * The code returned by the dialog when the user closes the "Add" dialog.\r
+ */\r
+ public static final int ADD = 53445;\r
+ /**\r
+ * The code returned by the dialog when the user closes the "Delete" dialog.\r
+ */\r
+ public static final int DELETE = ADD + 1;\r
+ /**\r
+ * The code returned by the dialog when the user resets the latency pair to default.\r
+ */\r
+ public static final int RESET = DELETE + 1;\r
+\r
+ /**\r
+ * String ID of the number of pairs saved in the settings file.\r
+ */\r
+ protected static final String LATENCY_NB_MATCH_PAIRS = "NB_LATENCY_MATCH_PAIRS"; //$NON-NLS-1$\r
+ /**\r
+ * String ID of the start event pairs saved in the settings file.\r
+ */\r
+ protected static final String LATENCY_PAIRS_START = "LATENCY_PAIRS_START"; //$NON-NLS-1$\r
+ /**\r
+ * String ID of the end event pairs saved in the settings file.\r
+ */\r
+ protected static final String LATENCY_PAIRS_END = "LATENCY_PAIRS_END"; //$NON-NLS-1$\r
+\r
+ /**\r
+ * Dialog settings, saves the event pairs across sessions.\r
+ */\r
+ protected IDialogSettings fSettings;\r
+\r
+ /**\r
+ * Do the graphs canvas need to be redrawn due to latency pairs changes ?\r
+ */\r
+ protected boolean fRedrawGraphs = false;\r
+ \r
+ // ------------------------------------------------------------------------\r
+ // Constructors\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Constructor.\r
+ * @param parentShell\r
+ * The parent shell.\r
+ * @param title\r
+ * The dialog window's title.\r
+ * @param message\r
+ * The dialog window's message.\r
+ */\r
+ public AbstractDialog(Shell parentShell, String title, String message) {\r
+ super(parentShell);\r
+ fDialogTitle = title;\r
+ fDialogMessage = message;\r
+\r
+ fSettings = LTTngUiPlugin.getDefault().getDialogSettings();\r
+ }\r
+\r
+ /**\r
+ * Constructor\r
+ * @param parentShell\r
+ * The parent shell.\r
+ * @param title\r
+ * The dialog window's title.\r
+ */\r
+ @SuppressWarnings("nls")\r
+ public AbstractDialog(Shell parentShell, String title) {\r
+ this(parentShell, title, "");\r
+ }\r
+\r
+ /**\r
+ * Constructor.\r
+ * @param parentShell\r
+ * The parent shell.\r
+ */\r
+ @SuppressWarnings("nls")\r
+ public AbstractDialog(Shell parentShell) {\r
+ this(parentShell, "", "");\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Creates the dialog.\r
+ * \r
+ * <b>Note :</b> Since there is an issue with the table's vertical scroll bar, this dialog "resize" is necessary to\r
+ * ensure a minimal height for the window.\r
+ */\r
+ @Override\r
+ public void create() {\r
+ super.create();\r
+ // Set the title\r
+ setTitle(fDialogTitle);\r
+ // Set the message\r
+ setMessage(fDialogMessage, IMessageProvider.INFORMATION);\r
+\r
+ // Position the dialog at the center of the screen\r
+ int windowWidth = Display.getCurrent().getPrimaryMonitor().getBounds().width;\r
+ int windowHeight = Display.getCurrent().getPrimaryMonitor().getBounds().height;\r
+ int dialogWidth = getShell().getSize().x;\r
+ int dialogHeight = windowHeight / 2;\r
+\r
+ int x = (windowWidth - dialogWidth) / 2;\r
+ int y = (windowHeight - dialogHeight) / 2;\r
+\r
+ getShell().setSize(getShell().getSize().x, dialogHeight);\r
+ getShell().setLocation(x, y);\r
+ }\r
+\r
+ /**\r
+ * Formats the "#" of the event in the table by adding "00" before it.\r
+ * @param number\r
+ * The number to format.\r
+ * @param max\r
+ * The maximum number of event pairs in the list.\r
+ * @return The formatted string.\r
+ */\r
+ @SuppressWarnings("nls")\r
+ protected String formatListNumber(int number, int max) {\r
+ return String.format("%0" + max + "d", number);\r
+ }\r
+\r
+ /**\r
+ * Returns the match pairs saved in the settings file.\r
+ * @return The match pairs saved in the settings file.\r
+ */\r
+ protected EventsPair getMatchPairs() {\r
+ try {\r
+ // Check if the settings file has already some data (i.e. try provoking an exception)\r
+ fSettings.getInt(LATENCY_NB_MATCH_PAIRS);\r
+\r
+ String[] starts = fSettings.getArray(LATENCY_PAIRS_START);\r
+ String[] ends = fSettings.getArray(LATENCY_PAIRS_END);\r
+\r
+ EventMatcher.getInstance().resetMatches();\r
+ for (int i = 0; i < starts.length; i++) {\r
+ EventMatcher.getInstance().addMatch(starts[i], ends[i]);\r
+ }\r
+\r
+ return EventMatcher.getInstance().getEvents();\r
+ } catch (NumberFormatException e) {\r
+ return EventMatcher.getInstance().getEvents();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Saves the event match pairs to a settings file.\r
+ * @param start\r
+ * The start event types.\r
+ * @param end\r
+ * The end event types.\r
+ */\r
+ protected void saveMatchPairs(Vector<String> start, Vector<String> end) {\r
+ fSettings.put(LATENCY_NB_MATCH_PAIRS, start.size());\r
+ fSettings.put(LATENCY_PAIRS_START, start.toArray(new String[] {}));\r
+ fSettings.put(LATENCY_PAIRS_END, end.toArray(new String[] {}));\r
+ }\r
+\r
+ /**\r
+ * Ask the LatencyView to send a new analysis request to the views, so that they can be redrawn.\r
+ */\r
+ protected void redrawGraphs() {\r
+ LatencyController.getInstance().refreshModels();\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite)\r
+ */\r
+ @Override\r
+ protected abstract Control createDialogArea(Composite parent);\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)\r
+ */\r
+ @Override\r
+ protected abstract void createButtonsForButtonBar(Composite parent);\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.jface.dialogs.Dialog#isResizable()\r
+ */\r
+ @Override\r
+ protected boolean isResizable() {\r
+ return true;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Adapted to new messages file, fixed warnings\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.dialogs;\r
+\r
+import java.util.Vector;\r
+\r
+import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher;\r
+import org.eclipse.linuxtools.lttng.core.util.EventsPair;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.Messages;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Event;\r
+import org.eclipse.swt.widgets.Listener;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Table;\r
+import org.eclipse.swt.widgets.TableColumn;\r
+import org.eclipse.swt.widgets.TableItem;\r
+\r
+/**\r
+ * <b><u>AddDialog</u></b>\r
+ * <p>\r
+ * Add dialog, lets the user add custom start/end event pairs.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class AddDialog extends AbstractDialog {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * The dialog's start table.\r
+ */\r
+ protected Table fStartTable;\r
+\r
+ /**\r
+ * The dialog's end table.\r
+ */\r
+ protected Table fEndTable;\r
+\r
+ /**\r
+ * The dialog's list table.\r
+ */\r
+ protected Table fListTable;\r
+\r
+ /**\r
+ * Start table columns.\r
+ */\r
+ protected TableColumn[] fStartColumns;\r
+\r
+ /**\r
+ * End table columns.\r
+ */\r
+ protected TableColumn[] fEndColumns;\r
+\r
+ /**\r
+ * List table columns.\r
+ */\r
+ protected TableColumn[] fListColumns;\r
+\r
+ /**\r
+ * Start table column names (header titles).\r
+ */\r
+ protected static final String[] START_COLUMN_NAMES = { "", Messages.LatencyView_Dialogs_AddEvents_Columns_Start }; //$NON-NLS-1$\r
+\r
+ /**\r
+ * End table column names (header titles).\r
+ */\r
+ protected static final String[] END_COLUMN_NAMES = { "", Messages.LatencyView_Dialogs_AddEvents_Columns_End }; //$NON-NLS-1$\r
+\r
+ /**\r
+ * List table column names (header titles).\r
+ */\r
+ protected static final String[] LIST_COLUMN_NAMES = {\r
+ "#", //$NON-NLS-1$\r
+ Messages.LatencyView_Dialogs_AddEvents_Columns_List_Trigger,\r
+ Messages.LatencyView_Dialogs_AddEvents_Columns_List_End };\r
+\r
+ /**\r
+ * Column widths.\r
+ */\r
+ protected static final int[] COLUMN_WIDTHS = { 25, 250, 250 };\r
+\r
+ /**\r
+ * Possible event types.\r
+ */\r
+ protected Vector<String> fEventTypes = new Vector<String>();\r
+\r
+ /**\r
+ * Start event types.\r
+ */\r
+ protected Vector<String> fEventStartTypes;\r
+\r
+ /**\r
+ * End event types.\r
+ */\r
+ protected Vector<String> fEventEndTypes;\r
+\r
+ /**\r
+ * Selected start type.\r
+ */\r
+ protected String fStartType;\r
+\r
+ /**\r
+ * Selected end type.\r
+ */\r
+ protected String fEndType;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructors\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Constructor.\r
+ * @param parentShell\r
+ * The parent shell.\r
+ * @param title\r
+ * The dialog's window title.\r
+ * @param message\r
+ * The dialog's window message.\r
+ */\r
+ public AddDialog(Shell parentShell, String title, String message) {\r
+ super(parentShell, title, message);\r
+\r
+ // Get the possible events from the list\r
+ fEventTypes = EventMatcher.getInstance().getTypeList();\r
+\r
+ // Get the list of start and end types from the EventMatcher\r
+ EventsPair pair = getMatchPairs();\r
+ fEventStartTypes = pair.getFirst();\r
+ fEventEndTypes = pair.getSecond();\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Creates the start table's columns (i.e. the table header).\r
+ */\r
+ protected void createStartColumns() {\r
+ fStartColumns = new TableColumn[START_COLUMN_NAMES.length];\r
+ for (int i = 0; i < START_COLUMN_NAMES.length; i++) {\r
+ fStartColumns[i] = new TableColumn(fStartTable, SWT.LEFT);\r
+ fStartColumns[i].setText(START_COLUMN_NAMES[i]);\r
+ fStartColumns[i].setWidth(COLUMN_WIDTHS[i]);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Creates the end table's columns (i.e. the table header).\r
+ */\r
+ protected void createEndColumns() {\r
+ fEndColumns = new TableColumn[END_COLUMN_NAMES.length];\r
+ for (int i = 0; i < END_COLUMN_NAMES.length; i++) {\r
+ fEndColumns[i] = new TableColumn(fEndTable, SWT.LEFT);\r
+ fEndColumns[i].setText(END_COLUMN_NAMES[i]);\r
+ fEndColumns[i].setWidth(COLUMN_WIDTHS[i]);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Creates the list table's columns (i.e. the table header).\r
+ */\r
+ protected void createListColumns() {\r
+ fListColumns = new TableColumn[LIST_COLUMN_NAMES.length];\r
+ for (int i = 0; i < LIST_COLUMN_NAMES.length; i++) {\r
+ fListColumns[i] = new TableColumn(fListTable, SWT.LEFT);\r
+ fListColumns[i].setText(LIST_COLUMN_NAMES[i]);\r
+ fListColumns[i].setWidth(COLUMN_WIDTHS[i]);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Creates the start column list.\r
+ * @param parent\r
+ * The parent composite.\r
+ */\r
+ protected void createStartColumn(Composite parent) {\r
+ final int style = SWT.SINGLE | SWT.CHECK | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL;\r
+ GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);\r
+ fStartTable = new Table(parent, style);\r
+ fStartTable.setLayoutData(layoutData);\r
+\r
+ // Some cosmetic enhancements\r
+ fStartTable.setHeaderVisible(true);\r
+ fStartTable.setLinesVisible(true);\r
+\r
+ createStartColumns();\r
+\r
+ for (int i = 0; i < fEventTypes.size(); i++) {\r
+ TableItem item = new TableItem(fStartTable, SWT.RIGHT);\r
+\r
+ String[] columns = { fEventTypes.get(i), fEventTypes.get(i) };\r
+\r
+ item.setText(columns);\r
+ }\r
+\r
+ fStartTable.setItemCount(fEventTypes.size());\r
+\r
+ fStartTable.addListener(SWT.Selection, new Listener() {\r
+ @Override\r
+ public void handleEvent(Event event) {\r
+ if (event.detail == SWT.CHECK) {\r
+ TableItem[] items = fStartTable.getItems();\r
+ for (TableItem item : items) {\r
+ if (item != event.item) {\r
+ item.setChecked(false);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ });\r
+ }\r
+\r
+ /**\r
+ * Creates the end column list.\r
+ * @param parent\r
+ * The parent composite.\r
+ */\r
+ protected void createEndColumn(Composite parent) {\r
+ final int style = SWT.SINGLE | SWT.CHECK | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL;\r
+ GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);\r
+ fEndTable = new Table(parent, style);\r
+ fEndTable.setLayoutData(layoutData);\r
+\r
+ // Some cosmetic enhancements\r
+ fEndTable.setHeaderVisible(true);\r
+ fEndTable.setLinesVisible(true);\r
+\r
+ createEndColumns();\r
+\r
+ for (int i = 0; i < fEventTypes.size(); i++) {\r
+ TableItem item = new TableItem(fEndTable, SWT.RIGHT);\r
+\r
+ String[] columns = { fEventTypes.get(i), fEventTypes.get(i) };\r
+\r
+ item.setText(columns);\r
+ }\r
+\r
+ fEndTable.setItemCount(fEventTypes.size());\r
+\r
+ fEndTable.addListener(SWT.Selection, new Listener() {\r
+ @Override\r
+ public void handleEvent(Event event) {\r
+ if (event.detail == SWT.CHECK) {\r
+ TableItem[] items = fEndTable.getItems();\r
+ for (TableItem item : items) {\r
+ if (item != event.item) {\r
+ item.setChecked(false);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ });\r
+ }\r
+\r
+ /**\r
+ * Creates the list column for already existing event pairs.\r
+ * @param parent\r
+ * The parent composite.\r
+ */\r
+ protected void createListColumn(Composite parent) {\r
+ final int style = SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL;\r
+ GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);\r
+ layoutData.horizontalSpan = 2;\r
+ fListTable = new Table(parent, style);\r
+ fListTable.setLayoutData(layoutData);\r
+\r
+ // Some cosmetic enhancements\r
+ fListTable.setHeaderVisible(true);\r
+ fListTable.setLinesVisible(true);\r
+\r
+ createListColumns();\r
+\r
+ for (int i = 0; i < fEventStartTypes.size(); i++) {\r
+ TableItem item = new TableItem(fListTable, SWT.RIGHT);\r
+\r
+ String max = String.valueOf(fEventStartTypes.size());\r
+ String number = formatListNumber(i + 1, max.length());\r
+\r
+ String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) };\r
+\r
+ item.setText(columns);\r
+ }\r
+\r
+ fListTable.setItemCount(103);\r
+ fListTable.remove(fEventTypes.size(), 103 - 1);\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AbstractDialog#createDialogArea(org.eclipse.swt.widgets.Composite)\r
+ */\r
+ @Override\r
+ protected Control createDialogArea(Composite parent) {\r
+ GridLayout layout = new GridLayout(2, true);\r
+ parent.setLayout(layout);\r
+\r
+ createStartColumn(parent);\r
+ createEndColumn(parent);\r
+ createListColumn(parent);\r
+\r
+ return parent;\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AbstractDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)\r
+ */\r
+ @Override\r
+ protected void createButtonsForButtonBar(Composite parent) {\r
+ GridData gridData = new GridData();\r
+ gridData.verticalAlignment = GridData.FILL;\r
+ gridData.horizontalSpan = 1;\r
+ gridData.grabExcessHorizontalSpace = true;\r
+ gridData.grabExcessVerticalSpace = true;\r
+ gridData.horizontalAlignment = SWT.RIGHT;\r
+\r
+ parent.setLayoutData(gridData);\r
+\r
+ // Create the "Add" button\r
+ Button addButton = createButton(parent, ADD, Messages.LatencyView_Dialogs_AddEvents_Buttons_Add, false);\r
+ addButton.addListener(SWT.Selection, new Listener() {\r
+ @Override\r
+ public void handleEvent(Event event) {\r
+ if (isValidInput()) {\r
+ // Add the event pair to the EventMatcher and save the pairs\r
+ EventMatcher.getInstance().addMatch(fStartType, fEndType);\r
+ fEventStartTypes.add(fStartType);\r
+ fEventEndTypes.add(fEndType);\r
+ saveMatchPairs(fEventStartTypes, fEventEndTypes);\r
+\r
+ EventsPair pairs = EventMatcher.getInstance().getEvents();\r
+ fEventStartTypes = pairs.getFirst();\r
+ fEventEndTypes = pairs.getSecond();\r
+\r
+ fListTable.removeAll();\r
+\r
+ for (int i = 0; i < fEventStartTypes.size(); i++) {\r
+ TableItem item = new TableItem(fListTable, SWT.RIGHT);\r
+\r
+ String max = String.valueOf(fEventStartTypes.size());\r
+ String number = formatListNumber(i + 1, max.length());\r
+\r
+ String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) };\r
+\r
+ item.setText(columns);\r
+ }\r
+\r
+ saveMatchPairs(fEventStartTypes, fEventEndTypes);\r
+ }\r
+\r
+ fRedrawGraphs = true;\r
+ }\r
+ });\r
+\r
+ // Create the "Close" button\r
+ Button closeButton = createButton(parent, CANCEL, Messages.LatencyView_Dialogs_AddEvents_Buttons_Close, false);\r
+ closeButton.addListener(SWT.Selection, new Listener() {\r
+ @Override\r
+ public void handleEvent(Event event) {\r
+ setReturnCode(CANCEL);\r
+\r
+ if (fRedrawGraphs == true)\r
+ redrawGraphs();\r
+\r
+ close();\r
+ }\r
+ });\r
+ }\r
+\r
+ /**\r
+ * Validate the list before adding event pairs.\r
+ * @return "true" if the input is valid, "false" otherwise.\r
+ */\r
+ protected boolean isValidInput() {\r
+ // Remove the previous error message\r
+ setErrorMessage(null);\r
+\r
+ boolean valid = true;\r
+\r
+ // Check if an item from the start list is selected\r
+ TableItem[] items = fStartTable.getItems();\r
+ fStartType = null;\r
+ boolean startHasSelectedItem = false;\r
+ for (int i = 0; i < items.length && !startHasSelectedItem; i++) {\r
+ if (items[i].getChecked() == true) {\r
+ fStartType = items[i].getText();\r
+ startHasSelectedItem = true;\r
+ }\r
+ }\r
+\r
+ // Check if an item from the end list is selected\r
+ items = fEndTable.getItems();\r
+ fEndType = null;\r
+ boolean endHasSelectedItem = false;\r
+ for (int i = 0; i < items.length && !endHasSelectedItem; i++) {\r
+ if (items[i].getChecked() == true) {\r
+ fEndType = items[i].getText();\r
+ endHasSelectedItem = true;\r
+ }\r
+ }\r
+\r
+ // Print error message if needed.\r
+ if (!startHasSelectedItem && !endHasSelectedItem) {\r
+ setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_NoSelection);\r
+ valid = false;\r
+ } else if (!startHasSelectedItem) {\r
+ setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_StartNotSelected);\r
+ valid = false;\r
+ } else if (!endHasSelectedItem) {\r
+ setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_EndNotSelected);\r
+ valid = false;\r
+ }\r
+\r
+ // Check if the same item is selected in both lists\r
+ if (startHasSelectedItem && endHasSelectedItem) {\r
+ if (fStartType.equalsIgnoreCase(fEndType)) {\r
+ setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_SameSelected);\r
+ valid = false;\r
+ }\r
+ }\r
+\r
+ // Check if the selected item is already in the list\r
+ if (startHasSelectedItem && endHasSelectedItem) {\r
+ EventsPair pairs = getMatchPairs();\r
+ Vector<String> startEvents = pairs.getFirst();\r
+ Vector<String> endEvents = pairs.getSecond();\r
+\r
+ boolean startAlreadyUsed = false;\r
+ boolean endAlreadyUsed = false;\r
+ boolean startAsEndAlreadyUsed = false;\r
+ boolean endAsStartAlreadyUsed = false;\r
+\r
+ if (startEvents.contains(fStartType)) {\r
+ startAlreadyUsed = true;\r
+ }\r
+ if (endEvents.contains(fEndType)) {\r
+ endAlreadyUsed = true;\r
+ }\r
+ if (startEvents.contains(fEndType)) {\r
+ endAsStartAlreadyUsed = true;\r
+ }\r
+ if (endEvents.contains(fStartType)) {\r
+ startAsEndAlreadyUsed = true;\r
+ }\r
+\r
+ if (startAlreadyUsed && endAlreadyUsed) {\r
+ setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_AlreadyMatched);\r
+ valid = false;\r
+ } else if (startAlreadyUsed) {\r
+ setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_StartAlreadyMatched);\r
+ valid = false;\r
+ } else if (endAlreadyUsed) {\r
+ setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_EndAlreadyMatched);\r
+ valid = false;\r
+ }\r
+\r
+ if (startAsEndAlreadyUsed) {\r
+ setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_StartAsEnd);\r
+ valid = false;\r
+ }\r
+ if (endAsStartAlreadyUsed) {\r
+ setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_EndAsStart);\r
+ valid = false;\r
+ }\r
+ }\r
+\r
+ return valid;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Adapted to new messages file, fixed warnings\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.dialogs;\r
+\r
+import org.eclipse.jface.dialogs.MessageDialog;\r
+import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.Messages;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Event;\r
+import org.eclipse.swt.widgets.Listener;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.TableItem;\r
+\r
+/**\r
+ * <b><u>DeleteDialog</u></b>\r
+ * <p>\r
+ * Remove dialog, lets the user remove start/end event pairs.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class DeleteDialog extends ListDialog {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructors\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Constructor.\r
+ * @param parentShell\r
+ * The parent shell.\r
+ * @param title\r
+ * The dialog's window title.\r
+ * @param message\r
+ * The dialog's window message.\r
+ */\r
+ public DeleteDialog(Shell parentShell, String title, String message) {\r
+ super(parentShell, title, message);\r
+\r
+ // Set the table style\r
+ fStyle = SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL;\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.ListDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)\r
+ */\r
+ @Override\r
+ protected void createButtonsForButtonBar(Composite parent) {\r
+ GridData gridData = new GridData();\r
+ gridData.verticalAlignment = GridData.FILL;\r
+ gridData.horizontalSpan = 1;\r
+ gridData.grabExcessHorizontalSpace = true;\r
+ gridData.grabExcessVerticalSpace = true;\r
+ gridData.horizontalAlignment = SWT.RIGHT;\r
+\r
+ parent.setLayoutData(gridData);\r
+\r
+ // Create the "Delete" button\r
+ Button deleteButton = createButton(parent, DELETE, Messages.LatencyView_Dialogs_DeleteEvents_Buttons_Delete, false);\r
+ deleteButton.addListener(SWT.Selection, new Listener() {\r
+ @Override\r
+ public void handleEvent(Event event) {\r
+ TableItem selectedItem = fTable.getSelection()[0];\r
+ if (selectedItem == null)\r
+ return;\r
+\r
+ int[] selectedIndices = fTable.getSelectionIndices();\r
+\r
+ String deletePairs = ""; //$NON-NLS-1$\r
+ for (int i = 0; i < selectedIndices.length; i++) {\r
+ int index = selectedIndices[i];\r
+ deletePairs += "\t* " + fEventStartTypes.get(index) + " / " + fEventEndTypes.get(index); //$NON-NLS-1$ //$NON-NLS-2$\r
+\r
+ if (i < selectedIndices.length - 1) {\r
+ deletePairs += "\n"; //$NON-NLS-1$\r
+ }\r
+ }\r
+\r
+ boolean confirmDeletion = MessageDialog.openQuestion(getShell(), Messages.LatencyView_Dialogs_DeleteEvents_Confirm_Title,\r
+ Messages.LatencyView_Dialogs_DeleteEvents_Confirm_Message + "\n\n" + deletePairs); //$NON-NLS-1$\r
+\r
+ if (confirmDeletion) {\r
+ // Remove the events starting from the end of the list, otherwise the TableItem elements will lose\r
+ // their index from the table and may trigger an exception when removing an index that is no longer\r
+ // valid.\r
+ for (int i = selectedIndices.length - 1; i >= 0; i--) {\r
+ int selectedIndex = selectedIndices[i];\r
+ EventMatcher.getInstance().removeMatch(fEventStartTypes.get(selectedIndex), fEventEndTypes.get(selectedIndex));\r
+\r
+ fTable.remove(selectedIndex);\r
+\r
+ // Update the list of events\r
+ fEventStartTypes.remove(selectedIndex);\r
+ fEventEndTypes.remove(selectedIndex);\r
+ }\r
+\r
+ // Save the events pairs in the settings file so it can be retrieved in the next session\r
+ saveMatchPairs(fEventStartTypes, fEventEndTypes);\r
+\r
+ fTable.setItemCount(fEventStartTypes.size());\r
+\r
+ TableItem[] newItems = fTable.getItems();\r
+ fTable.removeAll();\r
+ for (int i = 0; i < newItems.length; i++) {\r
+ TableItem item = new TableItem(fTable, SWT.RIGHT);\r
+\r
+ String max = String.valueOf(fEventStartTypes.size());\r
+ String number = formatListNumber(i + 1, max.length());\r
+\r
+ String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) };\r
+\r
+ item.setText(columns);\r
+ }\r
+\r
+ fRedrawGraphs = true;\r
+ }\r
+ }\r
+ });\r
+\r
+ // Create the "Close" button\r
+ Button closeButton = createButton(parent, CANCEL, Messages.LatencyView_Dialogs_AddEvents_Buttons_Close, false);\r
+ closeButton.addListener(SWT.Selection, new Listener() {\r
+ @Override\r
+ public void handleEvent(Event event) {\r
+ // Remember the user's list\r
+ saveMatchPairs(fEventStartTypes, fEventEndTypes);\r
+\r
+ setReturnCode(CANCEL);\r
+\r
+ if (fRedrawGraphs == true)\r
+ redrawGraphs();\r
+\r
+ close();\r
+ }\r
+ });\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Adapted to new messages file, fixed warnings\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.dialogs;\r
+\r
+import java.util.Vector;\r
+\r
+import org.eclipse.jface.dialogs.MessageDialog;\r
+import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher;\r
+import org.eclipse.linuxtools.lttng.core.util.EventsPair;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.Messages;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Event;\r
+import org.eclipse.swt.widgets.Listener;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Table;\r
+import org.eclipse.swt.widgets.TableColumn;\r
+import org.eclipse.swt.widgets.TableItem;\r
+\r
+/**\r
+ * <b><u>ListDialog</u></b>\r
+ * <p>\r
+ * List dialog, shows the list of start/end event pairs.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class ListDialog extends AbstractDialog {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * The dialog's table.\r
+ */\r
+ protected Table fTable;\r
+\r
+ /**\r
+ * Start event types.\r
+ */\r
+ protected Vector<String> fEventStartTypes;\r
+\r
+ /**\r
+ * End event types.\r
+ */\r
+ protected Vector<String> fEventEndTypes;\r
+\r
+ /**\r
+ * Table columns\r
+ */\r
+ protected TableColumn[] fColumns;\r
+\r
+ /**\r
+ * Column names (header titles).\r
+ */\r
+ protected static final String[] COLUMN_NAMES = { "#", Messages.LatencyView_Dialogs_ListEvents_Columns_Trigger, Messages.LatencyView_Dialogs_ListEvents_Columns_End }; //$NON-NLS-1$\r
+\r
+ /**\r
+ * Column widths.\r
+ */\r
+ protected static final int[] COLUMN_WIDTHS = { 25, 250, 250 };\r
+\r
+ /**\r
+ * The table style.\r
+ */\r
+ protected int fStyle;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructor\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Constructor.\r
+ * @param parentShell\r
+ * The parent shell.\r
+ * @param title\r
+ * The dialog's window title.\r
+ * @param message\r
+ * The dialog's window message.\r
+ */\r
+ public ListDialog(Shell parentShell, String title, String message) {\r
+ super(parentShell, title, message);\r
+\r
+ // Set the table style\r
+ fStyle = SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL;\r
+\r
+ // Get the list of start and end types from the EventMatcher\r
+ EventsPair pair = getMatchPairs();\r
+ fEventStartTypes = pair.getFirst();\r
+ fEventEndTypes = pair.getSecond();\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Creates the table's column (i.e. the table header).\r
+ */\r
+ protected void createColumns() {\r
+ fColumns = new TableColumn[COLUMN_NAMES.length];\r
+ for (int i = 0; i < COLUMN_NAMES.length; i++) {\r
+ fColumns[i] = new TableColumn(fTable, SWT.LEFT);\r
+ fColumns[i].setText(COLUMN_NAMES[i]);\r
+ fColumns[i].setWidth(COLUMN_WIDTHS[i]);\r
+ }\r
+ }\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AbstractDialog#createDialogArea(org.eclipse.swt.widgets.Composite)\r
+ */\r
+ @Override\r
+ protected Control createDialogArea(Composite parent) {\r
+ GridLayout layout = new GridLayout(1, true);\r
+ parent.setLayout(layout);\r
+\r
+ GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);\r
+ fTable = new Table(parent, fStyle);\r
+ fTable.setLayoutData(layoutData);\r
+\r
+ // Some cosmetic enhancements\r
+ fTable.setHeaderVisible(true);\r
+ fTable.setLinesVisible(true);\r
+\r
+ createColumns();\r
+\r
+ for (int i = 0; i < fEventStartTypes.size(); i++) {\r
+ TableItem item = new TableItem(fTable, SWT.RIGHT);\r
+\r
+ String max = String.valueOf(fEventStartTypes.size());\r
+ String number = formatListNumber(i + 1, max.length());\r
+\r
+ String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) };\r
+\r
+ item.setText(columns);\r
+ }\r
+\r
+ return parent;\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AbstractDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)\r
+ */\r
+ @Override\r
+ protected void createButtonsForButtonBar(Composite parent) {\r
+ GridData gridData = new GridData();\r
+ gridData.verticalAlignment = GridData.FILL;\r
+ gridData.horizontalSpan = 1;\r
+ gridData.grabExcessHorizontalSpace = true;\r
+ gridData.grabExcessVerticalSpace = true;\r
+ gridData.horizontalAlignment = SWT.RIGHT;\r
+\r
+ parent.setLayoutData(gridData);\r
+\r
+ // Create the "Reset" button\r
+ Button resetButton = createButton(parent, RESET, Messages.LatencyView_Dialogs_ListEvents_Buttons_Reset, false);\r
+ resetButton.addListener(SWT.Selection, new Listener() {\r
+ @Override\r
+ public void handleEvent(Event event) {\r
+ boolean confirmDeletion = MessageDialog.openQuestion(getShell(), Messages.LatencyView_Dialogs_ListEvents_Confirm_Title,\r
+ Messages.LatencyView_Dialogs_ListEvents_Confirm_Message);\r
+\r
+ if (confirmDeletion) {\r
+ EventMatcher.getInstance().resetMatches();\r
+\r
+ fTable.removeAll();\r
+\r
+ Vector<String> defaultStarts = new Vector<String>();\r
+ Vector<String> defaultEnds = new Vector<String>();\r
+\r
+ defaultStarts.add(EventMatcher.PAGE_FAULT_GET_USER_ENTRY);\r
+ defaultEnds.add(EventMatcher.PAGE_FAULT_GET_USER_EXIT);\r
+ defaultStarts.add(EventMatcher.TASKLET_LOW_ENTRY);\r
+ defaultEnds.add(EventMatcher.TASKLET_LOW_EXIT);\r
+ defaultStarts.add(EventMatcher.PAGE_FAULT_ENTRY);\r
+ defaultEnds.add(EventMatcher.PAGE_FAULT_EXIT);\r
+ defaultStarts.add(EventMatcher.SYSCALL_ENTRY);\r
+ defaultEnds.add(EventMatcher.SYSCALL_EXIT);\r
+ defaultStarts.add(EventMatcher.IRQ_ENTRY);\r
+ defaultEnds.add(EventMatcher.IRQ_EXIT);\r
+ defaultStarts.add(EventMatcher.READ);\r
+ defaultEnds.add(EventMatcher.WRITE);\r
+ defaultStarts.add(EventMatcher.OPEN);\r
+ defaultEnds.add(EventMatcher.CLOSE);\r
+ defaultStarts.add(EventMatcher.BUFFER_WAIT_START);\r
+ defaultEnds.add(EventMatcher.BUFFER_WAIT_END);\r
+ defaultStarts.add(EventMatcher.START_COMMIT);\r
+ defaultEnds.add(EventMatcher.END_COMMIT);\r
+ defaultStarts.add(EventMatcher.WAIT_ON_PAGE_START);\r
+ defaultEnds.add(EventMatcher.WAIT_ON_PAGE_END);\r
+\r
+ saveMatchPairs(defaultStarts, defaultEnds);\r
+\r
+ for (int i = 0; i < defaultStarts.size(); i++) {\r
+ EventMatcher.getInstance().addMatch(defaultStarts.get(i), defaultEnds.get(i));\r
+ }\r
+\r
+ // Get the list of start and end types from the EventMatcher\r
+ EventsPair pair = getMatchPairs();\r
+ fEventStartTypes = pair.getFirst();\r
+ fEventEndTypes = pair.getSecond();\r
+\r
+ for (int i = 0; i < fEventStartTypes.size(); i++) {\r
+ TableItem item = new TableItem(fTable, SWT.RIGHT);\r
+\r
+ String max = String.valueOf(fEventStartTypes.size());\r
+ String number = formatListNumber(i + 1, max.length());\r
+\r
+ String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) };\r
+\r
+ item.setText(columns);\r
+ }\r
+\r
+ fTable.setItemCount(fEventStartTypes.size());\r
+\r
+ fRedrawGraphs = true;\r
+ }\r
+ }\r
+ });\r
+\r
+ // Create the "Close" button\r
+ Button closeButton = createButton(parent, CANCEL, Messages.LatencyView_Dialogs_ListEvents_Buttons_Close, false);\r
+ closeButton.addListener(SWT.Selection, new Listener() {\r
+ @Override\r
+ public void handleEvent(Event event) {\r
+ setReturnCode(CANCEL);\r
+\r
+ if (fRedrawGraphs == true)\r
+ redrawGraphs();\r
+\r
+ close();\r
+ }\r
+ });\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>AbstractMouseListener</u></b>
+ * <p>
+ */
+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();
+}
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors: \r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation \r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Changed implemented interface to MouseTraceListener\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import org.eclipse.swt.events.MouseEvent;\r
+import org.eclipse.swt.events.MouseTrackListener;\r
+\r
+/**\r
+ * <b><u>AbstractMouseListener</u></b>\r
+ * <p>\r
+ * AbstractMouseListener, base class for the canvas mouse listener.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public abstract class AbstractMouseTrackListener implements MouseTrackListener {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Mouse x-coordinate.\r
+ */\r
+ protected int fMouseX;\r
+ /**\r
+ * Mouse y-coordinate.\r
+ */\r
+ protected int fMouseY;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.swt.events.MouseTrackListener#mouseEnter(org.eclipse.swt.events.MouseEvent)\r
+ */\r
+ @Override\r
+ public void mouseEnter(MouseEvent event) {\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.swt.events.MouseTrackListener#mouseExit(org.eclipse.swt.events.MouseEvent)\r
+ */\r
+ @Override\r
+ public void mouseExit(MouseEvent event) {\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.swt.events.MouseTrackListener#mouseHover(org.eclipse.swt.events.MouseEvent)\r
+ */\r
+ @Override\r
+ public void mouseHover(MouseEvent event) {\r
+ fMouseX = event.x;\r
+ fMouseY = event.y;\r
+ display();\r
+ }\r
+\r
+ /**\r
+ * Tooltip display callback.\r
+ */\r
+ protected abstract void display();\r
+\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Adapted to new model-view-controller design, display improvements\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.PaintEvent;\r
+import org.eclipse.swt.events.PaintListener;\r
+import org.eclipse.swt.graphics.Color;\r
+import org.eclipse.swt.graphics.Font;\r
+import org.eclipse.swt.graphics.GC;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.graphics.Rectangle;\r
+import org.eclipse.swt.widgets.Display;\r
+\r
+/**\r
+ * <b><u>AbstractPaintListener</u></b>\r
+ * <p> \r
+ * Abstract paint listener. Draws the graphs on the view canvas.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public abstract class AbstractPaintListener implements PaintListener {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Default colors and fonts\r
+ */\r
+ protected final Color DEFAULT_DATA_COLOR = new Color(Display.getDefault(), 74, 112, 139);\r
+ protected final static Color DEFAULT_LABEL_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_BLACK);\r
+ protected final static Color DEFAULT_TEXT_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY);\r
+ protected final static Color DEFAULT_DATA_BACKGROUND_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);\r
+ protected final static Color DEFAULT_CURRENT_EVENT_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_RED);\r
+\r
+ protected final Font DEFAULT_TITLE_FONT = new Font(Display.getDefault(), "Arial", 10, SWT.BOLD); //$NON-NLS-1$\r
+ protected final Font DEFAULT_VALUES_FONT = new Font(Display.getDefault(), "Arial", 7, SWT.NORMAL); //$NON-NLS-1$\r
+ protected final Font DEFAULT_LABEL_FONT = new Font(Display.getDefault(), "Arial", 8, SWT.NORMAL); //$NON-NLS-1$\r
+ \r
+ /**\r
+ * A reference to the listener's view.\r
+ */\r
+ protected AbstractViewer fViewer;\r
+\r
+ /**\r
+ * Graph title\r
+ */\r
+ protected String fGraphTitle;\r
+\r
+ /**\r
+ * X-axis label.\r
+ */\r
+ protected String fXAxisLabel;\r
+ \r
+ /**\r
+ * Y-axis label.\r
+ */\r
+ protected String fYAxisLabel;\r
+\r
+ /**\r
+ * Horizontal offset for the x-axis label.\r
+ */\r
+ protected int fXAxisLabelOffset;\r
+\r
+ /**\r
+ * Vertical offset for the horizontal axis offset.\r
+ */\r
+ protected int fHorizontalAxisYOffset = 20;\r
+\r
+ /**\r
+ * Graph padding.\r
+ */\r
+ protected int fPadding = Config.GRAPH_PADDING;\r
+\r
+ /**\r
+ * Graph client area.\r
+ */\r
+ protected Rectangle fClientArea = new Rectangle(0, 0, 1, 1);\r
+\r
+ /**\r
+ * Foreground color.\r
+ */\r
+ protected Color fForegroundColor;\r
+ \r
+ /**\r
+ * Background color.\r
+ */\r
+ protected Color fBackgroundColor;\r
+ \r
+ /**\r
+ * Data plotting color.\r
+ */\r
+ protected Color fDataColor;\r
+ \r
+ /**\r
+ * Axis label color.\r
+ */\r
+ protected Color fLabelColor;\r
+ \r
+ /**\r
+ * Text color.\r
+ */\r
+ protected Color fTextColor;\r
+ \r
+ /**\r
+ * Data background color.\r
+ */\r
+ protected Color fDataBackgroundColor;\r
+\r
+ /**\r
+ * Color for current event time line.\r
+ */\r
+ protected Color fCurrentEventColor;\r
+\r
+ /**\r
+ * Original canvas font.\r
+ */\r
+ protected Font fOriginalFont;\r
+\r
+ /**\r
+ * Font for the title of the graph.\r
+ */\r
+ protected Font fTitleFont;\r
+\r
+ /**\r
+ * Font for the values on the horizontal and vertical axis.\r
+ */\r
+ protected Font fValuesFont;\r
+\r
+ /**\r
+ * Font for the horizontal and vertical labels.\r
+ */\r
+ protected Font fLabelFont;\r
+\r
+ /**\r
+ * Horizontal offset for the axis arrow.\r
+ */\r
+ protected final int ARROW_DELTA_X = 10;\r
+\r
+ /**\r
+ * Vertical offset for the axis arrow.\r
+ */\r
+ protected final int ARROW_DELTA_Y = 4;\r
+\r
+ /**\r
+ * Max horizontal distance between ticks.\r
+ */\r
+ protected final int MAX_WIDTH_BETWEEN_TICKS = 40;\r
+\r
+ /**\r
+ * Max vertical distance between ticks.\r
+ */\r
+ protected final int MAX_HEIGHT_BETWEEN_TICKS = 30;\r
+\r
+ /**\r
+ * Max characters that can be displayed on the vertical axis.\r
+ */\r
+ protected final int MAX_CHAR_VERTICAL_DISPLAY = 5;\r
+\r
+ /**\r
+ * Draw label each "drawLabelEachNTicks_" ticks.\r
+ */\r
+ protected int fDrawLabelEachNTicks = 1;\r
+\r
+ /**\r
+ * Image drawn on the canvas.\r
+ */\r
+ protected Image fImage;\r
+\r
+ /**\r
+ * Paint canvas, where the values are plotted.\r
+ */\r
+ protected GC fAxisImage;\r
+\r
+ /**\r
+ * Is the paint listener initialized ?\r
+ */\r
+ protected boolean fInitialized = false;\r
+\r
+ /**\r
+ * Draw area.\r
+ */\r
+ protected Rectangle fDrawArea;\r
+\r
+ /**\r
+ * Right padding (in pixels).\r
+ */\r
+ protected int fPaddingRight = Config.GRAPH_PADDING;\r
+\r
+ /**\r
+ * Top padding (in pixels).\r
+ */\r
+ protected int fPaddingTop = Config.GRAPH_PADDING;\r
+\r
+ /**\r
+ * Vertical axis offset (in pixels).\r
+ */\r
+ protected int fVerticalAxisOffset = 2 * Config.GRAPH_PADDING;\r
+\r
+ /**\r
+ * Vertical axis factor for values (10^delta). When values larger than MAX_CHAR_VERTICAL_DISPLAY.\r
+ */\r
+ protected int fDelta = 0;\r
+\r
+ /**\r
+ * The barWidth of a bar\r
+ */\r
+ protected int fBarWith = Config.DEFAULT_HISTOGRAM_BAR_WIDTH;\r
+\r
+ /**\r
+ * Minimum value on horizontal axis\r
+ */\r
+ protected long fXMin = -1;\r
+\r
+ /**\r
+ * Maximum value on horizontal axis\r
+ */\r
+ protected long fXMax = -1;\r
+\r
+ /**\r
+ * Minimum value on vertical axis\r
+ */\r
+ protected long fYMin = -1;\r
+\r
+ /**\r
+ * Maximum value on vertical axis\r
+ */\r
+ protected long fYMax = -1;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructors\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Constructor.\r
+ * @param view\r
+ * A reference to the listener's view.\r
+ */\r
+ public AbstractPaintListener(AbstractViewer view) {\r
+ fViewer = view;\r
+ fDataColor = DEFAULT_DATA_COLOR;\r
+ fLabelColor = DEFAULT_LABEL_COLOR;\r
+ fTextColor = DEFAULT_TEXT_COLOR;\r
+ fDataBackgroundColor = DEFAULT_DATA_BACKGROUND_COLOR;\r
+ fCurrentEventColor = DEFAULT_CURRENT_EVENT_COLOR;\r
+ \r
+ fTitleFont = DEFAULT_TITLE_FONT;\r
+ fValuesFont = DEFAULT_VALUES_FONT;\r
+ fLabelFont = DEFAULT_LABEL_FONT;\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Accessors\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Returns the draw area height.\r
+ * @return The draw area height.\r
+ */\r
+ public double getHeight() {\r
+ return (fClientArea.height - 2.0 * fPadding - fHorizontalAxisYOffset - fPaddingTop);\r
+ }\r
+\r
+ /**\r
+ * Returns the histogram's draw area width.\r
+ * @return The histogram's draw area width.\r
+ */\r
+ public double getWidth() {\r
+ return (fClientArea.width - 2.0 * fPadding - fVerticalAxisOffset - fPaddingRight); // width of the plot area;\r
+ }\r
+\r
+ /**\r
+ * Returns the histogram's draw area padding.\r
+ * @return The histogram's draw area padding.\r
+ */\r
+ public int getPadding() {\r
+ return fPadding;\r
+ }\r
+\r
+ /**\r
+ * Returns the histogram's draw area top padding.\r
+ * @return The histogram's draw area top padding.\r
+ */\r
+ public int getPaddingTop() {\r
+ return fPaddingTop;\r
+ }\r
+\r
+ /**\r
+ * Returns the histogram's vertical axis offset.\r
+ * @return The histogram's vertical axis offset.\r
+ */\r
+ public int getVerticalAxisOffset() {\r
+ return fVerticalAxisOffset;\r
+ }\r
+\r
+ /**\r
+ * Returns the histogram's horizontal axis offset.\r
+ * @return The histogram's horizontal axis offset.\r
+ */\r
+ public int getHorizontalAxisYOffset() {\r
+ return fHorizontalAxisYOffset;\r
+ }\r
+\r
+ /**\r
+ * Returns the horizontal minimum value\r
+ * @return The horizontal minimum value.\r
+ */\r
+ public long getXMin() {\r
+ return fXMin;\r
+ }\r
+\r
+ /**\r
+ * Returns the horizontal maximum value\r
+ * @return The horizontal maximum value.\r
+ */\r
+ public long getXMax() {\r
+ return fXMax;\r
+ }\r
+\r
+ /**\r
+ * Returns the horizontal minimum value\r
+ * @return The horizontal minimum value.\r
+ */\r
+ public long getYMin() {\r
+ return fYMin;\r
+ }\r
+\r
+ /**\r
+ * Returns the vertical maximum value\r
+ * @return The vertical maximum value.\r
+ */\r
+ public long getYMax() {\r
+ return fYMax;\r
+ }\r
+ \r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Disposes local resources (e.g. colors or fonts)\r
+ */\r
+ public void dispose() {\r
+ DEFAULT_DATA_COLOR.dispose();\r
+ DEFAULT_TITLE_FONT.dispose();\r
+ DEFAULT_VALUES_FONT.dispose();\r
+ DEFAULT_LABEL_FONT.dispose();\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent)\r
+ */\r
+ @Override\r
+ public void paintControl(PaintEvent e) {\r
+ fClientArea = fViewer.getClientArea();\r
+\r
+ fForegroundColor = e.gc.getForeground();\r
+ fBackgroundColor = e.gc.getBackground();\r
+ fOriginalFont = e.gc.getFont();\r
+\r
+ scale();\r
+ \r
+ if (!fInitialized) {\r
+ fImage = new Image(Display.getDefault(), fViewer.getBounds());\r
+\r
+ fAxisImage = new GC(fImage);\r
+\r
+ fAxisImage.setForeground(fForegroundColor);\r
+ fAxisImage.setBackground(fBackgroundColor);\r
+ fAxisImage.fillRectangle(fImage.getBounds());\r
+\r
+ fInitialized = true;\r
+ }\r
+ \r
+ paintGraphTitle();\r
+ paintBackground(); \r
+ paintHorizontalAxis();\r
+ paintVerticalAxis();\r
+ paintContent();\r
+\r
+ e.gc.drawImage(fImage, 0, 0);\r
+ }\r
+\r
+ /**\r
+ * Paints the title of the graph.\r
+ */\r
+ public void paintGraphTitle() {\r
+ if (fGraphTitle != null) {\r
+ fAxisImage.setFont(fTitleFont);\r
+ fAxisImage.setForeground(fLabelColor);\r
+ fAxisImage.setBackground(fBackgroundColor);\r
+\r
+ int zoomFactor = fViewer.getZoomFactor() / fViewer.getZoomIncrement() + 1;\r
+ int labelWidth = fAxisImage.stringExtent(fGraphTitle).x;\r
+ // Draws the zoom factor in the title only if there is one\r
+ if (fViewer.getZoomFactor() > 1)\r
+ fAxisImage.drawText(fGraphTitle + " (" + zoomFactor + "x)", (fViewer.getBounds().width - fPadding - labelWidth) / 2, 0); //$NON-NLS-1$ //$NON-NLS-2$\r
+ else\r
+ fAxisImage.drawText(fGraphTitle, (fViewer.getBounds().width - fPadding - labelWidth) / 2, 0);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Paints the background of the draw area.\r
+ */\r
+ public void paintBackground() {\r
+ fAxisImage.setBackground(fDataBackgroundColor);\r
+\r
+ fAxisImage.fillRectangle(fPadding + fVerticalAxisOffset, fPadding + fPaddingTop, (int)getWidth() + 1, (int)getHeight());\r
+ }\r
+\r
+ /**\r
+ * Paints the horizontal axis.\r
+ */\r
+ public void paintHorizontalAxis() {\r
+ fAxisImage.setForeground(fForegroundColor);\r
+\r
+ int y = fClientArea.height - fPadding - fHorizontalAxisYOffset;\r
+\r
+ fAxisImage.drawLine(fClientArea.x + fPadding + fVerticalAxisOffset, y, fClientArea.width - fPadding, y);\r
+\r
+ paintHorizontalArrow(fClientArea.width - fPadding, y);\r
+ // Draw the axis graphic details only if there are some data points (i.e. do not draw the axis graphic details\r
+ // if the window timerange is so small that no latency can be computed, or if there are no matching events in\r
+ // the timerange (for example, when an experiment has many traces with a large time gap between the logged\r
+ // events sets).\r
+ if (fXMin != Long.MAX_VALUE && fXMax != Long.MIN_VALUE && fXMin != fXMax) {\r
+ paintHorizontalTicks(y);\r
+ paintHorizontalAxisValues(y + 30);\r
+ }\r
+ paintHorizontalAxisLabel(y + fHorizontalAxisYOffset - 5);\r
+ }\r
+\r
+ /**\r
+ * Paints the vertical axis.\r
+ */\r
+ public void paintVerticalAxis() {\r
+ fAxisImage.setForeground(fForegroundColor);\r
+\r
+ int x = fClientArea.x + fPadding + fVerticalAxisOffset;\r
+\r
+ fAxisImage.drawLine(x, fPadding, x, fClientArea.height - fPadding - fHorizontalAxisYOffset);\r
+\r
+ paintVerticalArrow(x, fClientArea.y + fPadding);\r
+ // Draw the axis graphic details only if there are some data points (i.e. do not draw the axis graphic details\r
+ // if the window timerange is so small that no latency can be computed, or if there are no matching events in\r
+ // the timerange (for example, when an experiment has many traces with a large time gap between the logged\r
+ // events sets).\r
+ if (fXMin != Long.MAX_VALUE && fXMax != Long.MIN_VALUE && fXMin != fXMax) {\r
+ paintVerticalTicks(x);\r
+ paintVerticalAxisValues(x);\r
+ }\r
+ paintVerticalAxisLabel(x);\r
+ }\r
+\r
+ /**\r
+ * Paints the arrow on the horizontal axis.\r
+ * @param x\r
+ * The x-coordinate of the point where the arrow points.\r
+ * @param y\r
+ * The y-coordinate of the point where the arrow points.\r
+ */\r
+ public void paintHorizontalArrow(int x, int y) {\r
+ // Arrow top line\r
+ fAxisImage.drawLine(x - ARROW_DELTA_X, y - ARROW_DELTA_Y, x, y);\r
+ // Arrow bottom line\r
+ fAxisImage.drawLine(x - ARROW_DELTA_X, y + ARROW_DELTA_Y, x, y);\r
+ }\r
+\r
+ /**\r
+ * Paints the arrow on the vertical axis.\r
+ * @param x\r
+ * The x-coordinate of the point where the arrow points.\r
+ * @param y\r
+ * The y-coordinate of the point where the arrow points.\r
+ */\r
+ public void paintVerticalArrow(int x, int y) {\r
+ // Arrow left line\r
+ fAxisImage.drawLine(x - ARROW_DELTA_Y, y + ARROW_DELTA_X, x, y);\r
+ // Arrow right line\r
+ fAxisImage.drawLine(x + ARROW_DELTA_Y, y + ARROW_DELTA_X, x, y);\r
+ }\r
+\r
+ /**\r
+ * Paints the horizontal ticks.\r
+ * @param y\r
+ * The y coordinate where to draw the axis.\r
+ */\r
+ public void paintHorizontalTicks(int y) {\r
+ if (fXMin >= 0L && fXMin >= 0L) {\r
+ int nbTicks = (int)(getWidth()) / MAX_WIDTH_BETWEEN_TICKS + 1;\r
+\r
+ for (int i = 0; i < nbTicks; i++) {\r
+ if (i % fDrawLabelEachNTicks == 0) {\r
+ int x = i * MAX_WIDTH_BETWEEN_TICKS + fPadding + fVerticalAxisOffset;\r
+ fAxisImage.drawLine(x, y, x, y + 3);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Paints the horizontal axis values.\r
+ * @param y\r
+ * The y coordinate where to draw the axis.\r
+ */\r
+ public void paintHorizontalAxisValues(int y) {\r
+ if (fXMin >= 0L && fXMax >= 0L) {\r
+ fAxisImage.setForeground(fTextColor);\r
+ fAxisImage.setBackground(fBackgroundColor);\r
+\r
+ double width = getWidth();\r
+ int nbTicks = ((int)getWidth()) / MAX_WIDTH_BETWEEN_TICKS + 1;\r
+\r
+ for (int i = 0; i < nbTicks; i++) {\r
+ if (i % fDrawLabelEachNTicks == 0) {\r
+ int x = i * MAX_WIDTH_BETWEEN_TICKS + fPadding + fVerticalAxisOffset;\r
+ \r
+ long currentValue = (i * MAX_WIDTH_BETWEEN_TICKS)* (long)((fXMax - fXMin) / width) + fXMin;\r
+ String currentLabel = formatStringForHorizontalAxis(currentValue);\r
+\r
+ fAxisImage.setFont(fValuesFont);\r
+ fAxisImage.drawText(currentLabel, x, y - 24);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Paints the horizontal axis label.\r
+ * @param y\r
+ * The y-coordinate where to draw the label.\r
+ */\r
+ public void paintHorizontalAxisLabel(int y) {\r
+ if (fXAxisLabel != null) {\r
+ fAxisImage.setFont(fLabelFont);\r
+ fAxisImage.setForeground(fLabelColor);\r
+\r
+ int labelWidth = fAxisImage.stringExtent(fXAxisLabel).x;\r
+\r
+ fAxisImage.drawText(fXAxisLabel, fClientArea.width - fPadding - labelWidth, y);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Paints the vertical axis ticks.\r
+ * @param x\r
+ * The x-coordinate where to draw the ticks.\r
+ */\r
+ public void paintVerticalTicks(int x) {\r
+ if (fYMin != 0L && fYMin != 0L) {\r
+ int nbTicks = (int)(getHeight() / MAX_HEIGHT_BETWEEN_TICKS + 1);\r
+\r
+ for (int i = 0; i < nbTicks; i++) {\r
+ int y = fClientArea.height - fPadding - fHorizontalAxisYOffset - i * MAX_HEIGHT_BETWEEN_TICKS;\r
+ fAxisImage.drawLine(x - 3, y, x, y);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Paints the vertical axis values.\r
+ * @param x\r
+ * The x-coordinate where to draw the values.\r
+ */\r
+ public void paintVerticalAxisValues(int x) {\r
+ if (fYMin >= 0L && fYMax >= 0L) {\r
+ fAxisImage.setForeground(fTextColor);\r
+ fAxisImage.setBackground(fBackgroundColor);\r
+\r
+ double height = getHeight();\r
+ int nbTicks = (int)(height / MAX_HEIGHT_BETWEEN_TICKS + 1);\r
+\r
+ // System.out.println("nbTicks = " + nbTicks);\r
+\r
+ for (int i = 0; i < nbTicks; i++) {\r
+ int y = fClientArea.height - fPadding - fHorizontalAxisYOffset - i * MAX_HEIGHT_BETWEEN_TICKS;\r
+\r
+ long currentValue = (i * MAX_HEIGHT_BETWEEN_TICKS)* (long)((fYMax - fYMin) / height) + fYMin;\r
+ String currentLabel = formatStringForVerticalAxis(currentValue);\r
+\r
+ fAxisImage.setFont(fValuesFont);\r
+\r
+ Point textDimensions = fAxisImage.stringExtent(currentLabel);\r
+ fAxisImage.drawText(currentLabel, x - textDimensions.x - 5, y - textDimensions.y / 2);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Increases the bar width. \r
+ */\r
+ public void increaseBarWitdh() {\r
+ fBarWith = fBarWith << 1;\r
+ if (fBarWith > Config.MAX_HISTOGRAM_BAR_WIDTH) {\r
+ fBarWith = Config.MAX_HISTOGRAM_BAR_WIDTH;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Decreases the bar width. \r
+ */\r
+ public void decreaseBarWitdh() {\r
+ fBarWith = fBarWith >> 1;\r
+ if (fBarWith < Config.MIN_HISTOGRAM_BAR_WIDTH) {\r
+ fBarWith = Config.MIN_HISTOGRAM_BAR_WIDTH; \r
+ }\r
+ }\r
+\r
+ \r
+ /**\r
+ * Paints the vertical axis label.\r
+ * @param x\r
+ * The x-coordinate where to draw the label.\r
+ */\r
+ public void paintVerticalAxisLabel(int x) {\r
+ if (fYAxisLabel != null) {\r
+ fAxisImage.setFont(fLabelFont);\r
+ fAxisImage.setForeground(fLabelColor);\r
+ fAxisImage.setBackground(fBackgroundColor);\r
+\r
+ if (fDelta >= 1)\r
+ fAxisImage.drawText(fYAxisLabel + " (x10^" + fDelta + ")", x + 10, fHorizontalAxisYOffset - 5); //$NON-NLS-1$//$NON-NLS-2$\r
+ else\r
+ fAxisImage.drawText(fYAxisLabel, x + 10, fPadding);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Adds points to the graph and draws them to the canvas.\r
+ * @param points\r
+ * The buffer of points to draw.\r
+ * @param nbPoints\r
+ * The number of points in the buffer.\r
+ */\r
+ abstract public String formatToolTipLabel(int x, int y);\r
+\r
+ /**\r
+ * Method to be implemented to scale the model data to the actual screen size.\r
+ */\r
+ abstract public void scale();\r
+ \r
+ /**\r
+ * Called for drawing elements after points are added to the graph.\r
+ */\r
+ abstract public void paintContent();\r
+\r
+ /**\r
+ * Clears the image and prepares it for redrawing.\r
+ */\r
+ public void clear() {\r
+ fInitialized = false;\r
+ fXMin = -1;\r
+ fXMax = -1;\r
+ fYMin = -1;\r
+ fYMax = -1;\r
+ }\r
+ \r
+ /**\r
+ * Draw horizontal label each "nbTicks" ticks.\r
+ * @param nbTicks\r
+ * The draw interval.\r
+ */\r
+ public void setDrawLabelEachNTicks(int nbTicks) {\r
+ fDrawLabelEachNTicks = nbTicks;\r
+ }\r
+\r
+ /**\r
+ * Sets the title of the graph.\r
+ * @param graphTitle\r
+ * The title of the graph.\r
+ */\r
+ public void setGraphTitle(String graphTitle) {\r
+ fGraphTitle = graphTitle;\r
+ }\r
+\r
+ /**\r
+ * Sets the horizontal axis label.\r
+ * @param xAxisLabel\r
+ * The horizontal axis label.\r
+ * @param offset\r
+ * The horizontal axis draw offset (in pixels).\r
+ */\r
+ public void setXAxisLabel(String xAxisLabel, int offset) {\r
+ fXAxisLabel = xAxisLabel;\r
+ fXAxisLabelOffset = offset;\r
+ }\r
+\r
+ /**\r
+ * Sets the vertical axis label.\r
+ * @param yAxisLabel\r
+ * The vertical axis label.\r
+ */\r
+ public void setYAxisLabel(String yAxisLabel) {\r
+ fYAxisLabel = yAxisLabel;\r
+ }\r
+\r
+ /**\r
+ * Returns a string representing the given value. \r
+ * \r
+ * @param value\r
+ * The numeric value to convert to String.\r
+ * @return The String-formatted value.\r
+ */\r
+ public String formatStringForHorizontalAxis(long value) {\r
+ return String.valueOf(value);\r
+ }\r
+\r
+ /**\r
+ * Returns a string representing the given value. \r
+ * \r
+ * @param value\r
+ * The numeric value to convert to String.\r
+ * @return The String-formatted value.\r
+ */\r
+ public String formatStringForVerticalAxis(long value) {\r
+ return String.valueOf(value);\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>GraphMouseListener</u></b>
+ * <p>
+ */
+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);
+ }
+}
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Adapted to new model-view-controller design, display improvements\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import java.text.DecimalFormat;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.distribution.model.BaseDistributionData;\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramUtils;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.GraphViewer;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.GraphScaledData;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphDataModel;\r
+\r
+/**\r
+ * <b><u>GraphPaintListener</u></b>\r
+ * <p>\r
+ * Graph paint listener.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class GraphPaintListener extends AbstractPaintListener {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Scaled data from data model\r
+ */\r
+ protected GraphScaledData fScaledData;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructors\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Constructor.\r
+ * @param viewer\r
+ * A reference to the listener's viewer.\r
+ */\r
+ public GraphPaintListener(AbstractViewer view) {\r
+ super(view);\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#scale()\r
+ */\r
+ @Override\r
+ public void scale() {\r
+ \r
+ // width of the plot area\r
+ double width = getWidth();\r
+ // height of the plot area\r
+ double height = getHeight();\r
+\r
+ IGraphDataModel model = ((GraphViewer)fViewer).getModel();\r
+ fScaledData = model.scaleTo((int)width, (int)height, fBarWith);\r
+\r
+ fXMin = fScaledData.getHorFirstBucketTime() > 0 ? fScaledData.getHorFirstBucketTime() : 0;\r
+ fXMax = 0;\r
+ if (fScaledData.getHorLastBucket() > 0) {\r
+ fXMax = fScaledData.getHorBucketEndTime(fScaledData.getHorNbBuckets() - 1);\r
+ }\r
+ \r
+ fYMin = fScaledData.getVerFirstBucketTime() > 0 ? fScaledData.getVerFirstBucketTime() : 0;\r
+ fYMax = 0;\r
+ if (fScaledData.getVerLastBucket() > 0) {\r
+ fYMax = fScaledData.getVerBucketEndTime(fScaledData.getVerNbBuckets() - 1);\r
+ }\r
+ }\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintContent()\r
+ */\r
+ @Override\r
+ public void paintContent() {\r
+ if (fXMin >= 0 && fXMax >= 0 && fYMin >= 0 && fYMax >= 0 && fScaledData != null) {\r
+ \r
+ fAxisImage.setForeground(fDataColor);\r
+ fAxisImage.setBackground(fDataColor);\r
+\r
+ double height = getHeight();\r
+\r
+ int xLen = fScaledData.getHorNbBuckets();\r
+ int yLen = fScaledData.getVerNbBuckets();\r
+\r
+ int barWidth = fScaledData.getBarWidth();\r
+ \r
+ for (int i = 0; i < xLen; i++) {\r
+ for (int j = 0; j < yLen; j++) {\r
+ if (fScaledData.getEventCount(i, j) > 0) {\r
+\r
+ double x = fPadding + i * barWidth + fVerticalAxisOffset + 1;\r
+ double y = fPadding + fPaddingTop + height - j * barWidth;\r
+\r
+ // Avoid over-drawing background area\r
+ int yBarWidth = fBarWith;\r
+ if (y - yBarWidth < fPadding + fPaddingTop) {\r
+ yBarWidth = (int) (y - fPadding - fPaddingTop);\r
+ }\r
+ int xBarWidth = fBarWith;\r
+ if(x + xBarWidth > fClientArea.width - fPadding - fPaddingRight) {\r
+ xBarWidth = (int)(fClientArea.width - fPadding - fPaddingRight - x); \r
+ }\r
+ fAxisImage.fillRectangle((int) x, (int) y - (int) yBarWidth, (int) xBarWidth, (int) yBarWidth);\r
+ }\r
+ }\r
+ }\r
+ \r
+ if (fScaledData.isCurrentEventTimeValid()) {\r
+ // Draw vertical line\r
+ int index = fScaledData.getHorBucketIndex(fScaledData.getCurrentEventTime());\r
+\r
+ int x = fPadding + index * barWidth + fVerticalAxisOffset + 1;\r
+ fAxisImage.setForeground(fCurrentEventColor);\r
+ fAxisImage.setBackground(fCurrentEventColor);\r
+ fAxisImage.drawLine(x, fPadding + fPaddingTop, x, fClientArea.height - fPadding - fHorizontalAxisYOffset);\r
+ }\r
+ }\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatStringForVerticalAxis(long)\r
+ */\r
+ @Override\r
+ public String formatStringForVerticalAxis(long value) {\r
+ DecimalFormat formatter = new DecimalFormat("0.0E0"); //$NON-NLS-1$\r
+ return formatter.format(value);\r
+ }\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatStringForHorizontalAxis(long)\r
+ */\r
+ @Override\r
+ public String formatStringForHorizontalAxis(long value) {\r
+ return HistogramUtils.nanosecondsToString(value);\r
+ }\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatToolTipLabel(int, int)\r
+ */\r
+ @Override\r
+ public String formatToolTipLabel(int x, int y) {\r
+\r
+ int index = getIndexFromHorizontalValue(x);\r
+ int yIndex = getIndexFromVerticalValue(y);\r
+\r
+ if (index != BaseDistributionData.OUT_OF_RANGE_BUCKET && yIndex != BaseDistributionData.OUT_OF_RANGE_BUCKET) {\r
+ if (fScaledData.getEventCount(index, yIndex) > 0) {\r
+ StringBuffer buffer = new StringBuffer();\r
+ buffer.append("Time Range in s = ["); //$NON-NLS-1$\r
+ // TODO change Utility\r
+ long startTime = fScaledData.getHorBucketStartTime(index) > 0 ? fScaledData.getHorBucketStartTime(index) : 0;\r
+ buffer.append(HistogramUtils.nanosecondsToString(startTime));\r
+ buffer.append(","); //$NON-NLS-1$\r
+ buffer.append(HistogramUtils.nanosecondsToString(fScaledData.getHorBucketEndTime(index)));\r
+ buffer.append("]\n"); //$NON-NLS-1$\r
+ buffer.append("Latency Range in s = ["); //$NON-NLS-1$\r
+ long yStartTime = fScaledData.getVerBucketStartTime(yIndex) > 0 ? fScaledData.getVerBucketStartTime(yIndex) : 0;\r
+ buffer.append(HistogramUtils.nanosecondsToString(yStartTime));\r
+ buffer.append(","); //$NON-NLS-1$\r
+ buffer.append(HistogramUtils.nanosecondsToString(fScaledData.getVerBucketEndTime(yIndex)));\r
+ buffer.append("]\n"); //$NON-NLS-1$\r
+ buffer.append("Latency count = "); //$NON-NLS-1$\r
+ buffer.append(fScaledData.getEventCount(index, yIndex));\r
+ return buffer.toString();\r
+ }\r
+ }\r
+ return ""; //$NON-NLS-1$\r
+ }\r
+ \r
+ public int getIndexFromHorizontalValue(int x) {\r
+ if (fScaledData != null) {\r
+ double barWidth = fScaledData.getBarWidth();\r
+ \r
+ int index = (int) ((x - fPadding - fVerticalAxisOffset - 1) / barWidth);\r
+ if ((index >= 0) && (fScaledData.getHorNbBuckets() > index)) {\r
+ return index;\r
+ }\r
+ }\r
+ return BaseDistributionData.OUT_OF_RANGE_BUCKET;\r
+ }\r
+ \r
+ public int getIndexFromVerticalValue(int y) {\r
+ if (fScaledData != null) {\r
+ double barWidth = fScaledData.getBarWidth();\r
+ double height = getHeight(); // height of the plot area\r
+ \r
+ int index = (int) ((height - (y - fPadding - fPaddingTop)) / barWidth);\r
+ if (index >= 0 && fScaledData.getVerNbBuckets() > index) {\r
+ return index;\r
+ }\r
+ }\r
+ return BaseDistributionData.OUT_OF_RANGE_BUCKET;\r
+ }\r
+\r
+ public long getCurrentTimeFromHorizontalValue(int x) {\r
+ if (fXMin >= 0 && fXMax >= 0) {\r
+ int index = getIndexFromHorizontalValue(x);\r
+ if (index != BaseDistributionData.OUT_OF_RANGE_BUCKET) {\r
+ return fScaledData.getHorBucketStartTime(index);\r
+ }\r
+ }\r
+ return Config.INVALID_EVENT_TIME;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Adapted to new model-view-controller design, display improvements\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import java.text.DecimalFormat;\r
+import java.util.Collections;\r
+import java.util.Vector;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramScaledData;\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramUtils;\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramDataModel;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.HistogramViewer;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.Messages;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+\r
+/**\r
+ * <b><u>HistogramPaintListener</u></b>\r
+ * <p>\r
+ * Histogram paint listener.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class HistogramPaintListener extends AbstractPaintListener {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Is a histogram bar so high that it is clipped from the draw area ?\r
+ */\r
+ private boolean fBarIsClipped = false;\r
+\r
+ /**\r
+ * Scaled data from data model\r
+ */\r
+ protected HistogramScaledData fScaledData;\r
+\r
+ /**\r
+ * Warning Image\r
+ */\r
+ protected Image fWarningImage;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructors\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Constructor.\r
+ * @param view\r
+ * A reference to the listener's viewer.\r
+ */\r
+ public HistogramPaintListener(AbstractViewer viewer) {\r
+ super(viewer);\r
+ fWarningImage = AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/warning.gif").createImage(Display.getCurrent()); //$NON-NLS-1$\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Accessors\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Returns the histogram's bar Width.\r
+ * @return The histogram's bar Width.\r
+ */\r
+ public int getBarWidth() {\r
+ return fBarWith;\r
+ }\r
+ \r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#dispose()\r
+ */\r
+ @Override\r
+ public void dispose() {\r
+ fWarningImage.dispose();\r
+ super.dispose();\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#scale()\r
+ */\r
+ @Override\r
+ public void scale() {\r
+ // width of the plot area\r
+ double width = getWidth();\r
+ // height of the plot area\r
+ double height = getHeight();\r
+\r
+ int barWidth = getBarWidth();\r
+\r
+ IHistogramDataModel model = ((HistogramViewer)fViewer).getModel();\r
+ fScaledData = model.scaleTo((int)width, (int)height, barWidth);\r
+\r
+ fYMin = 0;\r
+ fYMax = fScaledData.fMaxValue;\r
+\r
+ fXMin = fScaledData.getFirstBucketTime();\r
+ fXMin = fXMin > 0 ? fXMin : 0; \r
+ fXMax = fScaledData.getBucketEndTime(fScaledData.fLastBucket - 1);\r
+\r
+ // No data to display - set end time to 0 \r
+ if (fYMax == 0) {\r
+ fXMax = 0;\r
+ }\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintVerticalTicks(int)\r
+ */\r
+ @Override\r
+ public void paintVerticalTicks(int x) {\r
+ // done in method paintVerticalAxisValues()\r
+ }\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintVerticalAxisValues(int)\r
+ */\r
+ @Override\r
+ public void paintVerticalAxisValues(int x) {\r
+ int zoomFactor = 1;\r
+\r
+ zoomFactor = fViewer.getZoomFactor();\r
+\r
+ if (fYMin >= 0L && fYMax != 0L) {\r
+ fAxisImage.setForeground(fTextColor);\r
+ fAxisImage.setBackground(fBackgroundColor);\r
+\r
+ // Apply the zoom to the max value of the graph for the next calculations\r
+ long yMax = fYMax / zoomFactor;\r
+\r
+ int nbTicks = ((int)getHeight()) / MAX_HEIGHT_BETWEEN_TICKS + 1;\r
+\r
+ Vector<Integer> values = new Vector<Integer>();\r
+ boolean multipleSameValues = true;\r
+ while (multipleSameValues) {\r
+ double valueStep = (double) (yMax - fYMin) / (double) (nbTicks);\r
+\r
+ for (int i = 0; i < nbTicks; i++) {\r
+ double currentValue = (double) (fYMin + i * valueStep) / (Math.pow(10, fDelta));\r
+\r
+ values.add((int) currentValue);\r
+ }\r
+\r
+ Collections.sort(values);\r
+ boolean hasRepetition = false;\r
+ for (int i = 1; i < values.size(); i++) {\r
+ if (values.get(i) == values.get(i - 1)) {\r
+ hasRepetition = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (hasRepetition) {\r
+ nbTicks--;\r
+ values.clear();\r
+ } else {\r
+ multipleSameValues = false;\r
+\r
+ // Draw rectangle over the old values\r
+ int height = fViewer.getBounds().height - 2 * fPadding - fPaddingTop - fHorizontalAxisYOffset;\r
+ fAxisImage.fillRectangle(0, fPadding + fPaddingTop, fPadding + fVerticalAxisOffset, height);\r
+\r
+ double pixelStep = (getHeight()) / values.size() + 1;\r
+\r
+ for (int i = 0; i < values.size(); i++) {\r
+ double currentValue = values.get(i);\r
+\r
+ int y = (int) (fClientArea.height - fPadding - fHorizontalAxisYOffset - i * pixelStep);\r
+ String currentLabel = formatStringForVerticalAxis((long) currentValue);\r
+\r
+ fAxisImage.setFont(fValuesFont);\r
+\r
+ Point textDimensions = fAxisImage.stringExtent(currentLabel);\r
+ fAxisImage.drawText(currentLabel, x - textDimensions.x - 5, y - textDimensions.y / 2);\r
+ fAxisImage.drawLine(x - 3, y, x, y);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintContent()\r
+ */\r
+ @Override\r
+ public void paintContent() {\r
+ double zoomFactor = fViewer.getZoomFactor();\r
+\r
+ // Calculate the vertical axis factor and see if it has changed\r
+ double tmpDelta = fDelta;\r
+ fDelta = 0;\r
+ if (Long.toString(fYMax / (long) zoomFactor).length() > MAX_CHAR_VERTICAL_DISPLAY) {\r
+ fDelta = Long.toString(fYMax / (long) zoomFactor).length() - MAX_CHAR_VERTICAL_DISPLAY;\r
+ }\r
+ if (tmpDelta != fDelta) {\r
+ fViewer.clearBackground();\r
+ }\r
+\r
+ paintBackground();\r
+ paintVerticalAxis();\r
+ paintHorizontalAxis();\r
+\r
+ fAxisImage.setForeground(fDataColor);\r
+ fAxisImage.setBackground(fDataColor);\r
+\r
+ // height of the plot area\r
+ double height = getHeight();\r
+\r
+ int barWidth = getBarWidth();\r
+ \r
+ // axisImage_.setBackground(backgroundColor_);\r
+ // 1.a Iterate over the points, from 0 to nbPoints\r
+ // 1.b Find the max counter value\r
+ // 2. Assign the max value to the "yMax_" class attribute\r
+ // 3. Draw the histogram bars using "axisImage_.fillRectangle(...)"\r
+ boolean oneBarIsClipped = false;\r
+\r
+ for (int i = 0; i < fScaledData.fData.length; i++) {\r
+ double pointY = fScaledData.fData[i];\r
+\r
+ // in pixels\r
+ double x = fPadding + i * barWidth + fVerticalAxisOffset + 1;\r
+\r
+ if (i == fScaledData.fData.length - 1)\r
+ x -= 1.0;\r
+ double barHeight = zoomFactor * ((double)(pointY - fYMin) / (double)(fYMax - fYMin)) * height;\r
+\r
+ if (barHeight > height + 1) {\r
+ barHeight = height;\r
+ oneBarIsClipped = true;\r
+\r
+ fAxisImage.drawImage(fWarningImage, 5, 3);\r
+ }\r
+\r
+ // Only draw the bars that have a barHeight of more than 1 pixel\r
+ if (barHeight > 0) {\r
+ double y = fPadding + fPaddingTop + height - barHeight;\r
+ fAxisImage.setBackground(fDataColor);\r
+\r
+ if (barHeight > height - 1) {\r
+ fAxisImage.fillRectangle((int) x, (int) y, (int) barWidth, (int) (barHeight + 1));\r
+ } else {\r
+ fAxisImage.fillRectangle((int) x, (int) y, (int) barWidth, (int) (barHeight + 2));\r
+ }\r
+ }\r
+ }\r
+\r
+ if (oneBarIsClipped)\r
+ fBarIsClipped = true;\r
+ else\r
+ fBarIsClipped = false;\r
+ }\r
+ \r
+ /**\r
+ * Paints the histogram horizontal axis values in engineering notation in which the exponent is a multiple of three.\r
+ * @param value\r
+ * The numeric value to convert to engineering notation.\r
+ * @return The given value formatted according to the engineering notation.\r
+ */\r
+ @Override\r
+ public String formatStringForHorizontalAxis(long value) {\r
+ DecimalFormat formatter = new DecimalFormat("##0.#E0"); //$NON-NLS-1$\r
+ return formatter.format(value);\r
+ }\r
+\r
+ /**\r
+ * Sets the bar width.\r
+ * @param barWidth \r
+ * bar width to set\r
+ */\r
+ public void setBarWidth(int barWidth) {\r
+ fBarWith = barWidth;\r
+ }\r
+ \r
+ /**\r
+ * Returns "true" if a histogram bar is so high that it cannot be drawn in the draw area, "false" otherwise.\r
+ * @return "true" if a histogram bar is so high that it cannot be drawn in the draw area, "false" otherwise.\r
+ */\r
+ public boolean barIsClipped() {\r
+ return fBarIsClipped;\r
+ }\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatToolTipLabel(int, int)\r
+ */\r
+ @Override\r
+ public String formatToolTipLabel(int x, int y) {\r
+ if (fScaledData != null) {\r
+\r
+ double barWidth = getBarWidth();\r
+ double height = getHeight(); // height of the plot area\r
+ \r
+ double zoomFactor = fViewer.getZoomFactor();\r
+\r
+ int index = (int) ((x - fPadding - fVerticalAxisOffset - 1) / barWidth);\r
+\r
+ double barHeight = 0.0;\r
+ if (index >= 0 && index <= fScaledData.fLastBucket) {\r
+ barHeight = (zoomFactor * height * (fScaledData.fData[index] - fYMin) / (fYMax - fYMin));\r
+ }\r
+\r
+ long fMouseY = (long) (height - (y - fPadding - fPaddingTop));\r
+\r
+ // Verifying mouse pointer is over histogram bar\r
+ if (index >= 0 && fScaledData.fLastBucket >= index && fMouseY >= 0 && fMouseY < barHeight && fMouseY < height && x >= (fVerticalAxisOffset + fPadding)) {\r
+\r
+ fScaledData.fCurrentBucket = index;\r
+\r
+ long startTime = fScaledData.getBucketStartTime(index);\r
+ // negative values are possible if time values came into the model in decreasing order\r
+ if (startTime < 0) {\r
+ startTime = 0;\r
+ }\r
+ long endTime = fScaledData.getBucketEndTime(index);\r
+ int nbEvents = fScaledData.fData[index];\r
+\r
+ StringBuffer buffer = new StringBuffer();\r
+ buffer.append("Latency Range in s = ["); //$NON-NLS-1$\r
+ buffer.append(HistogramUtils.nanosecondsToString(startTime));\r
+ buffer.append(","); //$NON-NLS-1$\r
+ buffer.append(HistogramUtils.nanosecondsToString(endTime));\r
+ buffer.append("]\n"); //$NON-NLS-1$\r
+ buffer.append("Latency count = "); //$NON-NLS-1$\r
+ buffer.append(nbEvents);\r
+ return buffer.toString();\r
+ }\r
+ }\r
+ return ""; //$NON-NLS-1$\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Changed display interface implementation \r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer;\r
+\r
+/**\r
+ * <b><u>TimePointerListener</u></b>\r
+ * <p>\r
+ * Displays a tooltip showing the approximate values of the point under the mouse cursor.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class TimePointerListener extends AbstractMouseTrackListener {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * A reference to the observed view.\r
+ */\r
+ protected AbstractViewer fView;\r
+\r
+ /**\r
+ * A reference to the HistogramPaintListener.\r
+ */\r
+ protected GraphPaintListener fGraph;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructors\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Constructor.\r
+ * @param view\r
+ * A reference to the observed view.\r
+ * @param histogramPaintListener\r
+ * A reference to the histogram's paintListener.\r
+ */\r
+ public TimePointerListener(AbstractViewer view, GraphPaintListener graphPaintListener) {\r
+ fView = view;\r
+ fGraph = graphPaintListener;\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseTrackListener#display()\r
+ */\r
+ @Override\r
+ protected void display() {\r
+ fView.setToolTipText(fGraph.formatToolTipLabel(fMouseX, fMouseY));\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Bernd Hufmann - Changed display interface implementation\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.Messages;\r
+\r
+/**\r
+ * <b><u>TooltipListener</u></b>\r
+ * <p>\r
+ * Tooltip listener, displays the event count for each latency selected by the mouse click area on histogram.\r
+ * \r
+ * @author Ali Jawhar\r
+ */\r
+public class TooltipListener extends AbstractMouseTrackListener {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * A reference to the observed view.\r
+ */\r
+ protected AbstractViewer fView;\r
+\r
+ /**\r
+ * A reference to the HistogramPaintListener.\r
+ */\r
+ protected HistogramPaintListener fHistogram;\r
+\r
+ /**\r
+ * Is the mouse over the warning icon, indicating that a bar is higher than the draw area due to zooming ?\r
+ */\r
+ protected boolean fDisplayWarning = false;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructors\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Constructor.\r
+ * @param view\r
+ * A reference to the observed view.\r
+ * @param histogramPaintListener\r
+ * A reference to the histogram's paintListener.\r
+ */\r
+ public TooltipListener(AbstractViewer view, HistogramPaintListener histogramPaintListener) {\r
+ fView = view;\r
+ fHistogram = histogramPaintListener;\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseTrackListener#display()\r
+ */\r
+ @Override\r
+ protected void display() {\r
+ displayWarningTooltip();\r
+ displayTooltip();\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Helper Functions\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /**\r
+ * Displays a tooltip if the mouse is over the warning icon indication that a bar cannot be draw entirely due to the\r
+ * zoom factor.\r
+ */\r
+ protected void displayWarningTooltip() {\r
+ if (fHistogram.barIsClipped() && fMouseX > 5 && fMouseX < 21 && fMouseY > 3 && fMouseY < 18) {\r
+ fView.setToolTipText(Messages.LatencyView_ClippingWarning);\r
+ fDisplayWarning = true;\r
+ } else {\r
+ fDisplayWarning = false;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Displays the tooltip showing the details of the histogram bar pointed by the mouse.\r
+ */\r
+ protected void displayTooltip() {\r
+ if (!fDisplayWarning)\r
+ fView.setToolTipText(fHistogram.formatToolTipLabel(fMouseX, fMouseY));\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.widgets.Canvas;\r
+import org.eclipse.swt.widgets.Event;\r
+import org.eclipse.swt.widgets.Listener;\r
+\r
+/**\r
+ * <b><u>ZoomListener</u></b>\r
+ * <p>\r
+ * \r
+ * Canvas zoom listener.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class ZoomListener implements Listener {\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Attributes\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * A reference to the observed view.\r
+ */\r
+ protected AbstractViewer fView;\r
+ /**\r
+ * Default zoom factor.\r
+ */\r
+ protected int fZoomFactor;\r
+ /**\r
+ * Zoom increment.\r
+ */\r
+ protected int fZoomIncrement = 30;\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Constructors\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Constructor.\r
+ * @param view\r
+ * A reference to the observed view.\r
+ * @param defaultZoomFactor\r
+ * Default zoom factor.\r
+ */\r
+ public ZoomListener(AbstractViewer view, int defaultZoomFactor) {\r
+ fView = view;\r
+ fZoomFactor = defaultZoomFactor;\r
+ }\r
+\r
+ /**\r
+ * Constructor.\r
+ * @param view\r
+ * A reference to the observed view.\r
+ */\r
+ public ZoomListener(AbstractViewer view) {\r
+ this(view, 1);\r
+ }\r
+\r
+ // ------------------------------------------------------------------------\r
+ // Accessors\r
+ // ------------------------------------------------------------------------\r
+\r
+ /**\r
+ * Returns the zoom factor.\r
+ * @return The zoom factor.\r
+ */\r
+ public int getZoomFactor() {\r
+ if (fZoomFactor < 1)\r
+ return 1;\r
+ else\r
+ return fZoomFactor;\r
+ }\r
+\r
+ /**\r
+ * Returns the zoom increment.\r
+ * @return The zoom increment.\r
+ */\r
+ public int getZoomIncrement() {\r
+ return fZoomIncrement;\r
+ }\r
+ \r
+ // ------------------------------------------------------------------------\r
+ // Operations\r
+ // ------------------------------------------------------------------------\r
+ \r
+ /*\r
+ * (non-Javadoc)\r
+ * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)\r
+ */\r
+ @Override\r
+ public void handleEvent(Event event) {\r
+ switch (event.type) {\r
+ case SWT.MouseWheel:\r
+ boolean scrollDown = (event.count == 0 ? false : (event.count > 0 ? false : true));\r
+ int zoomStep = fZoomIncrement;\r
+ if (scrollDown)\r
+ zoomStep = -fZoomIncrement;\r
+ fZoomFactor = Math.max(0, fZoomFactor + zoomStep);\r
+\r
+ Canvas canvas = (Canvas) event.widget;\r
+ if (fView != null) {\r
+ // clear the background to allow redraw of values of the vertical axis.\r
+ fView.clearBackground();\r
+ fView.redrawTitle();\r
+ fView.askForRedraw();\r
+ }\r
+ canvas.redraw();\r
+ break;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Sets the zoom increment.\r
+ * @param zoomIncrement\r
+ * The new zoom increment.\r
+ */\r
+ public void setZoomIncrement(int zoomIncrement) {\r
+ fZoomIncrement = zoomIncrement;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+#*******************************************************************************\r
+# Copyright (c) 2011 Ericsson\r
+# \r
+# All rights reserved. This program and the accompanying materials are\r
+# made available under the terms of the Eclipse Public License v1.0 which\r
+# accompanies this distribution, and is available at\r
+# http://www.eclipse.org/legal/epl-v10.html\r
+# \r
+# Contributors:\r
+# Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+# Bernd Hufmann - Updated and added properties \r
+# *******************************************************************************/\r
+\r
+LatencyView_ViewName=LatencyView\r
+LatencyView_Action_IncreaseBarWidth_Tooltip=Increase bar width/height\r
+LatencyView_Action_DecreaseBarWidth_Tooltip=Decrease bar width/height\r
+LatencyView_Action_AddEvents_Tooltip=Add matching events\r
+LatencyView_Action_DeleteEvents_Tooltip=Delete matching events\r
+LatencyView_Action_ListEvents_Tooltip=List matching events\r
+LatencyView_Dialogs_AddEvents_Title=Add event pairs\r
+LatencyView_Dialogs_AddEvents_Message=Select a pair of events to add it to the match list :\r
+LatencyView_Dialogs_AddEvents_Buttons_Add=Add\r
+LatencyView_Dialogs_AddEvents_Buttons_Close=Close\r
+LatencyView_Dialogs_AddEvents_Columns_Start=Start event types\r
+LatencyView_Dialogs_AddEvents_Columns_End=End event types\r
+LatencyView_Dialogs_AddEvents_Columns_List_Trigger=Trigger event type\r
+LatencyView_Dialogs_AddEvents_Columns_List_End=End event type\r
+LatencyView_Dialogs_AddEvents_Errors_NoSelection=You must select one item from both lists_\r
+LatencyView_Dialogs_AddEvents_Errors_StartNotSelected=You must select one item from the start event list_\r
+LatencyView_Dialogs_AddEvents_Errors_EndNotSelected=You must select one item from the end event list_\r
+LatencyView_Dialogs_AddEvents_Errors_SameSelected=The same event cannot be selected in both list at the same time_\r
+LatencyView_Dialogs_AddEvents_Errors_AlreadyMatched=The start and end events are already matched_\r
+LatencyView_Dialogs_AddEvents_Errors_StartAlreadyMatched=The start event is already matched_\r
+LatencyView_Dialogs_AddEvents_Errors_EndAlreadyMatched=The end event is already matched_\r
+LatencyView_Dialogs_AddEvents_Errors_StartAsEnd=The start event is already matched as an end event_\r
+LatencyView_Dialogs_AddEvents_Errors_EndAsStart=The end event is already matched as a start event_\r
+LatencyView_Dialogs_DeleteEvents_Title=Delete event pairs\r
+LatencyView_Dialogs_DeleteEvents_Message=Select a pair of matched events to remove it from the list :\r
+LatencyView_Dialogs_DeleteEvents_Buttons_Close=Close\r
+LatencyView_Dialogs_DeleteEvents_Buttons_Delete=Delete\r
+LatencyView_Dialogs_DeleteEvents_Confirm_Title=Confirm event deletion\r
+LatencyView_Dialogs_DeleteEvents_Confirm_Message=Are you sure you want to delete these event pairs?\r
+LatencyView_Dialogs_ListEvents_Title=Matched events list\r
+LatencyView_Dialogs_ListEvents_Message=List of matched events for latency computation :\r
+LatencyView_Dialogs_ListEvents_Buttons_Close=Close\r
+LatencyView_Dialogs_ListEvents_Buttons_Reset=Reset to default pairs\r
+LatencyView_Dialogs_ListEvents_Columns_Trigger=Trigger event type\r
+LatencyView_Dialogs_ListEvents_Columns_End=End event type\r
+LatencyView_Dialogs_ListEvents_Confirm_Title=Confirm pairs reset\r
+LatencyView_Dialogs_ListEvents_Confirm_Message=Are you sure you want to reset the event pairs to their default values?\r
+LatencyView_Graphs_Graph_Title=Latency vs Time\r
+LatencyView_Graphs_Graph_XAxisLabel=time (s)\r
+LatencyView_Graphs_Graph_YAxisLabel=latency (ms)\r
+LatencyView_Graphs_Histogram_Title=Latency Distribution\r
+LatencyView_Graphs_Histogram_XAxisLabel=latency (ms)\r
+LatencyView_Graphs_Histogram_YAxisLabel=# events\r
+LatencyView_msgSlogan=Latency View\r
+LatencyView_tmf_UI=org.eclipse.linuxtools.lttng.ui\r
+LatencyView_ClippingWarning=One or more bars are higher than the drawing area due to zooming
\ No newline at end of file
--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactor code\r
+ * Bernd Hufmann - Added and updated constants\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.model;\r
+\r
+/**\r
+ * <b><u>Config</u></b>\r
+ * <p>\r
+ * Configuration class, holds some application constants.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class Config {\r
+\r
+ /**\r
+ * Private constructor to defeat instantiation.\r
+ */\r
+ private Config() {\r
+ }\r
+\r
+ /**\r
+ * Time scale for TMF events;\r
+ */\r
+ public static byte TIME_SCALE = -9;\r
+ \r
+ /**\r
+ * Size of the point buffer holding point values before sending them to the view.\r
+ */\r
+ public static final int POINT_BUFFER_SIZE = 10000;\r
+\r
+ /**\r
+ * Histogram bar width.\r
+ */\r
+ public static final int DEFAULT_HISTOGRAM_BAR_WIDTH = 2;\r
+ \r
+ /**\r
+ * Histogram bar width increase step.\r
+ */\r
+ public static final int MIN_HISTOGRAM_BAR_WIDTH = 1;\r
+\r
+ /**\r
+ * Histogram bar width increase step.\r
+ */\r
+ public static final int MAX_HISTOGRAM_BAR_WIDTH = 16;\r
+\r
+ \r
+ /**\r
+ * Diameter of a point drawn on the chart (in pixels).\r
+ */\r
+ public static final int GRAPH_POINT_DIAMETER = 1;\r
+\r
+ /**\r
+ * Graph padding.\r
+ */\r
+ public static final int GRAPH_PADDING = 10;\r
+\r
+ /**\r
+ * Default number of buckets used in data models\r
+ */\r
+ public static final int DEFAULT_NUMBER_OF_BUCKETS = 2 * 1000;\r
+ \r
+ /**\r
+ * Invalid event time\r
+ */\r
+ public static final long INVALID_EVENT_TIME = -1;\r
+}
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>GraphScaledData</u></b>
+ * Convenience class for scaled distribution data.
+ * <p>
+ */
+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;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>IGraphDataModel</u></b>
+ * <p>
+ */
+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);
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>IGraphModelListener</u></b>
+ * <p>
+ */
+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);
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>LatencyController</u></b>
+ * <p>
+ */
+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);
+ }
+ }
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>LatencyEventRequest</u></b>
+ * <p>
+ */
+public class LatencyEventRequest extends TmfEventRequest<LttngEvent> {
+
+ // ------------------------------------------------------------------------
+ // 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();
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+/**
+ * <b><u>LatencyGraphModel</u></b>
+ * <p>
+ */
+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);
+ }
+ }
+}