lttng: More luna annotation updates
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / views / histogram / HistogramDataModel.java
CommitLineData
c392540b 1/*******************************************************************************
11252342 2 * Copyright (c) 2011, 2013 Ericsson
bfe038ff 3 *
c392540b
FC
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
bfe038ff 8 *
c392540b
FC
9 * Contributors:
10 * Francois Chouinard - Initial API and implementation
bfe038ff 11 * Bernd Hufmann - Implementation of new interfaces/listeners and support for
fbd124dd 12 * time stamp in any order
e0752744 13 * Francois Chouinard - Moved from LTTng to TMF
00419b1f 14 * Francois Chouinard - Added support for empty initial buckets
0fcf3b09 15 * Patrick Tasse - Support selection range
c392540b
FC
16 *******************************************************************************/
17
e0752744 18package org.eclipse.linuxtools.tmf.ui.views.histogram;
c392540b
FC
19
20import java.util.Arrays;
21
fbd124dd 22import org.eclipse.core.runtime.ListenerList;
c392540b
FC
23
24/**
b544077e 25 * Histogram-independent data model.
f8177ba2 26 *
b544077e 27 * It has the following characteristics:
c392540b
FC
28 * <ul>
29 * <li>The <i>basetime</i> is the timestamp of the first event
30 * <li>There is a fixed number (<i>n</i>) of buckets of uniform duration
31 * (<i>d</i>)
32 * <li>The <i>timespan</i> of the model is thus: <i>n</i> * <i>d</i> time units
33 * <li>Bucket <i>i</i> holds the number of events that occurred in time range:
34 * [<i>basetime</i> + <i>i</i> * <i>d</i>, <i>basetime</i> + (<i>i</i> + 1) *
35 * <i>d</i>)
36 * </ul>
37 * Initially, the bucket durations is set to 1ns. As the events are read, they
38 * are tallied (using <i>countEvent()</i>) in the appropriate bucket (relative
39 * to the <i>basetime</i>).
40 * <p>
41 * Eventually, an event will have a timestamp that exceeds the <i>timespan</i>
42 * high end (determined by <i>n</i>, the number of buckets, and <i>d</i>, the
43 * bucket duration). At this point, the histogram needs to be compacted. This is
44 * done by simply merging adjacent buckets by pair, in effect doubling the
45 * <i>timespan</i> (<i>timespan'</i> = <i>n</i> * <i>d'</i>, where <i>d'</i> =
46 * 2<i>d</i>). This compaction happens as needed as the trace is read.
47 * <p>
fbd124dd 48 * The model allows for timestamps in not increasing order. The timestamps can
bfe038ff 49 * be fed to the model in any order. If an event has a timestamp less than the
fbd124dd 50 * <i>basetime</i>, the buckets will be moved to the right to account for the
bfe038ff 51 * new smaller timestamp. The new <i>basetime</i> is a multiple of the bucket
fbd124dd
BH
52 * duration smaller then the previous <i>basetime</i>. Note that the <i>basetime</i>
53 * might not be anymore a timestamp of an event. If necessary, the buckets will
bfe038ff 54 * be compacted before moving to the right. This might be necessary to not
fbd124dd
BH
55 * loose any event counts at the end of the buckets array.
56 * <p>
c392540b
FC
57 * The mapping from the model to the UI is performed by the <i>scaleTo()</i>
58 * method. By keeping the number of buckets <i>n</i> relatively large with
59 * respect to to the number of pixels in the actual histogram, we should achieve
60 * a nice result when visualizing the histogram.
61 * <p>
f8177ba2 62 *
00419b1f 63 * @version 2.0
b544077e 64 * @author Francois Chouinard
c392540b 65 */
fbd124dd 66public class HistogramDataModel implements IHistogramDataModel {
c392540b
FC
67
68 // ------------------------------------------------------------------------
69 // Constants
70 // ------------------------------------------------------------------------
71
b544077e
BH
72 /**
73 * The default number of buckets
74 */
c392540b
FC
75 public static final int DEFAULT_NUMBER_OF_BUCKETS = 16 * 1000;
76
b544077e 77 /**
f8177ba2 78 * Number of events after which listeners will be notified.
b544077e 79 */
fbd124dd 80 public static final int REFRESH_FREQUENCY = DEFAULT_NUMBER_OF_BUCKETS;
bfe038ff 81
c392540b
FC
82 // ------------------------------------------------------------------------
83 // Attributes
84 // ------------------------------------------------------------------------
85
86 // Bucket management
87 private final int fNbBuckets;
88 private final long[] fBuckets;
89 private long fBucketDuration;
90 private long fNbEvents;
91 private int fLastBucket;
92
93 // Timestamps
fbd124dd 94 private long fFirstBucketTime; // could be negative when analyzing events with descending order!!!
c392540b
FC
95 private long fFirstEventTime;
96 private long fLastEventTime;
0fcf3b09
PT
97 private long fSelectionBegin;
98 private long fSelectionEnd;
c392540b 99 private long fTimeLimit;
bfe038ff 100
e0752744 101 // Private listener lists
fbd124dd 102 private final ListenerList fModelListeners;
bfe038ff 103
e0752744
FC
104 // ------------------------------------------------------------------------
105 // Constructors
106 // ------------------------------------------------------------------------
107
b544077e
BH
108 /**
109 * Default constructor with default number of buckets.
110 */
c392540b 111 public HistogramDataModel() {
00419b1f
FC
112 this(0, DEFAULT_NUMBER_OF_BUCKETS);
113 }
114
115 /**
116 * Default constructor with default number of buckets.
117 * @param startTime The histogram start time
118 * @since 2.0
119 */
120 public HistogramDataModel(long startTime) {
121 this(startTime, DEFAULT_NUMBER_OF_BUCKETS);
c392540b
FC
122 }
123
b544077e
BH
124 /**
125 * Constructor with non-default number of buckets.
126 * @param nbBuckets A number of buckets.
127 */
c392540b 128 public HistogramDataModel(int nbBuckets) {
00419b1f
FC
129 this(0, nbBuckets);
130 }
131
132 /**
133 * Constructor with non-default number of buckets.
134 * @param startTime the histogram start time
135 * @param nbBuckets A number of buckets.
136 * @since 2.0
137 */
138 public HistogramDataModel(long startTime, int nbBuckets) {
139 fFirstBucketTime = fFirstEventTime = fLastEventTime = startTime;
c392540b
FC
140 fNbBuckets = nbBuckets;
141 fBuckets = new long[nbBuckets];
fbd124dd 142 fModelListeners = new ListenerList();
c392540b
FC
143 clear();
144 }
145
b544077e
BH
146 /**
147 * Copy constructor.
148 * @param other A model to copy.
149 */
c392540b
FC
150 public HistogramDataModel(HistogramDataModel other) {
151 fNbBuckets = other.fNbBuckets;
152 fBuckets = Arrays.copyOf(other.fBuckets, fNbBuckets);
00419b1f 153 fBucketDuration = Math.max(other.fBucketDuration, 1);
c392540b
FC
154 fNbEvents = other.fNbEvents;
155 fLastBucket = other.fLastBucket;
fbd124dd 156 fFirstBucketTime = other.fFirstBucketTime;
c392540b
FC
157 fFirstEventTime = other.fFirstEventTime;
158 fLastEventTime = other.fLastEventTime;
0fcf3b09
PT
159 fSelectionBegin = other.fSelectionBegin;
160 fSelectionEnd = other.fSelectionEnd;
c392540b 161 fTimeLimit = other.fTimeLimit;
fbd124dd
BH
162 fModelListeners = new ListenerList();
163 Object[] listeners = other.fModelListeners.getListeners();
164 for (Object listener : listeners) {
165 fModelListeners.add(listener);
166 }
c392540b
FC
167 }
168
169 // ------------------------------------------------------------------------
170 // Accessors
171 // ------------------------------------------------------------------------
172
b544077e
BH
173 /**
174 * Returns the number of events in the data model.
175 * @return number of events.
176 */
c392540b
FC
177 public long getNbEvents() {
178 return fNbEvents;
179 }
180
b544077e
BH
181 /**
182 * Returns the number of buckets in the model.
183 * @return number of buckets.
184 */
c392540b
FC
185 public int getNbBuckets() {
186 return fNbBuckets;
187 }
188
b544077e
BH
189 /**
190 * Returns the current bucket duration.
191 * @return bucket duration
192 */
c392540b
FC
193 public long getBucketDuration() {
194 return fBucketDuration;
195 }
bfe038ff 196
b544077e
BH
197 /**
198 * Returns the time value of the first bucket in the model.
199 * @return time of first bucket.
200 */
fbd124dd
BH
201 public long getFirstBucketTime() {
202 return fFirstBucketTime;
203 }
c392540b 204
b544077e
BH
205 /**
206 * Returns the time of the first event in the model.
207 * @return time of first event.
208 */
c392540b
FC
209 public long getStartTime() {
210 return fFirstEventTime;
211 }
bfe038ff 212
00419b1f
FC
213 /**
214 * Sets the model start time
215 * @param startTime the histogram range start time
216 * @param endTime the histogram range end time
217 * @since 2.0
218 */
219 public void setTimeRange(long startTime, long endTime) {
220 fFirstBucketTime = fFirstEventTime = fLastEventTime = startTime;
221 fBucketDuration = 1;
222 updateEndTime();
223 while (endTime >= fTimeLimit) {
224 mergeBuckets();
225 }
226 }
227
b544077e
BH
228 /**
229 * Returns the time of the last event in the model.
230 * @return the time of last event.
231 */
c392540b
FC
232 public long getEndTime() {
233 return fLastEventTime;
234 }
235
b544077e 236 /**
f8177ba2 237 * Returns the time of the current event in the model.
b544077e 238 * @return the time of the current event.
0fcf3b09 239 * @deprecated As of 2.1, use {@link #getSelectionBegin()} and {@link #getSelectionEnd()}
b544077e 240 */
0fcf3b09 241 @Deprecated
c392540b 242 public long getCurrentEventTime() {
0fcf3b09
PT
243 return fSelectionBegin;
244 }
245
246 /**
247 * Returns the begin time of the current selection in the model.
248 * @return the begin time of the current selection.
00ff7819 249 * @since 3.0
0fcf3b09
PT
250 */
251 public long getSelectionBegin() {
252 return fSelectionBegin;
253 }
254
255 /**
256 * Returns the end time of the current selection in the model.
257 * @return the end time of the current selection.
00ff7819 258 * @since 3.0
0fcf3b09
PT
259 */
260 public long getSelectionEnd() {
261 return fSelectionEnd;
c392540b
FC
262 }
263
b544077e
BH
264 /**
265 * Returns the time limit with is: start time + nbBuckets * bucketDuration
266 * @return the time limit.
267 */
c392540b
FC
268 public long getTimeLimit() {
269 return fTimeLimit;
270 }
bfe038ff 271
fbd124dd
BH
272 // ------------------------------------------------------------------------
273 // Listener handling
274 // ------------------------------------------------------------------------
bfe038ff 275
b544077e
BH
276 /**
277 * Add a listener to the model to be informed about model changes.
278 * @param listener A listener to add.
279 */
fbd124dd 280 public void addHistogramListener(IHistogramModelListener listener) {
bfe038ff 281 fModelListeners.add(listener);
fbd124dd 282 }
bfe038ff 283
b544077e
BH
284 /**
285 * Remove a given model listener.
286 * @param listener A listener to remove.
287 */
fbd124dd
BH
288 public void removeHistogramListener(IHistogramModelListener listener) {
289 fModelListeners.remove(listener);
290 }
c392540b 291
f8177ba2 292 // Notify listeners (always)
fbd124dd
BH
293 private void fireModelUpdateNotification() {
294 fireModelUpdateNotification(0);
295 }
bfe038ff 296
b544077e 297 // Notify listener on boundary
fbd124dd 298 private void fireModelUpdateNotification(long count) {
bfe038ff 299 if ((count % REFRESH_FREQUENCY) == 0) {
fbd124dd 300 Object[] listeners = fModelListeners.getListeners();
bfe038ff
MK
301 for (Object listener2 : listeners) {
302 IHistogramModelListener listener = (IHistogramModelListener) listener2;
fbd124dd
BH
303 listener.modelUpdated();
304 }
305 }
306 }
bfe038ff 307
c392540b
FC
308 // ------------------------------------------------------------------------
309 // Operations
310 // ------------------------------------------------------------------------
e0752744 311
fbd124dd
BH
312 @Override
313 public void complete() {
314 fireModelUpdateNotification();
315 }
c392540b
FC
316
317 /**
318 * Clear the histogram model.
b544077e 319 * @see org.eclipse.linuxtools.tmf.ui.views.distribution.model.IBaseDistributionModel#clear()
c392540b 320 */
fbd124dd 321 @Override
c392540b
FC
322 public void clear() {
323 Arrays.fill(fBuckets, 0);
324 fNbEvents = 0;
fbd124dd 325 fFirstBucketTime = 0;
c392540b 326 fLastEventTime = 0;
0fcf3b09
PT
327 fSelectionBegin = 0;
328 fSelectionEnd = 0;
c392540b 329 fLastBucket = 0;
f8177ba2 330 fBucketDuration = 1;
c392540b 331 updateEndTime();
fbd124dd 332 fireModelUpdateNotification();
c392540b
FC
333 }
334
335 /**
f8177ba2 336 * Sets the current event time (no notification of listeners)
bfe038ff 337 *
b544077e 338 * @param timestamp A time stamp to set.
0fcf3b09 339 * @deprecated As of 2.1, use {@link #setSelection(long, long)}
c392540b 340 */
0fcf3b09 341 @Deprecated
c392540b 342 public void setCurrentEvent(long timestamp) {
0fcf3b09
PT
343 fSelectionBegin = timestamp;
344 fSelectionEnd = timestamp;
c392540b
FC
345 }
346
fbd124dd 347 /**
f8177ba2 348 * Sets the current event time with notification of listeners
bfe038ff 349 *
b544077e 350 * @param timestamp A time stamp to set.
0fcf3b09 351 * @deprecated As of 2.1, use {@link #setSelectionNotifyListeners(long, long)}
fbd124dd 352 */
0fcf3b09 353 @Deprecated
fbd124dd 354 public void setCurrentEventNotifyListeners(long timestamp) {
0fcf3b09
PT
355 fSelectionBegin = timestamp;
356 fSelectionEnd = timestamp;
357 fireModelUpdateNotification();
358 }
359
360 /**
361 * Sets the current selection time range (no notification of listeners)
362 *
363 * @param beginTime The selection begin time.
364 * @param endTime The selection end time.
00ff7819 365 * @since 3.0
0fcf3b09
PT
366 */
367 public void setSelection(long beginTime, long endTime) {
368 fSelectionBegin = beginTime;
369 fSelectionEnd = endTime;
370 }
371
372 /**
373 * Sets the current selection time range with notification of listeners
374 *
375 * @param beginTime The selection begin time.
376 * @param endTime The selection end time.
00ff7819 377 * @since 3.0
0fcf3b09
PT
378 */
379 public void setSelectionNotifyListeners(long beginTime, long endTime) {
380 fSelectionBegin = beginTime;
381 fSelectionEnd = endTime;
fbd124dd
BH
382 fireModelUpdateNotification();
383 }
bfe038ff 384
c392540b
FC
385 /**
386 * Add event to the correct bucket, compacting the if needed.
bfe038ff 387 *
b544077e
BH
388 * @param eventCount The current event Count (for notification purposes)
389 * @param timestamp The timestamp of the event to count
f8177ba2 390 *
c392540b 391 */
fbd124dd
BH
392 @Override
393 public void countEvent(long eventCount, long timestamp) {
bfe038ff 394
fbd124dd
BH
395 // Validate
396 if (timestamp < 0) {
fbd124dd
BH
397 return;
398 }
bfe038ff 399
c392540b 400 // Set the start/end time if not already done
00419b1f 401 if ((fFirstBucketTime == 0) && (fLastBucket == 0) && (fBuckets[0] == 0) && (timestamp > 0)) {
fbd124dd 402 fFirstBucketTime = timestamp;
c392540b
FC
403 fFirstEventTime = timestamp;
404 updateEndTime();
405 }
bfe038ff 406
fbd124dd
BH
407 if (timestamp < fFirstEventTime) {
408 fFirstEventTime = timestamp;
409 }
bfe038ff 410
c392540b
FC
411 if (fLastEventTime < timestamp) {
412 fLastEventTime = timestamp;
413 }
bfe038ff 414
fbd124dd 415 if (timestamp >= fFirstBucketTime) {
c392540b 416
fbd124dd
BH
417 // Compact as needed
418 while (timestamp >= fTimeLimit) {
419 mergeBuckets();
420 }
c392540b 421
fbd124dd 422 } else {
bfe038ff 423
fbd124dd
BH
424 // get offset for adjustment
425 int offset = getOffset(timestamp);
426
427 // Compact as needed
bfe038ff 428 while((fLastBucket + offset) >= fNbBuckets) {
fbd124dd
BH
429 mergeBuckets();
430 offset = getOffset(timestamp);
431 }
bfe038ff 432
fbd124dd
BH
433 moveBuckets(offset);
434
435 fLastBucket = fLastBucket + offset;
c392540b 436
bfe038ff 437 fFirstBucketTime = fFirstBucketTime - (offset*fBucketDuration);
fbd124dd
BH
438 updateEndTime();
439 }
bfe038ff 440
c392540b 441 // Increment the right bucket
fbd124dd 442 int index = (int) ((timestamp - fFirstBucketTime) / fBucketDuration);
c392540b
FC
443 fBuckets[index]++;
444 fNbEvents++;
bfe038ff 445 if (fLastBucket < index) {
c392540b 446 fLastBucket = index;
bfe038ff
MK
447 }
448
fbd124dd 449 fireModelUpdateNotification(eventCount);
c392540b
FC
450 }
451
452 /**
fbd124dd 453 * Scale the model data to the width, height and bar width requested.
bfe038ff 454 *
b544077e
BH
455 * @param width A width of the histogram canvas
456 * @param height A height of the histogram canvas
457 * @param barWidth A width (in pixel) of a histogram bar
458 * @return the result array of size [width] and where the highest value doesn't exceed [height]
f8177ba2 459 *
b544077e 460 * @see org.eclipse.linuxtools.tmf.ui.views.histogram.IHistogramDataModel#scaleTo(int, int, int)
c392540b 461 */
fbd124dd
BH
462 @Override
463 public HistogramScaledData scaleTo(int width, int height, int barWidth) {
c392540b 464 // Basic validation
bfe038ff
MK
465 if ((width <= 0) || (height <= 0) || (barWidth <= 0))
466 {
fbd124dd 467 throw new AssertionError("Invalid histogram dimensions (" + width + "x" + height + ", barWidth=" + barWidth + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
bfe038ff 468 }
c392540b
FC
469
470 // The result structure
fbd124dd 471 HistogramScaledData result = new HistogramScaledData(width, height, barWidth);
c392540b
FC
472
473 // Scale horizontally
74237cc3 474 result.fMaxValue = 0;
bfe038ff 475
fbd124dd 476 int nbBars = width / barWidth;
bfe038ff
MK
477 int bucketsPerBar = (fLastBucket / nbBars) + 1;
478 result.fBucketDuration = Math.max(bucketsPerBar * fBucketDuration,1);
fbd124dd 479 for (int i = 0; i < nbBars; i++) {
c392540b 480 int count = 0;
bfe038ff
MK
481 for (int j = i * bucketsPerBar; j < ((i + 1) * bucketsPerBar); j++) {
482 if (fNbBuckets <= j) {
c392540b 483 break;
bfe038ff 484 }
c392540b
FC
485 count += fBuckets[j];
486 }
487 result.fData[i] = count;
488 result.fLastBucket = i;
bfe038ff 489 if (result.fMaxValue < count) {
c392540b 490 result.fMaxValue = count;
bfe038ff 491 }
c392540b
FC
492 }
493
494 // Scale vertically
495 if (result.fMaxValue > 0) {
496 result.fScalingFactor = (double) height / result.fMaxValue;
497 }
498
bfe038ff 499 fBucketDuration = Math.max(fBucketDuration, 1);
0fcf3b09
PT
500 // Set selection begin and end index in the scaled histogram
501 if (fSelectionBegin < fFirstBucketTime) {
502 result.fSelectionBeginBucket = -1;
503 } else if (fSelectionBegin > fLastEventTime) {
504 result.fSelectionBeginBucket = fLastBucket;
505 } else {
506 result.fSelectionBeginBucket = (int) ((fSelectionBegin - fFirstBucketTime) / fBucketDuration) / bucketsPerBar;
507 }
508 if (fSelectionEnd < fFirstBucketTime) {
509 result.fSelectionEndBucket = -1;
510 } else if (fSelectionEnd > fLastEventTime) {
511 result.fSelectionEndBucket = fLastBucket;
bfe038ff 512 } else {
0fcf3b09 513 result.fSelectionEndBucket = (int) ((fSelectionEnd - fFirstBucketTime) / fBucketDuration) / bucketsPerBar;
bfe038ff 514 }
c392540b 515
fbd124dd
BH
516 result.fFirstBucketTime = fFirstBucketTime;
517 result.fFirstEventTime = fFirstEventTime;
c392540b
FC
518 return result;
519 }
520
521 // ------------------------------------------------------------------------
522 // Helper functions
523 // ------------------------------------------------------------------------
524
525 private void updateEndTime() {
bfe038ff 526 fTimeLimit = fFirstBucketTime + (fNbBuckets * fBucketDuration);
c392540b
FC
527 }
528
529 private void mergeBuckets() {
bfe038ff
MK
530 for (int i = 0; i < (fNbBuckets / 2); i++) {
531 fBuckets[i] = fBuckets[2 * i] + fBuckets[(2 * i) + 1];
c392540b
FC
532 }
533 Arrays.fill(fBuckets, fNbBuckets / 2, fNbBuckets, 0);
534 fBucketDuration *= 2;
535 updateEndTime();
bfe038ff 536 fLastBucket = (fNbBuckets / 2) - 1;
c392540b 537 }
bfe038ff 538
fbd124dd
BH
539 private void moveBuckets(int offset) {
540 for(int i = fNbBuckets - 1; i >= offset; i--) {
bfe038ff 541 fBuckets[i] = fBuckets[i-offset];
fbd124dd
BH
542 }
543
544 for (int i = 0; i < offset; i++) {
545 fBuckets[i] = 0;
546 }
547 }
548
549 private int getOffset(long timestamp) {
550 int offset = (int) ((fFirstBucketTime - timestamp) / fBucketDuration);
bfe038ff 551 if (((fFirstBucketTime - timestamp) % fBucketDuration) != 0) {
fbd124dd
BH
552 offset++;
553 }
554 return offset;
555 }
c392540b
FC
556
557}
This page took 0.109451 seconds and 5 git commands to generate.